Define OSATOMIC_USE_INLINED to get usable atomics on DARWIN
[openafs.git] / src / rx / rx_atomic.h
1 /*
2  * Copyright (c) 2010 Your Filesystem Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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.
23  */
24
25 #ifndef OPENAFS_RX_ATOMIC_H
26 #define OPENAFS_RX_ATOMIC_H 1
27
28 #define RX_ATOMIC_INIT(i) { (i) }
29
30 #ifdef AFS_NT40_ENV
31 typedef struct {
32     volatile int var;
33 } rx_atomic_t;
34
35 static_inline void
36 rx_atomic_set(rx_atomic_t *atomic, int val) {
37     atomic->var = val;
38 }
39
40 static_inline int
41 rx_atomic_read(rx_atomic_t *atomic) {
42     return atomic->var;
43 }
44
45 static_inline void
46 rx_atomic_inc(rx_atomic_t *atomic) {
47     InterlockedIncrement(&atomic->var);
48 }
49
50 static_inline int
51 rx_atomic_inc_and_read(rx_atomic_t *atomic) {
52     return InterlockedIncrement(&atomic->var);
53 }
54
55 static_inline void
56 rx_atomic_add(rx_atomic_t *atomic, int change) {
57     InterlockedExchangeAdd(&atomic->var, change);
58 }
59
60 static_inline int
61 rx_atomic_add_and_read(rx_atomic_t *atomic, int change) {
62     return InterlockedExchangeAdd(&atomic->var, change) + change;
63 }
64
65 static_inline void
66 rx_atomic_dec(rx_atomic_t *atomic) {
67     InterlockedDecrement(&atomic->var);
68 }
69
70 static_inline int
71 rx_atomic_dec_and_read(rx_atomic_t *atomic) {
72     return InterlockedDecrement(&atomic->var);
73 }
74
75 static_inline void
76 rx_atomic_sub(rx_atomic_t *atomic, int change) {
77     InterlockedExchangeAdd(&atomic->var, 0 - change);
78 }
79
80 static_inline int
81 rx_atomic_test_bit(rx_atomic_t *atomic, int bit) {
82     return ((unsigned int) rx_atomic_read(atomic) & 1<<bit) != 0;
83 }
84
85 /* No InterlockedOr or InterlockedAnd on ix86, so just use the
86  * BitTest functions */
87
88 static_inline void
89 rx_atomic_set_bit(rx_atomic_t *atomic, int bit) {
90     (void) InterlockedBitTestAndSet(&atomic->var, bit);
91 }
92
93 static_inline void
94 rx_atomic_clear_bit(rx_atomic_t *atomic, int bit) {
95     (void) InterlockedBitTestAndReset(&atomic->var, bit);
96 }
97
98 static_inline int
99 rx_atomic_test_and_set_bit(rx_atomic_t *atomic, int bit) {
100     return InterlockedBitTestAndSet(&atomic->var, bit);
101 }
102
103 static_inline int
104 rx_atomic_test_and_clear_bit(rx_atomic_t *atomic, int bit) {
105     return InterlockedBitTestAndReset(&atomic->var, bit);
106 }
107
108 #elif defined(AFS_AIX61_ENV) || defined(AFS_USR_AIX61_ENV)
109 #include <sys/atomic_op.h>
110
111 typedef struct {
112    volatile int var;
113 } rx_atomic_t;
114
115 static_inline void
116 rx_atomic_set(rx_atomic_t *atomic, int val) {
117     atomic->var = val;
118 }
119
120 static_inline int
121 rx_atomic_read(rx_atomic_t *atomic) {
122     return atomic->var;
123 }
124
125 static_inline void
126 rx_atomic_inc(rx_atomic_t *atomic) {
127     fetch_and_add(&atomic->var, 1);
128 }
129
130 static_inline int
131 rx_atomic_inc_and_read(rx_atomic_t *atomic) {
132     return (fetch_and_add(&atomic->var, 1) + 1);
133 }
134
135 static_inline void
136 rx_atomic_add(rx_atomic_t *atomic, int change) {
137     fetch_and_add(&atomic->var, change);
138 }
139
140 static_inline int
141 rx_atomic_add_and_read(rx_atomic_t *atomic, int change) {
142     return (fetch_and_add(&atomic->var, change) + change);
143 }
144
145 static_inline void
146 rx_atomic_dec(rx_atomic_t *atomic) {
147     fetch_and_add(&atomic->var, -1);
148 }
149
150 static_inline int
151 rx_atomic_dec_and_read(rx_atomic_t *atomic) {
152     return (fetch_and_add(&atomic->var, -1) - 1);
153 }
154
155 static_inline void
156 rx_atomic_sub(rx_atomic_t *atomic, int change) {
157     fetch_and_add(&atomic->var, -change);
158 }
159
160 static_inline int
161 rx_atomic_test_bit(rx_atomic_t *atomic, int bit) {
162     return ((unsigned int) rx_atomic_read(atomic) & 1<<bit) != 0;
163 }
164
165 static_inline void
166 rx_atomic_set_bit(rx_atomic_t *atomic, int bit) {
167     fetch_and_or(&atomic->var, 1<<bit);
168 }
169
170 static_inline void
171 rx_atomic_clear_bit(rx_atomic_t *atomic, int bit) {
172     fetch_and_and(&atomic->var, ~(1<<bit));
173 }
174
175 static_inline int
176 rx_atomic_test_and_set_bit(rx_atomic_t *atomic, int bit) {
177     return (fetch_and_or(&atomic->var, (1<<bit)) & 1<<bit) != 0;
178 }
179
180 static_inline int
181 rx_atomic_test_and_clear_bit(rx_atomic_t *atomic, int bit) {
182     return (fetch_and_and(&atomic->var, ~(1<<bit)) & 1<<bit) != 0;
183 }
184
185 #elif defined(AFS_DARWIN80_ENV) || defined(AFS_USR_DARWIN80_ENV)
186
187 # if defined (AFS_DARWIN160_ENV) || defined(AFS_USR_DARWIN160_ENV)
188 #  define OSATOMIC_USE_INLINED 1
189 # else
190
191 #  if defined(KERNEL) && !defined(UKERNEL)
192 #   define OSAtomicIncrement32 OSIncrementAtomic
193 #   define OSAtomicAdd32 OSAddAtomic
194 #   define OSAtomicDecrement32 OSDecrementAtomic
195 #   define OSAtomicOr32 OSBitOrAtomic
196 #   define OSAtomicAnd32 OSBitAndAtomic
197 #  endif
198
199 # endif /* end defined DARWIN160 */
200
201 # include <libkern/OSAtomic.h>
202
203 typedef struct {
204     volatile int var;
205 } rx_atomic_t;
206
207 static_inline void
208 rx_atomic_set(rx_atomic_t *atomic, int val) {
209     atomic->var = val;
210 }
211
212 static_inline int
213 rx_atomic_read(rx_atomic_t *atomic) {
214     return atomic->var;
215 }
216
217 static_inline void
218 rx_atomic_inc(rx_atomic_t *atomic) {
219     OSAtomicIncrement32(&atomic->var);
220 }
221
222 static_inline int
223 rx_atomic_inc_and_read(rx_atomic_t *atomic) {
224     return OSAtomicIncrement32(&atomic->var);
225 }
226
227 static_inline void
228 rx_atomic_add(rx_atomic_t *atomic, int change) {
229     OSAtomicAdd32(change, &atomic->var);
230 }
231
232 static_inline int
233 rx_atomic_add_and_read(rx_atomic_t *atomic, int change) {
234     return OSAtomicAdd32(change, &atomic->var);
235 }
236
237 static_inline void
238 rx_atomic_dec(rx_atomic_t *atomic) {
239     OSAtomicDecrement32(&atomic->var);
240 }
241
242 static_inline int
243 rx_atomic_dec_and_read(rx_atomic_t *atomic) {
244     return OSAtomicDecrement32(&atomic->var);
245 }
246
247 static_inline void
248 rx_atomic_sub(rx_atomic_t *atomic, int change) {
249     OSAtomicAdd32(0 - change, &atomic->var);
250 }
251
252 static_inline int
253 rx_atomic_test_bit(rx_atomic_t *atomic, int bit) {
254     return ((unsigned int) rx_atomic_read(atomic) & 1<<bit) != 0;
255 }
256
257 static_inline void
258 rx_atomic_set_bit(rx_atomic_t *atomic, int bit) {
259     OSAtomicOr32(1<<bit, (volatile uint32_t *)&atomic->var);
260 }
261
262 static_inline void
263 rx_atomic_clear_bit(rx_atomic_t *atomic, int bit) {
264     OSAtomicAnd32(~(1<<bit), (volatile uint32_t *)&atomic->var);
265 }
266
267 static_inline int
268 rx_atomic_test_and_set_bit(rx_atomic_t *atomic, int bit) {
269     return ((OSAtomicOr32Orig(1<<bit, (volatile uint32_t *)&atomic->var) & 1<<bit)
270                 != 0);
271 }
272
273 static_inline int
274 rx_atomic_test_and_clear_bit(rx_atomic_t *atomic, int bit) {
275     return ((OSAtomicAnd32Orig(~(1<<bit),
276                                (volatile uint32_t *)&atomic->var) & 1<<bit)
277             != 0);
278 }
279
280 #elif defined(AFS_LINUX26_ENV) && defined(KERNEL)
281 #include <asm/atomic.h>
282
283 typedef atomic_t rx_atomic_t;
284
285 #define rx_atomic_set(X, V)       atomic_set(X, V)
286 #define rx_atomic_read(X)         atomic_read(X)
287 #define rx_atomic_inc(X)          atomic_inc(X)
288 #define rx_atomic_inc_and_read(X) atomic_inc_return(X)
289 #define rx_atomic_add(X, V)       atomic_add(V, X)
290 #define rx_atomic_add_and_read(X, V) atomic_add_return(V, X)
291 #define rx_atomic_dec(X)          atomic_dec(X)
292 #define rx_atomic_dec_and_read(X) atomic_dec_return(X)
293 #define rx_atomic_sub(X, V)       atomic_sub(V, X)
294 #define rx_atomic_test_bit(X, B)  test_bit(B, (unsigned long *) &(X)->counter)
295 #define rx_atomic_set_bit(X, B)   set_bit(B, (unsigned long *) &(X)->counter)
296 #define rx_atomic_clear_bit(X, B) clear_bit(B, (unsigned long *) &(X)->counter)
297 #define rx_atomic_test_and_set_bit(X, B)    test_and_set_bit(B, (unsigned long *) &(X)->counter)
298 #define rx_atomic_test_and_clear_bit(X, B)  test_and_clear_bit(B, (unsigned long *) &(X)->counter)
299
300 #elif defined(AFS_SUN510_ENV) || (defined(AFS_SUN5_ENV) && defined(KERNEL) && !defined(UKERNEL))
301
302 # if defined(KERNEL) && !defined(UKERNEL)
303 #  include <sys/atomic.h>
304 # else
305 #  include <atomic.h>
306 # endif
307
308 #ifndef AFS_SUN510_ENV
309 # define atomic_inc_32(X)    atomic_add_32((X), 1)
310 # define atomic_inc_32_nv(X) atomic_add_32_nv((X), 1)
311 # define atomic_dec_32(X)    atomic_add_32((X), -1)
312 # define atomic_dec_32_nv(X) atomic_add_32_nv((X), -1)
313 #endif
314
315 typedef struct {
316     volatile unsigned int var;
317 } rx_atomic_t;
318
319 static_inline void
320 rx_atomic_set(rx_atomic_t *atomic, int val) {
321     atomic->var = val;
322 }
323
324 static_inline int
325 rx_atomic_read(rx_atomic_t *atomic) {
326     return atomic->var;
327 }
328
329 static_inline void
330 rx_atomic_inc(rx_atomic_t *atomic) {
331     atomic_inc_32(&atomic->var);
332 }
333
334 static_inline int
335 rx_atomic_inc_and_read(rx_atomic_t *atomic) {
336     return atomic_inc_32_nv(&atomic->var);
337 }
338
339 static_inline void
340 rx_atomic_add(rx_atomic_t *atomic, int change) {
341     atomic_add_32(&atomic->var, change);
342 }
343
344 static_inline int
345 rx_atomic_add_and_read(rx_atomic_t *atomic, int change) {
346     return atomic_add_32_nv(&atomic->var, change);
347 }
348
349 static_inline void
350 rx_atomic_dec(rx_atomic_t *atomic) {
351     atomic_dec_32(&atomic->var);
352 }
353
354 static_inline int
355 rx_atomic_dec_and_read(rx_atomic_t *atomic) {
356     return atomic_dec_32_nv(&atomic->var);
357 }
358
359 static_inline void
360 rx_atomic_sub(rx_atomic_t *atomic, int change) {
361     atomic_add_32(&atomic->var, 0 - change);
362 }
363
364 static_inline int
365 rx_atomic_test_bit(rx_atomic_t *atomic, int bit) {
366     return ((unsigned int) rx_atomic_read(atomic) & 1<<bit) != 0;
367 }
368
369 static_inline void
370 rx_atomic_set_bit(rx_atomic_t *atomic, int bit) {
371     atomic_or_32(&atomic->var, 1<<bit);
372 }
373
374 static_inline void
375 rx_atomic_clear_bit(rx_atomic_t *atomic, int bit) {
376     atomic_and_32(&atomic->var, ~(1<<bit));
377 }
378
379 static_inline int
380 rx_atomic_test_and_set_bit(rx_atomic_t *atomic, int bit) {
381     return (atomic_set_long_excl(&atomic->var, bit) == -1);
382 }
383
384 static_inline int
385 rx_atomic_test_and_clear_bit(rx_atomic_t *atomic, int bit) {
386     return (atomic_clear_long_excl(&atomic->var, bit) == 0);
387 }
388
389 #elif defined(__GNUC__) && defined(HAVE_SYNC_FETCH_AND_ADD)
390
391 typedef struct {
392    volatile int var;
393 } rx_atomic_t;
394
395 static_inline void
396 rx_atomic_set(rx_atomic_t *atomic, int val) {
397     atomic->var = val;
398 }
399
400 static_inline int
401 rx_atomic_read(rx_atomic_t *atomic) {
402     return atomic->var;
403 }
404
405 static_inline void
406 rx_atomic_inc(rx_atomic_t *atomic) {
407     (void)__sync_fetch_and_add(&atomic->var, 1);
408 }
409
410 static_inline int
411 rx_atomic_inc_and_read(rx_atomic_t *atomic) {
412     return __sync_add_and_fetch(&atomic->var, 1);
413 }
414
415 static_inline void
416 rx_atomic_add(rx_atomic_t *atomic, int change) {
417     (void)__sync_fetch_and_add(&atomic->var, change);
418 }
419
420 static_inline int
421 rx_atomic_add_and_read(rx_atomic_t *atomic, int change) {
422     return __sync_fetch_and_add(&atomic->var, change);
423 }
424
425 static_inline void
426 rx_atomic_dec(rx_atomic_t *atomic) {
427     (void)__sync_fetch_and_sub(&atomic->var, 1);
428 }
429
430 static_inline int
431 rx_atomic_dec_and_read(rx_atomic_t *atomic) {
432     return __sync_sub_and_fetch(&atomic->var, 1);
433 }
434
435 static_inline void
436 rx_atomic_sub(rx_atomic_t *atomic, int change) {
437     (void)__sync_fetch_and_sub(&atomic->var, change);
438 }
439
440 static_inline int
441 rx_atomic_test_bit(rx_atomic_t *atomic, int bit) {
442     return ((unsigned int) rx_atomic_read(atomic) & 1<<bit) != 0;
443 }
444
445 static_inline void
446 rx_atomic_set_bit(rx_atomic_t *atomic, int bit) {
447     (void)__sync_fetch_and_or(&atomic->var, 1<<bit);
448 }
449
450 static_inline void
451 rx_atomic_clear_bit(rx_atomic_t *atomic, int bit) {
452     (void)__sync_fetch_and_and(&atomic->var, ~(1<<bit));
453 }
454
455 static_inline int
456 rx_atomic_test_and_set_bit(rx_atomic_t *atomic, int bit) {
457     return (__sync_fetch_and_or(&atomic->var, 1<<bit) & 1<<bit) != 0;
458 }
459
460 static_inline int
461 rx_atomic_test_and_clear_bit(rx_atomic_t *atomic, int bit) {
462     return (__sync_fetch_and_and(&atomic->var, ~(1<<bit)) & 1<<bit) != 0;
463 }
464
465 #else
466
467 /* If we're on a platform where we have no idea how to do atomics,
468  * then we fall back to using a single process wide mutex to protect
469  * all atomic variables. This won't be the quickest thing ever.
470  */
471
472 #ifdef RX_ENABLE_LOCKS
473 extern afs_kmutex_t rx_atomic_mutex;
474 #endif
475
476 typedef struct {
477     int var;
478 } rx_atomic_t;
479
480 static_inline void
481 rx_atomic_set(rx_atomic_t *atomic, int val) {
482     MUTEX_ENTER(&rx_atomic_mutex);
483     atomic->var = val;
484     MUTEX_EXIT(&rx_atomic_mutex);
485 }
486
487 static_inline int
488 rx_atomic_read(rx_atomic_t *atomic) {
489     int out;
490
491     MUTEX_ENTER(&rx_atomic_mutex);
492     out = atomic->var;
493     MUTEX_EXIT(&rx_atomic_mutex);
494
495     return out;
496 }
497
498 static_inline void
499 rx_atomic_inc(rx_atomic_t *atomic) {
500    MUTEX_ENTER(&rx_atomic_mutex);
501    atomic->var++;
502    MUTEX_EXIT(&rx_atomic_mutex);
503 }
504
505 static_inline int
506 rx_atomic_inc_and_read(rx_atomic_t *atomic) {
507     int retval;
508     MUTEX_ENTER(&rx_atomic_mutex);
509     atomic->var++;
510     retval = atomic->var;
511     MUTEX_EXIT(&rx_atomic_mutex);
512     return retval;
513 }
514
515 static_inline void
516 rx_atomic_add(rx_atomic_t *atomic, int change) {
517     MUTEX_ENTER(&rx_atomic_mutex);
518     atomic->var += change;
519     MUTEX_EXIT(&rx_atomic_mutex);
520 }
521
522 static_inline int
523 rx_atomic_add_and_read(rx_atomic_t *atomic, int change) {
524     int retval;
525
526     MUTEX_ENTER(&rx_atomic_mutex);
527     atomic->var += change;
528     retval = atomic->var;
529     MUTEX_EXIT(&rx_atomic_mutex);
530
531     return retval;
532 }
533
534 static_inline void
535 rx_atomic_dec(rx_atomic_t *atomic) {
536     MUTEX_ENTER(&rx_atomic_mutex);
537     atomic->var--;
538     MUTEX_EXIT(&rx_atomic_mutex);
539 }
540
541 static_inline int
542 rx_atomic_dec_and_read(rx_atomic_t *atomic) {
543     int retval;
544     MUTEX_ENTER(&rx_atomic_mutex);
545     atomic->var--;
546     retval = atomic->var;
547     MUTEX_EXIT(&rx_atomic_mutex);
548     return retval;
549 }
550
551
552 static_inline void
553 rx_atomic_sub(rx_atomic_t *atomic, int change) {
554     MUTEX_ENTER(&rx_atomic_mutex);
555     atomic->var -= change;
556     MUTEX_EXIT(&rx_atomic_mutex);
557 }
558
559 static_inline int
560 rx_atomic_test_bit(rx_atomic_t *atomic, int bit) {
561     return ((unsigned int) rx_atomic_read(atomic) & 1<<bit) != 0;
562 }
563
564 static_inline void
565 rx_atomic_set_bit(rx_atomic_t *atomic, int bit) {
566     MUTEX_ENTER(&rx_atomic_mutex);
567     atomic->var |= (1<<bit);
568     MUTEX_EXIT(&rx_atomic_mutex);
569 }
570
571 static_inline void
572 rx_atomic_clear_bit(rx_atomic_t *atomic, int bit) {
573     MUTEX_ENTER(&rx_atomic_mutex);
574     atomic->var &= ~(1<<bit);
575     MUTEX_EXIT(&rx_atomic_mutex);
576 }
577
578 static_inline int
579 rx_atomic_test_and_set_bit(rx_atomic_t *atomic, int bit) {
580     int val;
581
582     MUTEX_ENTER(&rx_atomic_mutex);
583     val = atomic->var;
584     atomic->var |= 1<<bit;
585     MUTEX_EXIT(&rx_atomic_mutex);
586
587     return (val & 1<<bit) == 1<<bit;
588 }
589
590 static_inline int
591 rx_atomic_test_and_clear_bit(rx_atomic_t *atomic, int bit) {
592     int val;
593
594     MUTEX_ENTER(&rx_atomic_mutex);
595     val = atomic->var;
596     atomic->var &= ~(1<<bit);
597     MUTEX_EXIT(&rx_atomic_mutex);
598
599     return (val & 1<<bit) == 1<<bit;
600 }
601 #endif
602
603 #endif