2 * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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
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.
31 #if defined(HAVE_CONFIG_H)
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
42 #if defined(AO_USE_WIN32_PTHREADS) && !defined(AO_USE_NO_SIGNALS)
43 # define AO_USE_NO_SIGNALS
46 #if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__BORLANDC__) \
47 || defined(AO_USE_NO_SIGNALS)
53 #ifndef AO_USE_NO_SIGNALS
57 #ifdef AO_USE_NANOSLEEP
58 /* This requires _POSIX_TIMERS feature. */
59 # include <sys/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>
66 # include <sys/select.h>
69 #include "atomic_ops.h" /* Without cas emulation! */
71 #ifndef AO_HAVE_double_t
72 # include "atomic_ops/sysdeps/standard_ao_double_t.h"
76 * Lock for pthreads-based implementation.
79 pthread_mutex_t AO_pt_lock = PTHREAD_MUTEX_INITIALIZER;
82 * Out of line compare-and-swap emulation based on test and set.
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.
90 * FIXME: We should probably also support emulation based on Lamport
91 * locks, since we may not have test_and_set either.
93 #define AO_HASH_SIZE 16
95 #define AO_HASH(x) (((unsigned long)(x) >> 12) & (AO_HASH_SIZE-1))
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,
104 static AO_T dummy = 1;
106 /* Spin for 2**n units. */
110 AO_T j = AO_load(&dummy);
112 for (i = 0; i < (2 << n); ++i)
126 # ifdef AO_USE_NANOSLEEP
129 ts.tv_nsec = (n > 28 ? 100000 * 1000 : 1 << (n - 2));
131 # elif defined(AO_USE_WIN32_PTHREADS)
132 Sleep(n > 28 ? 100 : 1 << (n - 22)); /* in millis */
135 /* Short async-signal-safe sleep. */
137 tv.tv_usec = n > 28 ? 100000 : 1 << (n - 12);
138 select(0, 0, 0, 0, &tv);
143 static void lock_ool(volatile AO_TS_t *l)
147 while (AO_test_and_set_acquire(l) == AO_TS_SET)
151 AO_INLINE void lock(volatile AO_TS_t *l)
153 if (AO_test_and_set_acquire(l) == AO_TS_SET)
157 AO_INLINE void unlock(volatile AO_TS_t *l)
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;
168 int AO_compare_and_swap_emulation(volatile AO_t *addr, AO_t old,
171 AO_TS_t *my_lock = AO_locks + AO_HASH(addr);
174 # ifndef AO_USE_NO_SIGNALS
176 if (!AO_load_acquire(&initialized))
179 if (!initialized) sigfillset(&all_sigs);
181 AO_store_release(&initialized, 1);
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. */
201 # ifndef AO_USE_NO_SIGNALS
202 sigprocmask(SIG_SETMASK, &old_sigs, NULL);
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)
211 AO_TS_t *my_lock = AO_locks + AO_HASH(addr);
214 # ifndef AO_USE_NO_SIGNALS
216 if (!AO_load_acquire(&initialized))
219 if (!initialized) sigfillset(&all_sigs);
221 AO_store_release(&initialized, 1);
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. */
233 if (addr -> AO_val1 == old_val1 && addr -> AO_val2 == old_val2)
235 addr -> AO_val1 = new_val1;
236 addr -> AO_val2 = new_val2;
242 # ifndef AO_USE_NO_SIGNALS
243 sigprocmask(SIG_SETMASK, &old_sigs, NULL);
248 void AO_store_full_emulation(volatile AO_t *addr, AO_t val)
250 AO_TS_t *my_lock = AO_locks + AO_HASH(addr);
256 #else /* Non-posix platform */
258 extern int AO_non_posix_implementation_is_entirely_in_headers;