blob: 063d250ead5fbdc82913f69d216f59ca439f39d8 [file] [log] [blame]
Howard Hinnant782d6982011-05-24 22:01:16 +00001//===---------------------------- cxa_guard.cpp ---------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "cxxabi.h"
11
12#include <pthread.h>
13#include <stdint.h>
14#include <stdio.h>
15#include <stdlib.h>
16
17namespace __cxxabiv1
18{
19
20namespace
21{
22
Nick Lewycky0008a2f2011-06-07 18:46:10 +000023#if LIBCXXABI_ARMEABI
24
25// A 32-bit, 4-byte-aligned static data value. The least significant 2 bits must
26// be statically initialized to 0.
27typedef uint32_t guard_type;
28
29// Test the lowest bit.
30inline bool is_initialized(guard_type* guard_object) {
31 return (*guard_object) & 1;
32}
33
34inline void set_initialized(guard_type* guard_object) {
35 *guard_object |= 1;
36}
37
38#else
39
40typedef uint64_t guard_type;
41
42bool is_initialized(guard_type* guard_object) {
43 char* initialized = (char*)guard_object;
44 return *initialized;
45}
46
47void set_initialized(guard_type* guard_object) {
48 char* initialized = (char*)guard_object;
49 *initialized = 1;
50}
51
52#endif
53
54
Howard Hinnant782d6982011-05-24 22:01:16 +000055void abort_message(const char* s)
56{
57 fputs(s, stderr);
58 ::abort();
59}
60
61pthread_mutex_t guard_mut = PTHREAD_MUTEX_INITIALIZER;
62pthread_cond_t guard_cv = PTHREAD_COND_INITIALIZER;
63
64#if __APPLE__
65
66typedef uint32_t lock_type;
67
68#if __LITTLE_ENDIAN__
69
70inline
71lock_type
72get_lock(uint64_t x)
73{
74 return static_cast<lock_type>(x >> 32);
75}
76
77inline
78void
79set_lock(uint64_t& x, lock_type y)
80{
81 x = static_cast<uint64_t>(y) << 32;
82}
83
84#else // __LITTLE_ENDIAN__
85
86inline
87lock_type
88get_lock(uint64_t x)
89{
90 return static_cast<lock_type>(x);
91}
92
93inline
94void
95set_lock(uint64_t& x, lock_type y)
96{
97 x = y;
98}
99
100#endif // __LITTLE_ENDIAN__
101
102#else // __APPLE__
103
104typedef bool lock_type;
105
106inline
107lock_type
108get_lock(uint64_t x)
109{
110 union
111 {
112 uint64_t guard;
113 uint8_t lock[2];
114 } f = {x};
115 return f.lock[1] != 0;
116}
117
118inline
119void
120set_lock(uint64_t& x, lock_type y)
121{
122 union
123 {
124 uint64_t guard;
125 uint8_t lock[2];
126 } f = {0};
127 f.lock[1] = y;
128 x = f.guard;
129}
130
Nick Lewycky0008a2f2011-06-07 18:46:10 +0000131inline
132lock_type
133get_lock(uint32_t x)
134{
135 union
136 {
137 uint32_t guard;
138 uint8_t lock[2];
139 } f = {x};
140 return f.lock[1] != 0;
141}
142
143inline
144void
145set_lock(uint32_t& x, lock_type y)
146{
147 union
148 {
149 uint32_t guard;
150 uint8_t lock[2];
151 } f = {0};
152 f.lock[1] = y;
153 x = f.guard;
154}
155
Howard Hinnant782d6982011-05-24 22:01:16 +0000156#endif // __APPLE__
157
158} // unnamed namespace
159
160extern "C"
161{
162
Nick Lewycky0008a2f2011-06-07 18:46:10 +0000163int __cxa_guard_acquire(guard_type* guard_object)
Howard Hinnant782d6982011-05-24 22:01:16 +0000164{
165 char* initialized = (char*)guard_object;
166 if (pthread_mutex_lock(&guard_mut))
167 abort_message("__cxa_guard_acquire failed to acquire mutex");
168 int result = *initialized == 0;
169 if (result)
170 {
171#if __APPLE__
172 const lock_type id = pthread_mach_thread_np(pthread_self());
173 lock_type lock = get_lock(*guard_object);
174 if (lock)
175 {
176 // if this thread set lock for this same guard_object, abort
177 if (lock == id)
178 abort_message("__cxa_guard_acquire detected deadlock");
179 do
180 {
181 if (pthread_cond_wait(&guard_cv, &guard_mut))
182 abort_message("__cxa_guard_acquire condition variable wait failed");
183 lock = get_lock(*guard_object);
184 } while (lock);
Nick Lewycky0008a2f2011-06-07 18:46:10 +0000185 result = !is_initialized(guard_object);
Howard Hinnant782d6982011-05-24 22:01:16 +0000186 if (result)
187 set_lock(*guard_object, id);
188 }
189 else
190 set_lock(*guard_object, id);
191#else // __APPLE__
192 while (get_lock(*guard_object))
193 if (pthread_cond_wait(&guard_cv, &guard_mut))
194 abort_message("__cxa_guard_acquire condition variable wait failed");
195 result = *initialized == 0;
196 if (result)
197 set_lock(*guard_object, true);
198#endif // __APPLE__
199 }
200 if (pthread_mutex_unlock(&guard_mut))
201 abort_message("__cxa_guard_acquire failed to release mutex");
202 return result;
203}
204
Nick Lewycky0008a2f2011-06-07 18:46:10 +0000205void __cxa_guard_release(guard_type* guard_object)
Howard Hinnant782d6982011-05-24 22:01:16 +0000206{
Howard Hinnant782d6982011-05-24 22:01:16 +0000207 if (pthread_mutex_lock(&guard_mut))
208 abort_message("__cxa_guard_release failed to acquire mutex");
209 *guard_object = 0;
Nick Lewycky0008a2f2011-06-07 18:46:10 +0000210 set_initialized(guard_object);
Howard Hinnant782d6982011-05-24 22:01:16 +0000211 if (pthread_mutex_unlock(&guard_mut))
212 abort_message("__cxa_guard_release failed to release mutex");
213 if (pthread_cond_broadcast(&guard_cv))
214 abort_message("__cxa_guard_release failed to broadcast condition variable");
215}
216
Nick Lewycky0008a2f2011-06-07 18:46:10 +0000217void __cxa_guard_abort(guard_type* guard_object)
Howard Hinnant782d6982011-05-24 22:01:16 +0000218{
219 if (pthread_mutex_lock(&guard_mut))
220 abort_message("__cxa_guard_abort failed to acquire mutex");
221 *guard_object = 0;
222 if (pthread_mutex_unlock(&guard_mut))
223 abort_message("__cxa_guard_abort failed to release mutex");
224 if (pthread_cond_broadcast(&guard_cv))
225 abort_message("__cxa_guard_abort failed to broadcast condition variable");
226}
227
228} // extern "C"
229
230} // __cxxabiv1