implemented Setup.hs to build boehm cpp libs and install them;
[hs-boehmgc.git] / gc-7.2 / libatomic_ops / src / atomic_ops.c
1 /*
2  * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  */
22
23 /*
24  * Initialized data and out-of-line functions to support atomic_ops.h
25  * go here.  Currently this is needed only for pthread-based atomics
26  * emulation, or for compare-and-swap emulation.
27  * Pthreads emulation isn't useful on a native Windows platform, and
28  * cas emulation is not needed.  Thus we skip this on Windows.
29  */
30
31 #if defined(HAVE_CONFIG_H)
32 # include "config.h"
33 #endif
34
35 #if defined(__native_client__) && !defined(AO_USE_NO_SIGNALS) \
36     && !defined(AO_USE_NANOSLEEP)
37   /* Since NaCl is not recognized by configure yet, we do it here.      */
38 # define AO_USE_NO_SIGNALS
39 # define AO_USE_NANOSLEEP
40 #endif
41
42 #if defined(AO_USE_WIN32_PTHREADS) && !defined(AO_USE_NO_SIGNALS)
43 # define AO_USE_NO_SIGNALS
44 #endif
45
46 #if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__BORLANDC__) \
47     || defined(AO_USE_NO_SIGNALS)
48
49 #undef AO_REQUIRE_CAS
50
51 #include <pthread.h>
52
53 #ifndef AO_USE_NO_SIGNALS
54 # include <signal.h>
55 #endif
56
57 #ifdef AO_USE_NANOSLEEP
58   /* This requires _POSIX_TIMERS feature. */
59 # include <sys/time.h>
60 # include <time.h>
61 #elif defined(AO_USE_WIN32_PTHREADS)
62 # include <windows.h> /* for Sleep() */
63 #elif defined(_HPUX_SOURCE)
64 # include <sys/time.h>
65 #else
66 # include <sys/select.h>
67 #endif
68
69 #include "atomic_ops.h"  /* Without cas emulation! */
70
71 #ifndef AO_HAVE_double_t
72 # include "atomic_ops/sysdeps/standard_ao_double_t.h"
73 #endif
74
75 /*
76  * Lock for pthreads-based implementation.
77  */
78
79 pthread_mutex_t AO_pt_lock = PTHREAD_MUTEX_INITIALIZER;
80
81 /*
82  * Out of line compare-and-swap emulation based on test and set.
83  *
84  * We use a small table of locks for different compare_and_swap locations.
85  * Before we update perform a compare-and-swap, we grab the corresponding
86  * lock.  Different locations may hash to the same lock, but since we
87  * never acquire more than one lock at a time, this can't deadlock.
88  * We explicitly disable signals while we perform this operation.
89  *
90  * FIXME: We should probably also support emulation based on Lamport
91  * locks, since we may not have test_and_set either.
92  */
93 #define AO_HASH_SIZE 16
94
95 #define AO_HASH(x) (((unsigned long)(x) >> 12) & (AO_HASH_SIZE-1))
96
97 AO_TS_t AO_locks[AO_HASH_SIZE] = {
98   AO_TS_INITIALIZER, AO_TS_INITIALIZER, AO_TS_INITIALIZER, AO_TS_INITIALIZER,
99   AO_TS_INITIALIZER, AO_TS_INITIALIZER, AO_TS_INITIALIZER, AO_TS_INITIALIZER,
100   AO_TS_INITIALIZER, AO_TS_INITIALIZER, AO_TS_INITIALIZER, AO_TS_INITIALIZER,
101   AO_TS_INITIALIZER, AO_TS_INITIALIZER, AO_TS_INITIALIZER, AO_TS_INITIALIZER,
102 };
103
104 static AO_T dummy = 1;
105
106 /* Spin for 2**n units. */
107 void AO_spin(int n)
108 {
109   int i;
110   AO_T j = AO_load(&dummy);
111
112   for (i = 0; i < (2 << n); ++i)
113     {
114        j *= 5;
115        j -= 4;
116     }
117   AO_store(&dummy, j);
118 }
119
120 void AO_pause(int n)
121 {
122   if (n < 12)
123     AO_spin(n);
124   else
125     {
126 #     ifdef AO_USE_NANOSLEEP
127         struct timespec ts;
128         ts.tv_sec = 0;
129         ts.tv_nsec = (n > 28 ? 100000 * 1000 : 1 << (n - 2));
130         nanosleep(&ts, 0);
131 #     elif defined(AO_USE_WIN32_PTHREADS)
132         Sleep(n > 28 ? 100 : 1 << (n - 22)); /* in millis */
133 #     else
134         struct timeval tv;
135         /* Short async-signal-safe sleep. */
136         tv.tv_sec = 0;
137         tv.tv_usec = n > 28 ? 100000 : 1 << (n - 12);
138         select(0, 0, 0, 0, &tv);
139 #     endif
140     }
141 }
142
143 static void lock_ool(volatile AO_TS_t *l)
144 {
145   int i = 0;
146
147   while (AO_test_and_set_acquire(l) == AO_TS_SET)
148     AO_pause(++i);
149 }
150
151 AO_INLINE void lock(volatile AO_TS_t *l)
152 {
153   if (AO_test_and_set_acquire(l) == AO_TS_SET)
154     lock_ool(l);
155 }
156
157 AO_INLINE void unlock(volatile AO_TS_t *l)
158 {
159   AO_CLEAR(l);
160 }
161
162 #ifndef AO_USE_NO_SIGNALS
163   static sigset_t all_sigs;
164   static volatile AO_t initialized = 0;
165   static volatile AO_TS_t init_lock = AO_TS_INITIALIZER;
166 #endif
167
168 int AO_compare_and_swap_emulation(volatile AO_t *addr, AO_t old,
169                                   AO_t new_val)
170 {
171   AO_TS_t *my_lock = AO_locks + AO_HASH(addr);
172   int result;
173
174 # ifndef AO_USE_NO_SIGNALS
175     sigset_t old_sigs;
176     if (!AO_load_acquire(&initialized))
177     {
178       lock(&init_lock);
179       if (!initialized) sigfillset(&all_sigs);
180       unlock(&init_lock);
181       AO_store_release(&initialized, 1);
182     }
183     sigprocmask(SIG_BLOCK, &all_sigs, &old_sigs);
184         /* Neither sigprocmask nor pthread_sigmask is 100%      */
185         /* guaranteed to work here.  Sigprocmask is not         */
186         /* guaranteed be thread safe, and pthread_sigmask       */
187         /* is not async-signal-safe.  Under linuxthreads,       */
188         /* sigprocmask may block some pthreads-internal         */
189         /* signals.  So long as we do that for short periods,   */
190         /* we should be OK.                                     */
191 # endif
192   lock(my_lock);
193   if (*addr == old)
194     {
195       *addr = new_val;
196       result = 1;
197     }
198   else
199     result = 0;
200   unlock(my_lock);
201 # ifndef AO_USE_NO_SIGNALS
202     sigprocmask(SIG_SETMASK, &old_sigs, NULL);
203 # endif
204   return result;
205 }
206
207 int AO_compare_double_and_swap_double_emulation(volatile AO_double_t *addr,
208                                                 AO_t old_val1, AO_t old_val2,
209                                                 AO_t new_val1, AO_t new_val2)
210 {
211   AO_TS_t *my_lock = AO_locks + AO_HASH(addr);
212   int result;
213
214 # ifndef AO_USE_NO_SIGNALS
215     sigset_t old_sigs;
216     if (!AO_load_acquire(&initialized))
217     {
218       lock(&init_lock);
219       if (!initialized) sigfillset(&all_sigs);
220       unlock(&init_lock);
221       AO_store_release(&initialized, 1);
222     }
223     sigprocmask(SIG_BLOCK, &all_sigs, &old_sigs);
224         /* Neither sigprocmask nor pthread_sigmask is 100%      */
225         /* guaranteed to work here.  Sigprocmask is not         */
226         /* guaranteed be thread safe, and pthread_sigmask       */
227         /* is not async-signal-safe.  Under linuxthreads,       */
228         /* sigprocmask may block some pthreads-internal         */
229         /* signals.  So long as we do that for short periods,   */
230         /* we should be OK.                                     */
231 # endif
232   lock(my_lock);
233   if (addr -> AO_val1 == old_val1 && addr -> AO_val2 == old_val2)
234     {
235       addr -> AO_val1 = new_val1;
236       addr -> AO_val2 = new_val2;
237       result = 1;
238     }
239   else
240     result = 0;
241   unlock(my_lock);
242 # ifndef AO_USE_NO_SIGNALS
243     sigprocmask(SIG_SETMASK, &old_sigs, NULL);
244 # endif
245   return result;
246 }
247
248 void AO_store_full_emulation(volatile AO_t *addr, AO_t val)
249 {
250   AO_TS_t *my_lock = AO_locks + AO_HASH(addr);
251   lock(my_lock);
252   *addr = val;
253   unlock(my_lock);
254 }
255
256 #else /* Non-posix platform */
257
258 extern int AO_non_posix_implementation_is_entirely_in_headers;
259
260 #endif