blob: 2a01f27ad99d2dec79e7460fbeaacde1e5fcf8c0 [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
Saleem Abdulrasool12315ed2015-12-04 02:14:58 +000010#include "__cxxabi_config.h"
11
Nick Kledzik49cbb022011-08-02 01:18:14 +000012#include "abort_message.h"
Jonathan Roelofs40e98422014-05-06 21:30:56 +000013#include "config.h"
Howard Hinnant4a889712011-05-24 22:01:16 +000014
Jonathan Roelofs3b7f0852014-09-05 17:46:40 +000015#if !LIBCXXABI_HAS_NO_THREADS
Jonathan Roelofs40e98422014-05-06 21:30:56 +000016# include <pthread.h>
17#endif
Howard Hinnant4a889712011-05-24 22:01:16 +000018#include <stdint.h>
Howard Hinnant5d6b9d22012-01-25 19:02:40 +000019
20/*
21 This implementation must be careful to not call code external to this file
22 which will turn around and try to call __cxa_guard_acquire reentrantly.
23 For this reason, the headers of this file are as restricted as possible.
24 Previous implementations of this code for __APPLE__ have used
25 pthread_mutex_lock and the abort_message utility without problem. This
26 implementation also uses pthread_cond_wait which has tested to not be a
27 problem.
28*/
Howard Hinnant4a889712011-05-24 22:01:16 +000029
30namespace __cxxabiv1
31{
32
33namespace
34{
35
Dan Albert3bd13ca2015-02-05 01:33:15 +000036#ifdef __arm__
Nick Lewycky69e35a72011-06-07 18:46:10 +000037// A 32-bit, 4-byte-aligned static data value. The least significant 2 bits must
38// be statically initialized to 0.
39typedef uint32_t guard_type;
40
Saleem Abdulrasool7c470052016-08-31 20:29:05 +000041inline void set_initialized(guard_type* guard_object) {
42 *guard_object |= 1;
43}
44#else
45typedef uint64_t guard_type;
46
47void set_initialized(guard_type* guard_object) {
48 char* initialized = (char*)guard_object;
49 *initialized = 1;
50}
51#endif
52
53#if LIBCXXABI_HAS_NO_THREADS || (defined(__APPLE__) && !defined(__arm__))
54#ifdef __arm__
55
Nick Lewycky69e35a72011-06-07 18:46:10 +000056// Test the lowest bit.
57inline bool is_initialized(guard_type* guard_object) {
58 return (*guard_object) & 1;
59}
60
Nick Lewycky69e35a72011-06-07 18:46:10 +000061#else
62
Nick Lewycky69e35a72011-06-07 18:46:10 +000063bool is_initialized(guard_type* guard_object) {
64 char* initialized = (char*)guard_object;
65 return *initialized;
66}
67
Saleem Abdulrasool7c470052016-08-31 20:29:05 +000068#endif
Nick Lewycky69e35a72011-06-07 18:46:10 +000069#endif
70
Jonathan Roelofs3b7f0852014-09-05 17:46:40 +000071#if !LIBCXXABI_HAS_NO_THREADS
Howard Hinnant4a889712011-05-24 22:01:16 +000072pthread_mutex_t guard_mut = PTHREAD_MUTEX_INITIALIZER;
73pthread_cond_t guard_cv = PTHREAD_COND_INITIALIZER;
Jonathan Roelofs40e98422014-05-06 21:30:56 +000074#endif
Howard Hinnant4a889712011-05-24 22:01:16 +000075
Howard Hinnantffa26662012-03-14 19:39:50 +000076#if defined(__APPLE__) && !defined(__arm__)
Howard Hinnant4a889712011-05-24 22:01:16 +000077
78typedef uint32_t lock_type;
79
80#if __LITTLE_ENDIAN__
81
82inline
83lock_type
84get_lock(uint64_t x)
85{
86 return static_cast<lock_type>(x >> 32);
87}
88
89inline
90void
91set_lock(uint64_t& x, lock_type y)
92{
93 x = static_cast<uint64_t>(y) << 32;
94}
95
96#else // __LITTLE_ENDIAN__
97
98inline
99lock_type
100get_lock(uint64_t x)
101{
102 return static_cast<lock_type>(x);
103}
104
105inline
106void
107set_lock(uint64_t& x, lock_type y)
108{
109 x = y;
110}
111
112#endif // __LITTLE_ENDIAN__
113
Howard Hinnantbaae2be2012-03-14 19:30:00 +0000114#else // !__APPLE__ || __arm__
Howard Hinnant4a889712011-05-24 22:01:16 +0000115
116typedef bool lock_type;
117
118inline
119lock_type
120get_lock(uint64_t x)
121{
122 union
123 {
124 uint64_t guard;
125 uint8_t lock[2];
126 } f = {x};
127 return f.lock[1] != 0;
128}
129
130inline
131void
132set_lock(uint64_t& x, lock_type y)
133{
134 union
135 {
136 uint64_t guard;
137 uint8_t lock[2];
138 } f = {0};
139 f.lock[1] = y;
140 x = f.guard;
141}
142
Nick Lewycky69e35a72011-06-07 18:46:10 +0000143inline
144lock_type
145get_lock(uint32_t x)
146{
147 union
148 {
149 uint32_t guard;
150 uint8_t lock[2];
151 } f = {x};
152 return f.lock[1] != 0;
153}
154
155inline
156void
157set_lock(uint32_t& x, lock_type y)
158{
159 union
160 {
161 uint32_t guard;
162 uint8_t lock[2];
163 } f = {0};
164 f.lock[1] = y;
165 x = f.guard;
166}
167
Howard Hinnant4a889712011-05-24 22:01:16 +0000168#endif // __APPLE__
169
170} // unnamed namespace
171
172extern "C"
173{
174
Jonathan Roelofs3b7f0852014-09-05 17:46:40 +0000175#if LIBCXXABI_HAS_NO_THREADS
Saleem Abdulrasool12315ed2015-12-04 02:14:58 +0000176_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) {
Jonathan Roelofs40e98422014-05-06 21:30:56 +0000177 return !is_initialized(guard_object);
178}
179
Saleem Abdulrasool12315ed2015-12-04 02:14:58 +0000180_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) {
Jonathan Roelofs40e98422014-05-06 21:30:56 +0000181 *guard_object = 0;
182 set_initialized(guard_object);
183}
184
Saleem Abdulrasool12315ed2015-12-04 02:14:58 +0000185_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) {
Jonathan Roelofs40e98422014-05-06 21:30:56 +0000186 *guard_object = 0;
187}
188
Jonathan Roelofs3b7f0852014-09-05 17:46:40 +0000189#else // !LIBCXXABI_HAS_NO_THREADS
Jonathan Roelofs40e98422014-05-06 21:30:56 +0000190
Saleem Abdulrasool12315ed2015-12-04 02:14:58 +0000191_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) {
Jonathan Roelofsbce1e4d2014-05-08 18:48:43 +0000192 char* initialized = (char*)guard_object;
Howard Hinnant4a889712011-05-24 22:01:16 +0000193 if (pthread_mutex_lock(&guard_mut))
194 abort_message("__cxa_guard_acquire failed to acquire mutex");
195 int result = *initialized == 0;
196 if (result)
197 {
Howard Hinnantffa26662012-03-14 19:39:50 +0000198#if defined(__APPLE__) && !defined(__arm__)
Howard Hinnant4a889712011-05-24 22:01:16 +0000199 const lock_type id = pthread_mach_thread_np(pthread_self());
200 lock_type lock = get_lock(*guard_object);
201 if (lock)
202 {
203 // if this thread set lock for this same guard_object, abort
204 if (lock == id)
205 abort_message("__cxa_guard_acquire detected deadlock");
206 do
207 {
208 if (pthread_cond_wait(&guard_cv, &guard_mut))
209 abort_message("__cxa_guard_acquire condition variable wait failed");
210 lock = get_lock(*guard_object);
211 } while (lock);
Nick Lewycky69e35a72011-06-07 18:46:10 +0000212 result = !is_initialized(guard_object);
Howard Hinnant4a889712011-05-24 22:01:16 +0000213 if (result)
214 set_lock(*guard_object, id);
215 }
216 else
217 set_lock(*guard_object, id);
Howard Hinnantbaae2be2012-03-14 19:30:00 +0000218#else // !__APPLE__ || __arm__
Howard Hinnant4a889712011-05-24 22:01:16 +0000219 while (get_lock(*guard_object))
220 if (pthread_cond_wait(&guard_cv, &guard_mut))
221 abort_message("__cxa_guard_acquire condition variable wait failed");
222 result = *initialized == 0;
223 if (result)
224 set_lock(*guard_object, true);
Howard Hinnantbaae2be2012-03-14 19:30:00 +0000225#endif // !__APPLE__ || __arm__
Howard Hinnant4a889712011-05-24 22:01:16 +0000226 }
227 if (pthread_mutex_unlock(&guard_mut))
228 abort_message("__cxa_guard_acquire failed to release mutex");
229 return result;
230}
231
Saleem Abdulrasool12315ed2015-12-04 02:14:58 +0000232_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) {
Howard Hinnant4a889712011-05-24 22:01:16 +0000233 if (pthread_mutex_lock(&guard_mut))
234 abort_message("__cxa_guard_release failed to acquire mutex");
235 *guard_object = 0;
Nick Lewycky69e35a72011-06-07 18:46:10 +0000236 set_initialized(guard_object);
Howard Hinnant4a889712011-05-24 22:01:16 +0000237 if (pthread_mutex_unlock(&guard_mut))
238 abort_message("__cxa_guard_release failed to release mutex");
239 if (pthread_cond_broadcast(&guard_cv))
240 abort_message("__cxa_guard_release failed to broadcast condition variable");
241}
242
Saleem Abdulrasool12315ed2015-12-04 02:14:58 +0000243_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) {
Howard Hinnant4a889712011-05-24 22:01:16 +0000244 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