Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/c++abi/src/cxa_guard.cpp
12346 views
1
//===---------------------------- 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_config.h"
11
12
#include "abort_message.h"
13
#include <__threading_support>
14
15
#include <stdint.h>
16
17
/*
18
This implementation must be careful to not call code external to this file
19
which will turn around and try to call __cxa_guard_acquire reentrantly.
20
For this reason, the headers of this file are as restricted as possible.
21
Previous implementations of this code for __APPLE__ have used
22
std::__libcpp_mutex_lock and the abort_message utility without problem. This
23
implementation also uses std::__libcpp_condvar_wait which has tested
24
to not be a problem.
25
*/
26
27
namespace __cxxabiv1
28
{
29
30
namespace
31
{
32
33
#ifdef __arm__
34
// A 32-bit, 4-byte-aligned static data value. The least significant 2 bits must
35
// be statically initialized to 0.
36
typedef uint32_t guard_type;
37
38
inline void set_initialized(guard_type* guard_object) {
39
*guard_object |= 1;
40
}
41
#else
42
typedef uint64_t guard_type;
43
44
void set_initialized(guard_type* guard_object) {
45
char* initialized = (char*)guard_object;
46
*initialized = 1;
47
}
48
#endif
49
50
#if defined(_LIBCXXABI_HAS_NO_THREADS) || (defined(__APPLE__) && !defined(__arm__))
51
#ifdef __arm__
52
53
// Test the lowest bit.
54
inline bool is_initialized(guard_type* guard_object) {
55
return (*guard_object) & 1;
56
}
57
58
#else
59
60
bool is_initialized(guard_type* guard_object) {
61
char* initialized = (char*)guard_object;
62
return *initialized;
63
}
64
65
#endif
66
#endif
67
68
#ifndef _LIBCXXABI_HAS_NO_THREADS
69
std::__libcpp_mutex_t guard_mut = _LIBCPP_MUTEX_INITIALIZER;
70
std::__libcpp_condvar_t guard_cv = _LIBCPP_CONDVAR_INITIALIZER;
71
#endif
72
73
#if defined(__APPLE__) && !defined(__arm__)
74
75
typedef uint32_t lock_type;
76
77
#if __LITTLE_ENDIAN__
78
79
inline
80
lock_type
81
get_lock(uint64_t x)
82
{
83
return static_cast<lock_type>(x >> 32);
84
}
85
86
inline
87
void
88
set_lock(uint64_t& x, lock_type y)
89
{
90
x = static_cast<uint64_t>(y) << 32;
91
}
92
93
#else // __LITTLE_ENDIAN__
94
95
inline
96
lock_type
97
get_lock(uint64_t x)
98
{
99
return static_cast<lock_type>(x);
100
}
101
102
inline
103
void
104
set_lock(uint64_t& x, lock_type y)
105
{
106
x = y;
107
}
108
109
#endif // __LITTLE_ENDIAN__
110
111
#else // !__APPLE__ || __arm__
112
113
typedef bool lock_type;
114
115
#if !defined(__arm__)
116
static_assert(std::is_same<guard_type, uint64_t>::value, "");
117
118
inline lock_type get_lock(uint64_t x)
119
{
120
union
121
{
122
uint64_t guard;
123
uint8_t lock[2];
124
} f = {x};
125
return f.lock[1] != 0;
126
}
127
128
inline void set_lock(uint64_t& x, lock_type y)
129
{
130
union
131
{
132
uint64_t guard;
133
uint8_t lock[2];
134
} f = {0};
135
f.lock[1] = y;
136
x = f.guard;
137
}
138
#else // defined(__arm__)
139
static_assert(std::is_same<guard_type, uint32_t>::value, "");
140
141
inline lock_type get_lock(uint32_t x)
142
{
143
union
144
{
145
uint32_t guard;
146
uint8_t lock[2];
147
} f = {x};
148
return f.lock[1] != 0;
149
}
150
151
inline void set_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
162
#endif // !defined(__arm__)
163
164
#endif // __APPLE__ && !__arm__
165
166
} // unnamed namespace
167
168
extern "C"
169
{
170
171
#ifndef _LIBCXXABI_HAS_NO_THREADS
172
_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) {
173
char* initialized = (char*)guard_object;
174
if (std::__libcpp_mutex_lock(&guard_mut))
175
abort_message("__cxa_guard_acquire failed to acquire mutex");
176
int result = *initialized == 0;
177
if (result)
178
{
179
#if defined(__APPLE__) && !defined(__arm__)
180
// This is a special-case pthread dependency for Mac. We can't pull this
181
// out into libcxx's threading API (__threading_support) because not all
182
// supported Mac environments provide this function (in pthread.h). To
183
// make it possible to build/use libcxx in those environments, we have to
184
// keep this pthread dependency local to libcxxabi. If there is some
185
// convenient way to detect precisely when pthread_mach_thread_np is
186
// available in a given Mac environment, it might still be possible to
187
// bury this dependency in __threading_support.
188
#ifdef _LIBCPP_HAS_THREAD_API_PTHREAD
189
const lock_type id = pthread_mach_thread_np(std::__libcpp_thread_get_current_id());
190
#else
191
#error "How do I pthread_mach_thread_np()?"
192
#endif
193
lock_type lock = get_lock(*guard_object);
194
if (lock)
195
{
196
// if this thread set lock for this same guard_object, abort
197
if (lock == id)
198
abort_message("__cxa_guard_acquire detected deadlock");
199
do
200
{
201
if (std::__libcpp_condvar_wait(&guard_cv, &guard_mut))
202
abort_message("__cxa_guard_acquire condition variable wait failed");
203
lock = get_lock(*guard_object);
204
} while (lock);
205
result = !is_initialized(guard_object);
206
if (result)
207
set_lock(*guard_object, id);
208
}
209
else
210
set_lock(*guard_object, id);
211
#else // !__APPLE__ || __arm__
212
while (get_lock(*guard_object))
213
if (std::__libcpp_condvar_wait(&guard_cv, &guard_mut))
214
abort_message("__cxa_guard_acquire condition variable wait failed");
215
result = *initialized == 0;
216
if (result)
217
set_lock(*guard_object, true);
218
#endif // !__APPLE__ || __arm__
219
}
220
if (std::__libcpp_mutex_unlock(&guard_mut))
221
abort_message("__cxa_guard_acquire failed to release mutex");
222
return result;
223
}
224
225
_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) {
226
if (std::__libcpp_mutex_lock(&guard_mut))
227
abort_message("__cxa_guard_release failed to acquire mutex");
228
*guard_object = 0;
229
set_initialized(guard_object);
230
if (std::__libcpp_mutex_unlock(&guard_mut))
231
abort_message("__cxa_guard_release failed to release mutex");
232
if (std::__libcpp_condvar_broadcast(&guard_cv))
233
abort_message("__cxa_guard_release failed to broadcast condition variable");
234
}
235
236
_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) {
237
if (std::__libcpp_mutex_lock(&guard_mut))
238
abort_message("__cxa_guard_abort failed to acquire mutex");
239
*guard_object = 0;
240
if (std::__libcpp_mutex_unlock(&guard_mut))
241
abort_message("__cxa_guard_abort failed to release mutex");
242
if (std::__libcpp_condvar_broadcast(&guard_cv))
243
abort_message("__cxa_guard_abort failed to broadcast condition variable");
244
}
245
246
#else // _LIBCXXABI_HAS_NO_THREADS
247
248
_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) {
249
return !is_initialized(guard_object);
250
}
251
252
_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) {
253
*guard_object = 0;
254
set_initialized(guard_object);
255
}
256
257
_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) {
258
*guard_object = 0;
259
}
260
261
#endif // !_LIBCXXABI_HAS_NO_THREADS
262
263
} // extern "C"
264
265
} // __cxxabiv1
266
267