blob: 64abda1e1d4cdcd75b2e514f891c4c3797a8714c [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"
11
12#include <pthread.h>
13#include <stdint.h>
14#include <stdio.h>
15#include <stdlib.h>
16
17namespace __cxxabiv1
18{
19
20namespace
21{
22
23void abort_message(const char* s)
24{
25 fputs(s, stderr);
26 ::abort();
27}
28
29pthread_mutex_t guard_mut = PTHREAD_MUTEX_INITIALIZER;
30pthread_cond_t guard_cv = PTHREAD_COND_INITIALIZER;
31
32#if __APPLE__
33
34typedef uint32_t lock_type;
35
36#if __LITTLE_ENDIAN__
37
38inline
39lock_type
40get_lock(uint64_t x)
41{
42 return static_cast<lock_type>(x >> 32);
43}
44
45inline
46void
47set_lock(uint64_t& x, lock_type y)
48{
49 x = static_cast<uint64_t>(y) << 32;
50}
51
52#else // __LITTLE_ENDIAN__
53
54inline
55lock_type
56get_lock(uint64_t x)
57{
58 return static_cast<lock_type>(x);
59}
60
61inline
62void
63set_lock(uint64_t& x, lock_type y)
64{
65 x = y;
66}
67
68#endif // __LITTLE_ENDIAN__
69
70#else // __APPLE__
71
72typedef bool lock_type;
73
74inline
75lock_type
76get_lock(uint64_t x)
77{
78 union
79 {
80 uint64_t guard;
81 uint8_t lock[2];
82 } f = {x};
83 return f.lock[1] != 0;
84}
85
86inline
87void
88set_lock(uint64_t& x, lock_type y)
89{
90 union
91 {
92 uint64_t guard;
93 uint8_t lock[2];
94 } f = {0};
95 f.lock[1] = y;
96 x = f.guard;
97}
98
99#endif // __APPLE__
100
101} // unnamed namespace
102
103extern "C"
104{
105
106int __cxa_guard_acquire(uint64_t* guard_object)
107{
108 char* initialized = (char*)guard_object;
109 if (pthread_mutex_lock(&guard_mut))
110 abort_message("__cxa_guard_acquire failed to acquire mutex");
111 int result = *initialized == 0;
112 if (result)
113 {
114#if __APPLE__
115 const lock_type id = pthread_mach_thread_np(pthread_self());
116 lock_type lock = get_lock(*guard_object);
117 if (lock)
118 {
119 // if this thread set lock for this same guard_object, abort
120 if (lock == id)
121 abort_message("__cxa_guard_acquire detected deadlock");
122 do
123 {
124 if (pthread_cond_wait(&guard_cv, &guard_mut))
125 abort_message("__cxa_guard_acquire condition variable wait failed");
126 lock = get_lock(*guard_object);
127 } while (lock);
128 result = *initialized == 0;
129 if (result)
130 set_lock(*guard_object, id);
131 }
132 else
133 set_lock(*guard_object, id);
134#else // __APPLE__
135 while (get_lock(*guard_object))
136 if (pthread_cond_wait(&guard_cv, &guard_mut))
137 abort_message("__cxa_guard_acquire condition variable wait failed");
138 result = *initialized == 0;
139 if (result)
140 set_lock(*guard_object, true);
141#endif // __APPLE__
142 }
143 if (pthread_mutex_unlock(&guard_mut))
144 abort_message("__cxa_guard_acquire failed to release mutex");
145 return result;
146}
147
148void __cxa_guard_release(uint64_t* guard_object)
149{
150 char* initialized = (char*)guard_object;
151 if (pthread_mutex_lock(&guard_mut))
152 abort_message("__cxa_guard_release failed to acquire mutex");
153 *guard_object = 0;
154 *initialized = 1;
155 if (pthread_mutex_unlock(&guard_mut))
156 abort_message("__cxa_guard_release failed to release mutex");
157 if (pthread_cond_broadcast(&guard_cv))
158 abort_message("__cxa_guard_release failed to broadcast condition variable");
159}
160
161void __cxa_guard_abort(uint64_t* guard_object)
162{
163 if (pthread_mutex_lock(&guard_mut))
164 abort_message("__cxa_guard_abort failed to acquire mutex");
165 *guard_object = 0;
166 if (pthread_mutex_unlock(&guard_mut))
167 abort_message("__cxa_guard_abort failed to release mutex");
168 if (pthread_cond_broadcast(&guard_cv))
169 abort_message("__cxa_guard_abort failed to broadcast condition variable");
170}
171
172} // extern "C"
173
174} // __cxxabiv1