blob: 1b4191713e600405bf9ceabe67ee7b37d2025a97 [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"
Jonathan Roelofs40e98422014-05-06 21:30:56 +000011#include "config.h"
Howard Hinnant4a889712011-05-24 22:01:16 +000012
Jonathan Roelofs3b7f0852014-09-05 17:46:40 +000013#if !LIBCXXABI_HAS_NO_THREADS
Jonathan Roelofs40e98422014-05-06 21:30:56 +000014# include <pthread.h>
15#endif
Howard Hinnant4a889712011-05-24 22:01:16 +000016#include <stdint.h>
Howard Hinnant5d6b9d22012-01-25 19:02:40 +000017
18/*
19 This implementation must be careful to not call code external to this file
20 which will turn around and try to call __cxa_guard_acquire reentrantly.
21 For this reason, the headers of this file are as restricted as possible.
22 Previous implementations of this code for __APPLE__ have used
23 pthread_mutex_lock and the abort_message utility without problem. This
24 implementation also uses pthread_cond_wait which has tested to not be a
25 problem.
26*/
Howard Hinnant4a889712011-05-24 22:01:16 +000027
28namespace __cxxabiv1
29{
30
31namespace
32{
33
Dan Albert3bd13ca2015-02-05 01:33:15 +000034#ifdef __arm__
Nick Lewycky69e35a72011-06-07 18:46:10 +000035
36// A 32-bit, 4-byte-aligned static data value. The least significant 2 bits must
37// be statically initialized to 0.
38typedef uint32_t guard_type;
39
40// Test the lowest bit.
41inline bool is_initialized(guard_type* guard_object) {
42 return (*guard_object) & 1;
43}
44
45inline void set_initialized(guard_type* guard_object) {
46 *guard_object |= 1;
47}
48
49#else
50
51typedef uint64_t guard_type;
52
53bool is_initialized(guard_type* guard_object) {
54 char* initialized = (char*)guard_object;
55 return *initialized;
56}
57
58void set_initialized(guard_type* guard_object) {
59 char* initialized = (char*)guard_object;
60 *initialized = 1;
61}
62
63#endif
64
Jonathan Roelofs3b7f0852014-09-05 17:46:40 +000065#if !LIBCXXABI_HAS_NO_THREADS
Howard Hinnant4a889712011-05-24 22:01:16 +000066pthread_mutex_t guard_mut = PTHREAD_MUTEX_INITIALIZER;
67pthread_cond_t guard_cv = PTHREAD_COND_INITIALIZER;
Jonathan Roelofs40e98422014-05-06 21:30:56 +000068#endif
Howard Hinnant4a889712011-05-24 22:01:16 +000069
Howard Hinnantffa26662012-03-14 19:39:50 +000070#if defined(__APPLE__) && !defined(__arm__)
Howard Hinnant4a889712011-05-24 22:01:16 +000071
72typedef uint32_t lock_type;
73
74#if __LITTLE_ENDIAN__
75
76inline
77lock_type
78get_lock(uint64_t x)
79{
80 return static_cast<lock_type>(x >> 32);
81}
82
83inline
84void
85set_lock(uint64_t& x, lock_type y)
86{
87 x = static_cast<uint64_t>(y) << 32;
88}
89
90#else // __LITTLE_ENDIAN__
91
92inline
93lock_type
94get_lock(uint64_t x)
95{
96 return static_cast<lock_type>(x);
97}
98
99inline
100void
101set_lock(uint64_t& x, lock_type y)
102{
103 x = y;
104}
105
106#endif // __LITTLE_ENDIAN__
107
Howard Hinnantbaae2be2012-03-14 19:30:00 +0000108#else // !__APPLE__ || __arm__
Howard Hinnant4a889712011-05-24 22:01:16 +0000109
110typedef bool lock_type;
111
112inline
113lock_type
114get_lock(uint64_t x)
115{
116 union
117 {
118 uint64_t guard;
119 uint8_t lock[2];
120 } f = {x};
121 return f.lock[1] != 0;
122}
123
124inline
125void
126set_lock(uint64_t& x, lock_type y)
127{
128 union
129 {
130 uint64_t guard;
131 uint8_t lock[2];
132 } f = {0};
133 f.lock[1] = y;
134 x = f.guard;
135}
136
Nick Lewycky69e35a72011-06-07 18:46:10 +0000137inline
138lock_type
139get_lock(uint32_t x)
140{
141 union
142 {
143 uint32_t guard;
144 uint8_t lock[2];
145 } f = {x};
146 return f.lock[1] != 0;
147}
148
149inline
150void
151set_lock(uint32_t& x, lock_type y)
152{
153 union
154 {
155 uint32_t guard;
156 uint8_t lock[2];
157 } f = {0};
158 f.lock[1] = y;
159 x = f.guard;
160}
161
Howard Hinnant4a889712011-05-24 22:01:16 +0000162#endif // __APPLE__
163
164} // unnamed namespace
165
166extern "C"
167{
168
Jonathan Roelofs3b7f0852014-09-05 17:46:40 +0000169#if LIBCXXABI_HAS_NO_THREADS
Nick Lewycky69e35a72011-06-07 18:46:10 +0000170int __cxa_guard_acquire(guard_type* guard_object)
Howard Hinnant4a889712011-05-24 22:01:16 +0000171{
Jonathan Roelofs40e98422014-05-06 21:30:56 +0000172 return !is_initialized(guard_object);
173}
174
175void __cxa_guard_release(guard_type* guard_object)
176{
177 *guard_object = 0;
178 set_initialized(guard_object);
179}
180
181void __cxa_guard_abort(guard_type* guard_object)
182{
183 *guard_object = 0;
184}
185
Jonathan Roelofs3b7f0852014-09-05 17:46:40 +0000186#else // !LIBCXXABI_HAS_NO_THREADS
Jonathan Roelofs40e98422014-05-06 21:30:56 +0000187
188int __cxa_guard_acquire(guard_type* guard_object)
189{
Jonathan Roelofsbce1e4d2014-05-08 18:48:43 +0000190 char* initialized = (char*)guard_object;
Howard Hinnant4a889712011-05-24 22:01:16 +0000191 if (pthread_mutex_lock(&guard_mut))
192 abort_message("__cxa_guard_acquire failed to acquire mutex");
193 int result = *initialized == 0;
194 if (result)
195 {
Howard Hinnantffa26662012-03-14 19:39:50 +0000196#if defined(__APPLE__) && !defined(__arm__)
Howard Hinnant4a889712011-05-24 22:01:16 +0000197 const lock_type id = pthread_mach_thread_np(pthread_self());
198 lock_type lock = get_lock(*guard_object);
199 if (lock)
200 {
201 // if this thread set lock for this same guard_object, abort
202 if (lock == id)
203 abort_message("__cxa_guard_acquire detected deadlock");
204 do
205 {
206 if (pthread_cond_wait(&guard_cv, &guard_mut))
207 abort_message("__cxa_guard_acquire condition variable wait failed");
208 lock = get_lock(*guard_object);
209 } while (lock);
Nick Lewycky69e35a72011-06-07 18:46:10 +0000210 result = !is_initialized(guard_object);
Howard Hinnant4a889712011-05-24 22:01:16 +0000211 if (result)
212 set_lock(*guard_object, id);
213 }
214 else
215 set_lock(*guard_object, id);
Howard Hinnantbaae2be2012-03-14 19:30:00 +0000216#else // !__APPLE__ || __arm__
Howard Hinnant4a889712011-05-24 22:01:16 +0000217 while (get_lock(*guard_object))
218 if (pthread_cond_wait(&guard_cv, &guard_mut))
219 abort_message("__cxa_guard_acquire condition variable wait failed");
220 result = *initialized == 0;
221 if (result)
222 set_lock(*guard_object, true);
Howard Hinnantbaae2be2012-03-14 19:30:00 +0000223#endif // !__APPLE__ || __arm__
Howard Hinnant4a889712011-05-24 22:01:16 +0000224 }
225 if (pthread_mutex_unlock(&guard_mut))
226 abort_message("__cxa_guard_acquire failed to release mutex");
227 return result;
228}
229
Nick Lewycky69e35a72011-06-07 18:46:10 +0000230void __cxa_guard_release(guard_type* guard_object)
Howard Hinnant4a889712011-05-24 22:01:16 +0000231{
Howard Hinnant4a889712011-05-24 22:01:16 +0000232 if (pthread_mutex_lock(&guard_mut))
233 abort_message("__cxa_guard_release failed to acquire mutex");
234 *guard_object = 0;
Nick Lewycky69e35a72011-06-07 18:46:10 +0000235 set_initialized(guard_object);
Howard Hinnant4a889712011-05-24 22:01:16 +0000236 if (pthread_mutex_unlock(&guard_mut))
237 abort_message("__cxa_guard_release failed to release mutex");
238 if (pthread_cond_broadcast(&guard_cv))
239 abort_message("__cxa_guard_release failed to broadcast condition variable");
240}
241
Nick Lewycky69e35a72011-06-07 18:46:10 +0000242void __cxa_guard_abort(guard_type* guard_object)
Howard Hinnant4a889712011-05-24 22:01:16 +0000243{
244 if (pthread_mutex_lock(&guard_mut))
245 abort_message("__cxa_guard_abort failed to acquire mutex");
246 *guard_object = 0;
247 if (pthread_mutex_unlock(&guard_mut))
248 abort_message("__cxa_guard_abort failed to release mutex");
249 if (pthread_cond_broadcast(&guard_cv))
250 abort_message("__cxa_guard_abort failed to broadcast condition variable");
251}
252
Jonathan Roelofs3b7f0852014-09-05 17:46:40 +0000253#endif // !LIBCXXABI_HAS_NO_THREADS
Jonathan Roelofs40e98422014-05-06 21:30:56 +0000254
Howard Hinnant4a889712011-05-24 22:01:16 +0000255} // extern "C"
256
257} // __cxxabiv1