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(_MSC_VER) && !defined(__MINGW32__) && !defined(__BORLANDC__) \
36 || defined(AO_USE_WIN32_PTHREADS)
42 #ifdef AO_USE_WIN32_PTHREADS
43 # include <windows.h> /* for Sleep() */
47 # include <sys/time.h>
49 # include <sys/select.h>
53 #include "atomic_ops.h" /* Without cas emulation! */
55 #ifndef AO_HAVE_double_t
56 # include "atomic_ops/sysdeps/standard_ao_double_t.h"
60 * Lock for pthreads-based implementation.
63 pthread_mutex_t AO_pt_lock = PTHREAD_MUTEX_INITIALIZER;
66 * Out of line compare-and-swap emulation based on test and set.
68 * We use a small table of locks for different compare_and_swap locations.
69 * Before we update perform a compare-and-swap, we grab the corresponding
70 * lock. Different locations may hash to the same lock, but since we
71 * never acquire more than one lock at a time, this can't deadlock.
72 * We explicitly disable signals while we perform this operation.
74 * FIXME: We should probably also support emulation based on Lamport
75 * locks, since we may not have test_and_set either.
77 #define AO_HASH_SIZE 16
79 #define AO_HASH(x) (((unsigned long)(x) >> 12) & (AO_HASH_SIZE-1))
81 AO_TS_t AO_locks[AO_HASH_SIZE] = {
82 AO_TS_INITIALIZER, AO_TS_INITIALIZER,
83 AO_TS_INITIALIZER, AO_TS_INITIALIZER,
84 AO_TS_INITIALIZER, AO_TS_INITIALIZER,
85 AO_TS_INITIALIZER, AO_TS_INITIALIZER,
86 AO_TS_INITIALIZER, AO_TS_INITIALIZER,
87 AO_TS_INITIALIZER, AO_TS_INITIALIZER,
88 AO_TS_INITIALIZER, AO_TS_INITIALIZER,
89 AO_TS_INITIALIZER, AO_TS_INITIALIZER,
92 static AO_T dummy = 1;
94 /* Spin for 2**n units. */
98 AO_T j = AO_load(&dummy);
100 for (i = 0; i < (2 << n); ++i)
114 # ifdef AO_USE_WIN32_PTHREADS
115 Sleep(n > 28 ? 100 : 1 << (n - 22)); /* in millis */
119 /* Short async-signal-safe sleep. */
121 tv.tv_usec = (n > 28? 100000 : (1 << (n - 12)));
122 select(0, 0, 0, 0, &tv);
127 static void lock_ool(volatile AO_TS_t *l)
131 while (AO_test_and_set_acquire(l) == AO_TS_SET)
135 AO_INLINE void lock(volatile AO_TS_t *l)
137 if (AO_test_and_set_acquire(l) == AO_TS_SET)
141 AO_INLINE void unlock(volatile AO_TS_t *l)
146 #ifndef AO_USE_WIN32_PTHREADS
147 static sigset_t all_sigs;
148 static volatile AO_t initialized = 0;
151 static volatile AO_TS_t init_lock = AO_TS_INITIALIZER;
153 int AO_compare_and_swap_emulation(volatile AO_t *addr, AO_t old,
156 AO_TS_t *my_lock = AO_locks + AO_HASH(addr);
159 # ifndef AO_USE_WIN32_PTHREADS
161 if (!AO_load_acquire(&initialized))
164 if (!initialized) sigfillset(&all_sigs);
166 AO_store_release(&initialized, 1);
168 sigprocmask(SIG_BLOCK, &all_sigs, &old_sigs);
169 /* Neither sigprocmask nor pthread_sigmask is 100% */
170 /* guaranteed to work here. Sigprocmask is not */
171 /* guaranteed be thread safe, and pthread_sigmask */
172 /* is not async-signal-safe. Under linuxthreads, */
173 /* sigprocmask may block some pthreads-internal */
174 /* signals. So long as we do that for short periods, */
175 /* we should be OK. */
186 # ifndef AO_USE_WIN32_PTHREADS
187 sigprocmask(SIG_SETMASK, &old_sigs, NULL);
192 int AO_compare_double_and_swap_double_emulation(volatile AO_double_t *addr,
193 AO_t old_val1, AO_t old_val2,
194 AO_t new_val1, AO_t new_val2)
196 AO_TS_t *my_lock = AO_locks + AO_HASH(addr);
199 # ifndef AO_USE_WIN32_PTHREADS
201 if (!AO_load_acquire(&initialized))
204 if (!initialized) sigfillset(&all_sigs);
206 AO_store_release(&initialized, 1);
208 sigprocmask(SIG_BLOCK, &all_sigs, &old_sigs);
209 /* Neither sigprocmask nor pthread_sigmask is 100% */
210 /* guaranteed to work here. Sigprocmask is not */
211 /* guaranteed be thread safe, and pthread_sigmask */
212 /* is not async-signal-safe. Under linuxthreads, */
213 /* sigprocmask may block some pthreads-internal */
214 /* signals. So long as we do that for short periods, */
215 /* we should be OK. */
218 if (addr -> AO_val1 == old_val1 && addr -> AO_val2 == old_val2)
220 addr -> AO_val1 = new_val1;
221 addr -> AO_val2 = new_val2;
227 # ifndef AO_USE_WIN32_PTHREADS
228 sigprocmask(SIG_SETMASK, &old_sigs, NULL);
233 void AO_store_full_emulation(volatile AO_t *addr, AO_t val)
235 AO_TS_t *my_lock = AO_locks + AO_HASH(addr);
241 #else /* Non-posix platform */
243 int AO_non_posix_implementation_is_entirely_in_headers;