2 * Copyright (c) 2010 Your Filesystem Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 #ifndef OPENAFS_RX_ATOMIC_H
26 #define OPENAFS_RX_ATOMIC_H 1
28 #define RX_ATOMIC_INIT(i) { (i) }
36 rx_atomic_set(rx_atomic_t *atomic, int val) {
41 rx_atomic_read(rx_atomic_t *atomic) {
46 rx_atomic_inc(rx_atomic_t *atomic) {
47 InterlockedIncrement(&atomic->var);
51 rx_atomic_inc_and_read(rx_atomic_t *atomic) {
52 return InterlockedIncrement(&atomic->var);
56 rx_atomic_add(rx_atomic_t *atomic, int change) {
57 InterlockedExchangeAdd(&atomic->var, change);
61 rx_atomic_add_and_read(rx_atomic_t *atomic, int change) {
62 return InterlockedExchangeAdd(&atomic->var, change) + change;
66 rx_atomic_dec(rx_atomic_t *atomic) {
67 InterlockedDecrement(&atomic->var);
71 rx_atomic_dec_and_read(rx_atomic_t *atomic) {
72 return InterlockedDecrement(&atomic->var);
76 rx_atomic_sub(rx_atomic_t *atomic, int change) {
77 InterlockedExchangeAdd(&atomic->var, 0 - change);
80 #elif defined(AFS_AIX61_ENV) || defined(AFS_USR_AIX61_ENV)
81 #include <sys/atomic_op.h>
88 rx_atomic_set(rx_atomic_t *atomic, int val) {
93 rx_atomic_read(rx_atomic_t *atomic) {
98 rx_atomic_inc(rx_atomic_t *atomic) {
99 fetch_and_add(&atomic->var, 1);
103 rx_atomic_inc_and_read(rx_atomic_t *atomic) {
104 return (fetch_and_add(&atomic->var, 1) + 1);
108 rx_atomic_add(rx_atomic_t *atomic, int change) {
109 fetch_and_add(&atomic->var, change);
113 rx_atomic_add_and_read(rx_atomic_t *atomic, int change) {
114 return (fetch_and_add(&atomic->var, change) + change);
118 rx_atomic_dec(rx_atomic_t *atomic) {
119 fetch_and_add(&atomic->var, -1);
123 rx_atomic_dec_and_read(rx_atomic_t *atomic) {
124 return (fetch_and_add(&atomic->var, -1) - 1);
128 rx_atomic_sub(rx_atomic_t *atomic, int change) {
129 fetch_and_add(&atomic->var, -change);
132 #elif defined(AFS_DARWIN80_ENV) || defined(AFS_USR_DARWIN80_ENV)
134 # if (defined(AFS_DARWIN160_ENV) || defined(AFS_USR_DARWIN160_ENV)) && !defined(KERNEL)
135 # define OSATOMIC_USE_INLINED 1
138 # include <libkern/OSAtomic.h>
140 # if defined(KERNEL) && !defined(UKERNEL)
142 OSAtomicIncrement32(volatile int *value)
144 return OSIncrementAtomic(value) + 1;
148 OSAtomicAdd32(int amount, volatile int *value)
150 return OSAddAtomic(amount, value) + amount;
154 OSAtomicDecrement32(volatile int *value)
156 return OSDecrementAtomic(value) - 1;
166 rx_atomic_set(rx_atomic_t *atomic, int val) {
171 rx_atomic_read(rx_atomic_t *atomic) {
176 rx_atomic_inc(rx_atomic_t *atomic) {
177 OSAtomicIncrement32(&atomic->var);
181 rx_atomic_inc_and_read(rx_atomic_t *atomic) {
182 return OSAtomicIncrement32(&atomic->var);
186 rx_atomic_add(rx_atomic_t *atomic, int change) {
187 OSAtomicAdd32(change, &atomic->var);
191 rx_atomic_add_and_read(rx_atomic_t *atomic, int change) {
192 return OSAtomicAdd32(change, &atomic->var);
196 rx_atomic_dec(rx_atomic_t *atomic) {
197 OSAtomicDecrement32(&atomic->var);
201 rx_atomic_dec_and_read(rx_atomic_t *atomic) {
202 return OSAtomicDecrement32(&atomic->var);
206 rx_atomic_sub(rx_atomic_t *atomic, int change) {
207 OSAtomicAdd32(0 - change, &atomic->var);
209 #elif defined(AFS_LINUX26_ENV) && defined(KERNEL)
210 #include <asm/atomic.h>
212 typedef atomic_t rx_atomic_t;
214 #define rx_atomic_set(X, V) atomic_set(X, V)
215 #define rx_atomic_read(X) atomic_read(X)
216 #define rx_atomic_inc(X) atomic_inc(X)
217 #define rx_atomic_inc_and_read(X) atomic_inc_return(X)
218 #define rx_atomic_add(X, V) atomic_add(V, X)
219 #define rx_atomic_add_and_read(X, V) atomic_add_return(V, X)
220 #define rx_atomic_dec(X) atomic_dec(X)
221 #define rx_atomic_dec_and_read(X) atomic_dec_return(X)
222 #define rx_atomic_sub(X, V) atomic_sub(V, X)
224 #elif defined(AFS_SUN510_ENV) || (defined(AFS_SUN5_ENV) && defined(KERNEL) && !defined(UKERNEL))
226 # if defined(KERNEL) && !defined(UKERNEL)
227 # include <sys/atomic.h>
232 #ifndef AFS_SUN510_ENV
233 # define atomic_inc_32(X) atomic_add_32((X), 1)
234 # define atomic_inc_32_nv(X) atomic_add_32_nv((X), 1)
235 # define atomic_dec_32(X) atomic_add_32((X), -1)
236 # define atomic_dec_32_nv(X) atomic_add_32_nv((X), -1)
240 volatile unsigned int var;
244 rx_atomic_set(rx_atomic_t *atomic, int val) {
249 rx_atomic_read(rx_atomic_t *atomic) {
254 rx_atomic_inc(rx_atomic_t *atomic) {
255 atomic_inc_32(&atomic->var);
259 rx_atomic_inc_and_read(rx_atomic_t *atomic) {
260 return atomic_inc_32_nv(&atomic->var);
264 rx_atomic_add(rx_atomic_t *atomic, int change) {
265 atomic_add_32(&atomic->var, change);
269 rx_atomic_add_and_read(rx_atomic_t *atomic, int change) {
270 return atomic_add_32_nv(&atomic->var, change);
274 rx_atomic_dec(rx_atomic_t *atomic) {
275 atomic_dec_32(&atomic->var);
279 rx_atomic_dec_and_read(rx_atomic_t *atomic) {
280 return atomic_dec_32_nv(&atomic->var);
284 rx_atomic_sub(rx_atomic_t *atomic, int change) {
285 atomic_add_32(&atomic->var, 0 - change);
288 #elif defined(__GNUC__) && defined(HAVE_SYNC_FETCH_AND_ADD)
295 rx_atomic_set(rx_atomic_t *atomic, int val) {
300 rx_atomic_read(rx_atomic_t *atomic) {
305 rx_atomic_inc(rx_atomic_t *atomic) {
306 (void)__sync_fetch_and_add(&atomic->var, 1);
310 rx_atomic_inc_and_read(rx_atomic_t *atomic) {
311 return __sync_add_and_fetch(&atomic->var, 1);
315 rx_atomic_add(rx_atomic_t *atomic, int change) {
316 (void)__sync_fetch_and_add(&atomic->var, change);
320 rx_atomic_add_and_read(rx_atomic_t *atomic, int change) {
321 return __sync_fetch_and_add(&atomic->var, change);
325 rx_atomic_dec(rx_atomic_t *atomic) {
326 (void)__sync_fetch_and_sub(&atomic->var, 1);
330 rx_atomic_dec_and_read(rx_atomic_t *atomic) {
331 return __sync_sub_and_fetch(&atomic->var, 1);
335 rx_atomic_sub(rx_atomic_t *atomic, int change) {
336 (void)__sync_fetch_and_sub(&atomic->var, change);
341 /* If we're on a platform where we have no idea how to do atomics,
342 * then we fall back to using a single process wide mutex to protect
343 * all atomic variables. This won't be the quickest thing ever.
346 #ifdef RX_ENABLE_LOCKS
347 extern afs_kmutex_t rx_atomic_mutex;
355 rx_atomic_set(rx_atomic_t *atomic, int val) {
356 MUTEX_ENTER(&rx_atomic_mutex);
358 MUTEX_EXIT(&rx_atomic_mutex);
362 rx_atomic_read(rx_atomic_t *atomic) {
365 MUTEX_ENTER(&rx_atomic_mutex);
367 MUTEX_EXIT(&rx_atomic_mutex);
373 rx_atomic_inc(rx_atomic_t *atomic) {
374 MUTEX_ENTER(&rx_atomic_mutex);
376 MUTEX_EXIT(&rx_atomic_mutex);
380 rx_atomic_inc_and_read(rx_atomic_t *atomic) {
382 MUTEX_ENTER(&rx_atomic_mutex);
384 retval = atomic->var;
385 MUTEX_EXIT(&rx_atomic_mutex);
390 rx_atomic_add(rx_atomic_t *atomic, int change) {
391 MUTEX_ENTER(&rx_atomic_mutex);
392 atomic->var += change;
393 MUTEX_EXIT(&rx_atomic_mutex);
397 rx_atomic_add_and_read(rx_atomic_t *atomic, int change) {
400 MUTEX_ENTER(&rx_atomic_mutex);
401 atomic->var += change;
402 retval = atomic->var;
403 MUTEX_EXIT(&rx_atomic_mutex);
409 rx_atomic_dec(rx_atomic_t *atomic) {
410 MUTEX_ENTER(&rx_atomic_mutex);
412 MUTEX_EXIT(&rx_atomic_mutex);
416 rx_atomic_dec_and_read(rx_atomic_t *atomic) {
418 MUTEX_ENTER(&rx_atomic_mutex);
420 retval = atomic->var;
421 MUTEX_EXIT(&rx_atomic_mutex);
427 rx_atomic_sub(rx_atomic_t *atomic, int change) {
428 MUTEX_ENTER(&rx_atomic_mutex);
429 atomic->var -= change;
430 MUTEX_EXIT(&rx_atomic_mutex);