blob: 742bac385bee08007727ff1c4daa2f0c387c4677 [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"
Nick Kledzik3915a4e2011-08-02 01:18:14 +000011#include "abort_message.h"
Howard Hinnant782d6982011-05-24 22:01:16 +000012
13#include <pthread.h>
14#include <stdint.h>
15#include <stdio.h>
16#include <stdlib.h>
17
18namespace __cxxabiv1
19{
20
21namespace
22{
23
Nick Lewycky0008a2f2011-06-07 18:46:10 +000024#if LIBCXXABI_ARMEABI
25
26// A 32-bit, 4-byte-aligned static data value. The least significant 2 bits must
27// be statically initialized to 0.
28typedef uint32_t guard_type;
29
30// Test the lowest bit.
31inline bool is_initialized(guard_type* guard_object) {
32 return (*guard_object) & 1;
33}
34
35inline void set_initialized(guard_type* guard_object) {
36 *guard_object |= 1;
37}
38
39#else
40
41typedef uint64_t guard_type;
42
43bool is_initialized(guard_type* guard_object) {
44 char* initialized = (char*)guard_object;
45 return *initialized;
46}
47
48void set_initialized(guard_type* guard_object) {
49 char* initialized = (char*)guard_object;
50 *initialized = 1;
51}
52
53#endif
54
Howard Hinnant782d6982011-05-24 22:01:16 +000055pthread_mutex_t guard_mut = PTHREAD_MUTEX_INITIALIZER;
56pthread_cond_t guard_cv = PTHREAD_COND_INITIALIZER;
57
58#if __APPLE__
59
60typedef uint32_t lock_type;
61
62#if __LITTLE_ENDIAN__
63
64inline
65lock_type
66get_lock(uint64_t x)
67{
68 return static_cast<lock_type>(x >> 32);
69}
70
71inline
72void
73set_lock(uint64_t& x, lock_type y)
74{
75 x = static_cast<uint64_t>(y) << 32;
76}
77
78#else // __LITTLE_ENDIAN__
79
80inline
81lock_type
82get_lock(uint64_t x)
83{
84 return static_cast<lock_type>(x);
85}
86
87inline
88void
89set_lock(uint64_t& x, lock_type y)
90{
91 x = y;
92}
93
94#endif // __LITTLE_ENDIAN__
95
96#else // __APPLE__
97
98typedef bool lock_type;
99
100inline
101lock_type
102get_lock(uint64_t x)
103{
104 union
105 {
106 uint64_t guard;
107 uint8_t lock[2];
108 } f = {x};
109 return f.lock[1] != 0;
110}
111
112inline
113void
114set_lock(uint64_t& x, lock_type y)
115{
116 union
117 {
118 uint64_t guard;
119 uint8_t lock[2];
120 } f = {0};
121 f.lock[1] = y;
122 x = f.guard;
123}
124
Nick Lewycky0008a2f2011-06-07 18:46:10 +0000125inline
126lock_type
127get_lock(uint32_t x)
128{
129 union
130 {
131 uint32_t guard;
132 uint8_t lock[2];
133 } f = {x};
134 return f.lock[1] != 0;
135}
136
137inline
138void
139set_lock(uint32_t& x, lock_type y)
140{
141 union
142 {
143 uint32_t guard;
144 uint8_t lock[2];
145 } f = {0};
146 f.lock[1] = y;
147 x = f.guard;
148}
149
Howard Hinnant782d6982011-05-24 22:01:16 +0000150#endif // __APPLE__
151
152} // unnamed namespace
153
154extern "C"
155{
156
Nick Lewycky0008a2f2011-06-07 18:46:10 +0000157int __cxa_guard_acquire(guard_type* guard_object)
Howard Hinnant782d6982011-05-24 22:01:16 +0000158{
159 char* initialized = (char*)guard_object;
160 if (pthread_mutex_lock(&guard_mut))
161 abort_message("__cxa_guard_acquire failed to acquire mutex");
162 int result = *initialized == 0;
163 if (result)
164 {
165#if __APPLE__
166 const lock_type id = pthread_mach_thread_np(pthread_self());
167 lock_type lock = get_lock(*guard_object);
168 if (lock)
169 {
170 // if this thread set lock for this same guard_object, abort
171 if (lock == id)
172 abort_message("__cxa_guard_acquire detected deadlock");
173 do
174 {
175 if (pthread_cond_wait(&guard_cv, &guard_mut))
176 abort_message("__cxa_guard_acquire condition variable wait failed");
177 lock = get_lock(*guard_object);
178 } while (lock);
Nick Lewycky0008a2f2011-06-07 18:46:10 +0000179 result = !is_initialized(guard_object);
Howard Hinnant782d6982011-05-24 22:01:16 +0000180 if (result)
181 set_lock(*guard_object, id);
182 }
183 else
184 set_lock(*guard_object, id);
185#else // __APPLE__
186 while (get_lock(*guard_object))
187 if (pthread_cond_wait(&guard_cv, &guard_mut))
188 abort_message("__cxa_guard_acquire condition variable wait failed");
189 result = *initialized == 0;
190 if (result)
191 set_lock(*guard_object, true);
192#endif // __APPLE__
193 }
194 if (pthread_mutex_unlock(&guard_mut))
195 abort_message("__cxa_guard_acquire failed to release mutex");
196 return result;
197}
198
Nick Lewycky0008a2f2011-06-07 18:46:10 +0000199void __cxa_guard_release(guard_type* guard_object)
Howard Hinnant782d6982011-05-24 22:01:16 +0000200{
Howard Hinnant782d6982011-05-24 22:01:16 +0000201 if (pthread_mutex_lock(&guard_mut))
202 abort_message("__cxa_guard_release failed to acquire mutex");
203 *guard_object = 0;
Nick Lewycky0008a2f2011-06-07 18:46:10 +0000204 set_initialized(guard_object);
Howard Hinnant782d6982011-05-24 22:01:16 +0000205 if (pthread_mutex_unlock(&guard_mut))
206 abort_message("__cxa_guard_release failed to release mutex");
207 if (pthread_cond_broadcast(&guard_cv))
208 abort_message("__cxa_guard_release failed to broadcast condition variable");
209}
210
Nick Lewycky0008a2f2011-06-07 18:46:10 +0000211void __cxa_guard_abort(guard_type* guard_object)
Howard Hinnant782d6982011-05-24 22:01:16 +0000212{
213 if (pthread_mutex_lock(&guard_mut))
214 abort_message("__cxa_guard_abort failed to acquire mutex");
215 *guard_object = 0;
216 if (pthread_mutex_unlock(&guard_mut))
217 abort_message("__cxa_guard_abort failed to release mutex");
218 if (pthread_cond_broadcast(&guard_cv))
219 abort_message("__cxa_guard_abort failed to broadcast condition variable");
220}
221
222} // extern "C"
223
224} // __cxxabiv1