blob: a8d5bae816677038b1c13185d75b4cc0653f4bd7 [file] [log] [blame]
Howard Hinnant4a889712011-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
Nick Kledzik49cbb022011-08-02 01:18:14 +000010#include "abort_message.h"
Howard Hinnant4a889712011-05-24 22:01:16 +000011
12#include <pthread.h>
13#include <stdint.h>
Howard Hinnant5d6b9d22012-01-25 19:02:40 +000014
15/*
16 This implementation must be careful to not call code external to this file
17 which will turn around and try to call __cxa_guard_acquire reentrantly.
18 For this reason, the headers of this file are as restricted as possible.
19 Previous implementations of this code for __APPLE__ have used
20 pthread_mutex_lock and the abort_message utility without problem. This
21 implementation also uses pthread_cond_wait which has tested to not be a
22 problem.
23*/
Howard Hinnant4a889712011-05-24 22:01:16 +000024
25namespace __cxxabiv1
26{
27
28namespace
29{
30
Howard Hinnantbaae2be2012-03-14 19:30:00 +000031#if __arm__
Nick Lewycky69e35a72011-06-07 18:46:10 +000032
33// A 32-bit, 4-byte-aligned static data value. The least significant 2 bits must
34// be statically initialized to 0.
35typedef uint32_t guard_type;
36
37// Test the lowest bit.
38inline bool is_initialized(guard_type* guard_object) {
39 return (*guard_object) & 1;
40}
41
42inline void set_initialized(guard_type* guard_object) {
43 *guard_object |= 1;
44}
45
46#else
47
48typedef uint64_t guard_type;
49
50bool is_initialized(guard_type* guard_object) {
51 char* initialized = (char*)guard_object;
52 return *initialized;
53}
54
55void set_initialized(guard_type* guard_object) {
56 char* initialized = (char*)guard_object;
57 *initialized = 1;
58}
59
60#endif
61
Howard Hinnant4a889712011-05-24 22:01:16 +000062pthread_mutex_t guard_mut = PTHREAD_MUTEX_INITIALIZER;
63pthread_cond_t guard_cv = PTHREAD_COND_INITIALIZER;
64
Howard Hinnantbaae2be2012-03-14 19:30:00 +000065#if defined(__APPLE__) && !defined(__arm_)
Howard Hinnant4a889712011-05-24 22:01:16 +000066
67typedef uint32_t lock_type;
68
69#if __LITTLE_ENDIAN__
70
71inline
72lock_type
73get_lock(uint64_t x)
74{
75 return static_cast<lock_type>(x >> 32);
76}
77
78inline
79void
80set_lock(uint64_t& x, lock_type y)
81{
82 x = static_cast<uint64_t>(y) << 32;
83}
84
85#else // __LITTLE_ENDIAN__
86
87inline
88lock_type
89get_lock(uint64_t x)
90{
91 return static_cast<lock_type>(x);
92}
93
94inline
95void
96set_lock(uint64_t& x, lock_type y)
97{
98 x = y;
99}
100
101#endif // __LITTLE_ENDIAN__
102
Howard Hinnantbaae2be2012-03-14 19:30:00 +0000103#else // !__APPLE__ || __arm__
Howard Hinnant4a889712011-05-24 22:01:16 +0000104
105typedef bool lock_type;
106
107inline
108lock_type
109get_lock(uint64_t x)
110{
111 union
112 {
113 uint64_t guard;
114 uint8_t lock[2];
115 } f = {x};
116 return f.lock[1] != 0;
117}
118
119inline
120void
121set_lock(uint64_t& x, lock_type y)
122{
123 union
124 {
125 uint64_t guard;
126 uint8_t lock[2];
127 } f = {0};
128 f.lock[1] = y;
129 x = f.guard;
130}
131
Nick Lewycky69e35a72011-06-07 18:46:10 +0000132inline
133lock_type
134get_lock(uint32_t x)
135{
136 union
137 {
138 uint32_t guard;
139 uint8_t lock[2];
140 } f = {x};
141 return f.lock[1] != 0;
142}
143
144inline
145void
146set_lock(uint32_t& x, lock_type y)
147{
148 union
149 {
150 uint32_t guard;
151 uint8_t lock[2];
152 } f = {0};
153 f.lock[1] = y;
154 x = f.guard;
155}
156
Howard Hinnant4a889712011-05-24 22:01:16 +0000157#endif // __APPLE__
158
159} // unnamed namespace
160
161extern "C"
162{
163
Nick Lewycky69e35a72011-06-07 18:46:10 +0000164int __cxa_guard_acquire(guard_type* guard_object)
Howard Hinnant4a889712011-05-24 22:01:16 +0000165{
166 char* initialized = (char*)guard_object;
167 if (pthread_mutex_lock(&guard_mut))
168 abort_message("__cxa_guard_acquire failed to acquire mutex");
169 int result = *initialized == 0;
170 if (result)
171 {
Howard Hinnantbaae2be2012-03-14 19:30:00 +0000172#if defined(__APPLE__) && !defined(__arm_)
Howard Hinnant4a889712011-05-24 22:01:16 +0000173 const lock_type id = pthread_mach_thread_np(pthread_self());
174 lock_type lock = get_lock(*guard_object);
175 if (lock)
176 {
177 // if this thread set lock for this same guard_object, abort
178 if (lock == id)
179 abort_message("__cxa_guard_acquire detected deadlock");
180 do
181 {
182 if (pthread_cond_wait(&guard_cv, &guard_mut))
183 abort_message("__cxa_guard_acquire condition variable wait failed");
184 lock = get_lock(*guard_object);
185 } while (lock);
Nick Lewycky69e35a72011-06-07 18:46:10 +0000186 result = !is_initialized(guard_object);
Howard Hinnant4a889712011-05-24 22:01:16 +0000187 if (result)
188 set_lock(*guard_object, id);
189 }
190 else
191 set_lock(*guard_object, id);
Howard Hinnantbaae2be2012-03-14 19:30:00 +0000192#else // !__APPLE__ || __arm__
Howard Hinnant4a889712011-05-24 22:01:16 +0000193 while (get_lock(*guard_object))
194 if (pthread_cond_wait(&guard_cv, &guard_mut))
195 abort_message("__cxa_guard_acquire condition variable wait failed");
196 result = *initialized == 0;
197 if (result)
198 set_lock(*guard_object, true);
Howard Hinnantbaae2be2012-03-14 19:30:00 +0000199#endif // !__APPLE__ || __arm__
Howard Hinnant4a889712011-05-24 22:01:16 +0000200 }
201 if (pthread_mutex_unlock(&guard_mut))
202 abort_message("__cxa_guard_acquire failed to release mutex");
203 return result;
204}
205
Nick Lewycky69e35a72011-06-07 18:46:10 +0000206void __cxa_guard_release(guard_type* guard_object)
Howard Hinnant4a889712011-05-24 22:01:16 +0000207{
Howard Hinnant4a889712011-05-24 22:01:16 +0000208 if (pthread_mutex_lock(&guard_mut))
209 abort_message("__cxa_guard_release failed to acquire mutex");
210 *guard_object = 0;
Nick Lewycky69e35a72011-06-07 18:46:10 +0000211 set_initialized(guard_object);
Howard Hinnant4a889712011-05-24 22:01:16 +0000212 if (pthread_mutex_unlock(&guard_mut))
213 abort_message("__cxa_guard_release failed to release mutex");
214 if (pthread_cond_broadcast(&guard_cv))
215 abort_message("__cxa_guard_release failed to broadcast condition variable");
216}
217
Nick Lewycky69e35a72011-06-07 18:46:10 +0000218void __cxa_guard_abort(guard_type* guard_object)
Howard Hinnant4a889712011-05-24 22:01:16 +0000219{
220 if (pthread_mutex_lock(&guard_mut))
221 abort_message("__cxa_guard_abort failed to acquire mutex");
222 *guard_object = 0;
223 if (pthread_mutex_unlock(&guard_mut))
224 abort_message("__cxa_guard_abort failed to release mutex");
225 if (pthread_cond_broadcast(&guard_cv))
226 abort_message("__cxa_guard_abort failed to broadcast condition variable");
227}
228
229} // extern "C"
230
231} // __cxxabiv1