5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2006 - 2007 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
20 /****h* silcutil/SILC Atomic Operations Interface
24 * SILC Atomic operations interface provides utility functions to perform
25 * simple operations with integers atomically. This enables fast integer
26 * additions and subtractions safely in multithreaded environment. It is
27 * especially suited for reference counters and similar and is much faster
28 * than using locking. This interface supports 8, 16 and 32 bit integers
29 * and 32 or 64 bit pointers.
31 * On some platforms this interface actually use mutual exclusion lock
32 * instead of true atomic operations, leading into some performace penalty.
33 * Also on some platforms the 8 and 16 bit integers are actually 32 bit
36 * Fast operations are supported on: x86, x86_64, ia64, PPC
43 /* For now we always assume SMP */
46 /* Use lock prefix only on true SMP systems */
48 #define SILC_SMP_LOCK "lock; "
53 /****s* silcutil/SilcAtomicAPI/SilcAtomic32
57 * typedef struct { ... } SilcAtomic32;
61 * The atomic operation structure given as argument to all atomic
62 * operation functions. It hols the actual 32-bit atomic variable.
66 * SilcAtomic32 refcnt;
68 * // Initialize atomic variable
69 * silc_atomic_init32(&refcnt, 0);
72 * // Increment referene counter
73 * silc_atomic_add_int32(&refcnt, 1);
76 * // Uninitialize atomic variable
77 * silc_atomic_uninit32(&refcnt);
81 /****s* silcutil/SilcAtomicAPI/SilcAtomic16
85 * typedef struct { ... } SilcAtomic16;
89 * The atomic operation structure given as argument to all atomic
90 * operation functions. It hols the actual 16-bit atomic variable.
94 * SilcAtomic16 refcnt;
96 * // Initialize atomic variable
97 * silc_atomic_init16(&refcnt, 0);
100 * // Increment referene counter
101 * silc_atomic_add_int16(&refcnt, 1);
104 * // Uninitialize atomic variable
105 * silc_atomic_uninit16(&refcnt);
109 /****s* silcutil/SilcAtomicAPI/SilcAtomic8
113 * typedef struct { ... } SilcAtomic8;
117 * The atomic operation structure given as argument to all atomic
118 * operation functions. It hols the actual 8-bit atomic variable.
122 * SilcAtomic8 refcnt;
124 * // Initialize atomic variable
125 * silc_atomic_init8(&refcnt, 0);
128 * // Increment referene counter
129 * silc_atomic_add_int8(&refcnt, 1);
132 * // Uninitialize atomic variable
133 * silc_atomic_uninit8(&refcnt);
137 /****s* silcutil/SilcAtomicAPI/SilcAtomicPointer
141 * typedef struct { ... } SilcAtomicPointer;
145 * The atomic operation structure given as argument to all atomic
146 * operation functions. It hols the actual pointer variable.
150 * SilcAtomicPointer ptr;
152 * // Initialize atomic variable
153 * silc_atomic_init_pointer(&ptr, NULL);
157 * silc_atomic_set_pointer(&ptr, context);
160 * // Uninitialize atomic variable
161 * silc_atomic_uninit_pointer(&ptr);
165 #if !defined(SILC_THREADS) || defined(SILC_WIN32) || (defined(__GNUC__) && \
166 (defined(SILC_I486) || defined(SILC_X86_64) || defined(SILC_IA64) || \
167 defined(SILC_POWERPC)))
169 volatile SilcUInt32 value;
172 volatile void *value;
175 #define SILC_ATOMIC_MUTEX
178 volatile SilcUInt32 value;
182 volatile void *value;
186 #if !defined(SILC_THREADS) || (defined(__GNUC__) && (defined(SILC_I486) || \
187 defined(SILC_X86_64)))
189 volatile SilcUInt16 value;
191 #elif defined(SILC_WIN32) || (defined(__GNUC__) && (defined(SILC_IA64) || \
192 defined(SILC_POWERPC)))
194 volatile SilcUInt32 value;
199 volatile SilcUInt16 value;
203 #if !defined(SILC_THREADS) || (defined(__GNUC__) && (defined(SILC_I486) || \
204 defined(SILC_X86_64)))
206 volatile SilcUInt8 value;
208 #elif defined(SILC_WIN32) || (defined(__GNUC__) && (defined(SILC_IA64) || \
209 defined(SILC_POWERPC)))
211 volatile SilcUInt32 value;
216 volatile SilcUInt8 value;
220 /****f* silcutil/SilcAtomicAPI/silc_atomic_init32
225 * SilcBool silc_atomic_init32(SilcAtomic32 *atomic, SilcUInt32 value);
229 * Initializes the atomic variable `atomic', and sets the `value' as its
230 * inital value. Returns FALSE on error. To uninitialize call the
231 * silc_atomic_uninit32 function.
235 /****f* silcutil/SilcAtomicAPI/silc_atomic_init16
240 * SilcBool silc_atomic_init16(SilcAtomic16 *atomic, SilcUInt16 value);
244 * Initializes the atomic variable `atomic', and sets the `value' as its
245 * inital value. Returns FALSE on error. To uninitialize call the
246 * silc_atomic_uninit32 function.
250 /****f* silcutil/SilcAtomicAPI/silc_atomic_init8
255 * SilcBool silc_atomic_init8(SilcAtomic8 *atomic, SilcUInt8 value);
259 * Initializes the atomic variable `atomic', and sets the `value' as its
260 * inital value. Returns FALSE on error. To uninitialize call the
261 * silc_atomic_uninit8 function.
265 /****f* silcutil/SilcAtomicAPI/silc_atomic_init_pointer
270 * SilcBool silc_atomic_init_pointer(SilcAtomicPointer *atomic,
275 * Initializes the atomic pointer variable `atomic', and sets the `pointer'
276 * as its inital pointer. Returns FALSE on error. To uninitialize call
277 * the silc_atomic_uninit_pointer function.
281 #define SILC_ATOMIC_INIT_F(name, bits, type) \
283 SilcBool silc_atomic_init##name(SilcAtomic##bits *atomic, type value)
285 #if defined(SILC_ATOMIC_MUTEX)
286 #define SILC_ATOMIC_INIT(name, bits, type) \
287 SILC_ATOMIC_INIT_F(name, bits, type) \
289 atomic->value = value; \
290 return silc_mutex_alloc(&atomic->lock); \
293 #define SILC_ATOMIC_INIT(name, bits, type) \
294 SILC_ATOMIC_INIT_F(name, bits, type) \
296 atomic->value = value; \
299 #endif /* SILC_ATOMIC_MUTEX */
301 SILC_ATOMIC_INIT(8, 8, SilcUInt8);
302 SILC_ATOMIC_INIT(16, 16, SilcUInt16);
303 SILC_ATOMIC_INIT(32, 32, SilcUInt32);
304 SILC_ATOMIC_INIT(_pointer, Pointer, void *);
306 /****f* silcutil/SilcAtomicAPI/silc_atomic_uninit32
311 * void silc_atomic_uninit32(SilcAtomic32 *atomic);
315 * Uninitializes the atomic variable `atomic'. This should alwyas be
316 * called after the atomic variable is not used anymore.
320 /****f* silcutil/SilcAtomicAPI/silc_atomic_uninit16
325 * void silc_atomic_uninit16(SilcAtomic16 *atomic);
329 * Uninitializes the atomic variable `atomic'. This should alwyas be
330 * called after the atomic variable is not used anymore.
334 /****f* silcutil/SilcAtomicAPI/silc_atomic_uninit8
339 * void silc_atomic_uninit8(SilcAtomic8 *atomic);
343 * Uninitializes the atomic variable `atomic'. This should alwyas be
344 * called after the atomic variable is not used anymore.
348 /****f* silcutil/SilcAtomicAPI/silc_atomic_uninit_pointer
353 * void silc_atomic_uninit_pointer(SilcAtomicPointer *atomic);
357 * Uninitializes the atomic variable `atomic'. This should alwyas be
358 * called after the atomic variable is not used anymore.
362 #define SILC_ATOMIC_UNINIT_F(bits, t) \
363 static inline void silc_atomic_uninit##bits(SilcAtomic##t *atomic)
365 #if defined(SILC_ATOMIC_MUTEX)
366 #define SILC_ATOMIC_UNINIT(bits, t) \
367 SILC_ATOMIC_UNINIT_F(bits, t) \
369 silc_mutex_free(atomic->lock); \
372 #define SILC_ATOMIC_UNINIT(bits, t) \
373 SILC_ATOMIC_UNINIT_F(bits, t) \
376 #endif /* SILC_ATOMIC_MUTEX */
378 SILC_ATOMIC_UNINIT(8, 8);
379 SILC_ATOMIC_UNINIT(16, 16);
380 SILC_ATOMIC_UNINIT(32, 32);
381 SILC_ATOMIC_UNINIT(_pointer, Pointer);
383 /****f* silcutil/SilcAtomicAPI/silc_atomic_set_int32
388 * void silc_atomic_set_int32(SilcAtomic32 *atomic, SilcUInt32 value);
392 * Atomically sets `value' to 32-bit integer.
396 /****f* silcutil/SilcAtomicAPI/silc_atomic_set_int16
401 * void silc_atomic_set_int16(SilcAtomic16 *atomic, SilcUInt16 value);
405 * Atomically sets `value' to 16-bit integer.
409 /****f* silcutil/SilcAtomicAPI/silc_atomic_set_int8
414 * void silc_atomic_set_int8(SilcAtomic8 *atomic, SilcUInt8 value);
418 * Atomically sets `value' to 8-bit integer.
422 #define SILC_ATOMIC_SET_INT_F(bits) \
423 static inline void silc_atomic_set_int##bits(SilcAtomic##bits *atomic, \
424 SilcUInt##bits value)
426 #if !defined(SILC_THREADS)
427 #define SILC_ATOMIC_SET_INT(bits, bp, bp2) \
428 SILC_ATOMIC_SET_INT_F(bits) \
430 /* No atomic operations */ \
431 atomic->value = value; \
434 #elif defined(SILC_WIN32)
435 #define SILC_ATOMIC_SET_INT(bits, bp, bp2) \
436 SILC_ATOMIC_SET_INT_F(bits) \
439 InterlockedExchange((LONG)&atomic->value, (LONG)value); \
442 #elif defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64))
443 #define SILC_ATOMIC_SET_INT(bits, bp, bp2) \
444 SILC_ATOMIC_SET_INT_F(bits) \
446 /* GCC + i486 or x86_64 */ \
447 __asm __volatile("xchg" bp " %" bp2 "0, %1" \
449 : "m" (atomic->value), "0" (value)); \
452 #elif defined(__GNUC__) && defined(SILC_IA64)
453 #define SILC_ATOMIC_SET_INT(bits, bp, bp2) \
454 SILC_ATOMIC_SET_INT_F(bits) \
456 /* IA64, memory barrier needed */ \
457 atomic->value = value; \
458 __sync_synchronize(); \
461 #elif defined(__GNUC__) && defined(SILC_POWERPC)
462 #define SILC_ATOMIC_SET_INT(bits, bp, bp2) \
463 SILC_ATOMIC_SET_INT_F(bits) \
465 /* PowerPC, memory barrier needed */ \
466 atomic->value = value; \
467 __asm("sync" : : : "memory"); \
470 #else /* SILC_ATOMIC_MUTEX */
471 #define SILC_ATOMIC_SET_INT(bits, bp, bp2) \
472 SILC_ATOMIC_SET_INT_F(bits) \
475 silc_mutex_lock(atomic->lock); \
476 atomic->value = value; \
477 silc_mutex_unlock(atomic->lock); \
479 #endif /* !SILC_THREADS */
481 SILC_ATOMIC_SET_INT(8, "b", "b");
482 SILC_ATOMIC_SET_INT(16, "w", "w");
483 SILC_ATOMIC_SET_INT(32, "l", "");
485 /****f* silcutil/SilcAtomicAPI/silc_atomic_set_pointer
490 * void silc_atomic_set_pointer(SilcAtomicPointer *atomic, void *pointer);
494 * Atomically sets `pointer' to the atomic variable.
499 void silc_atomic_set_pointer(SilcAtomicPointer *atomic, void *pointer)
501 #if !defined(SILC_THREADS) || \
502 (defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64)))
503 /* No threads, Windows, i486 or x86_64, no memory barrier needed */
504 atomic->value = pointer;
506 #elif defined(SILC_WIN32)
507 InterlockedExchangePointer(&atomic->value, pointer);
509 #elif defined(__GNUC__) && defined(SILC_IA64)
510 /* IA64, memory barrier needed */
511 atomic->value = pointer;
512 __sync_synchronize();
514 #elif defined(__GNUC__) && defined(SILC_POWERPC)
515 /* PowerPC, memory barrier needed */
516 atomic->value = pointer;
517 __asm("sync" : : : "memory");
521 silc_mutex_lock(atomic->lock);
522 atomic->value = pointer;
523 silc_mutex_unlock(atomic->lock);
527 /****f* silcutil/SilcAtomicAPI/silc_atomic_get_int32
532 * SilcUInt32 silc_atomic_get_int32(SilcAtomic32 *atomic);
536 * Returns the current value of the atomic variable.
540 /****f* silcutil/SilcAtomicAPI/silc_atomic_get_int16
545 * SilcUInt32 silc_atomic_get_int16(SilcAtomic16 *atomic);
549 * Returns the current value of the atomic variable.
553 /****f* silcutil/SilcAtomicAPI/silc_atomic_get_int8
558 * SilcUInt32 silc_atomic_get_int8(SilcAtomic8 *atomic);
562 * Returns the current value of the atomic variable.
566 #define SILC_ATOMIC_GET_INT_F(bits) \
568 SilcUInt##bits silc_atomic_get_int##bits(SilcAtomic##bits *atomic)
570 #if !defined(SILC_THREADS) || defined(SILC_WIN32) || \
571 (defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64)))
572 #define SILC_ATOMIC_GET_INT(bits) \
573 SILC_ATOMIC_GET_INT_F(bits) \
575 SilcUInt##bits ret; \
577 /* No threads, Windows, i486 or x86_64, no memory barrier needed */ \
578 ret = atomic->value; \
582 #elif defined(__GNUC__) && defined(SILC_IA64)
583 #define SILC_ATOMIC_GET_INT(bits) \
584 SILC_ATOMIC_GET_INT_F(bits) \
586 SilcUInt##bits ret; \
588 /* IA64, memory barrier needed */ \
589 __sync_synchronize(); \
590 ret = atomic->value; \
594 #elif defined(__GNUC__) && defined(SILC_POWERPC)
595 #define SILC_ATOMIC_GET_INT(bits) \
596 SILC_ATOMIC_GET_INT_F(bits) \
598 SilcUInt##bits ret; \
600 /* PowerPC, memory barrier needed */ \
601 __asm("sync" : : : "memory"); \
602 ret = atomic->value; \
606 #else /* SILC_ATOMIC_MUTEX */
607 #define SILC_ATOMIC_GET_INT(bits) \
608 SILC_ATOMIC_GET_INT_F(bits) \
610 SilcUInt##bits ret; \
613 silc_mutex_lock(atomic->lock); \
614 ret = atomic->value; \
615 silc_mutex_unlock(atomic->lock); \
618 #endif /* !SILC_THREADS */
620 SILC_ATOMIC_GET_INT(8);
621 SILC_ATOMIC_GET_INT(16);
622 SILC_ATOMIC_GET_INT(32);
624 /****f* silcutil/SilcAtomicAPI/silc_atomic_get_pointer
629 * SilcUInt8 silc_atomic_get_pointer(SilcAtomicPointer *atomic)
633 * Returns the current pointer value of the atomic variable.
638 void *silc_atomic_get_pointer(SilcAtomicPointer *atomic)
642 #if !defined(SILC_THREADS) || defined(SILC_WIN32) || \
643 (defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64)))
644 /* No threads, Windows, i486 or x86_64, no memory barrier needed */
645 ret = (void *)atomic->value;
648 #elif defined(__GNUC__) && defined(SILC_IA64)
649 /* IA64, memory barrier needed */
650 __sync_synchronize();
651 ret = (void *)atomic->value;
654 #elif defined(__GNUC__) && defined(SILC_POWERPC)
655 /* PowerPC, memory barrier needed */
656 __asm("sync" : : : "memory");
657 ret = (void *)atomic->value;
662 silc_mutex_lock(atomic->lock);
663 ret = (void *)atomic->value;
664 silc_mutex_unlock(atomic->lock);
669 /****f* silcutil/SilcAtomicAPI/silc_atomic_add_int32
674 * SilcUInt32 silc_atomic_add_int32(SilcAtomic32 *atomic, SilcInt32 value);
678 * Atomically adds `value' to 32-bit integer. Returns the value after
683 /****f* silcutil/SilcAtomicAPI/silc_atomic_add_int32
688 * SilcUInt16 silc_atomic_add_int16(SilcAtomic16 *atomic, SilcInt16 value);
692 * Atomically adds `value' to 16-bit integer. Returns the value after
697 /****f* silcutil/SilcAtomicAPI/silc_atomic_add_int8
702 * SilcUInt8 silc_atomic_add_int8(SilcAtomic8 *atomic, SilcInt8 value);
706 * Atomically adds `value' to 8-bit integer. Returns the value after
711 #define SILC_ATOMIC_ADD_INT_F(bits) \
713 SilcUInt##bits silc_atomic_add_int##bits(SilcAtomic##bits *atomic, \
716 #if !defined(SILC_THREADS)
717 #define SILC_ATOMIC_ADD_INT(bits, bp) \
718 SILC_ATOMIC_ADD_INT_F(bits) \
720 SilcUInt##bits ret; \
721 /* No atomic operations */ \
722 ret = atomic->value; \
723 atomic->value += value; \
724 return ret + value; \
727 #elif defined(SILC_WIN32)
728 #define SILC_ATOMIC_ADD_INT(bits, bp) \
729 SILC_ATOMIC_ADD_INT_F(bits) \
731 SilcUInt##bits ret; \
734 ret = InterlockedExchangeAdd(&atomic->value, val); \
735 return ret + value; \
738 #elif defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64))
739 #define SILC_ATOMIC_ADD_INT(bits, bp) \
740 SILC_ATOMIC_ADD_INT_F(bits) \
742 SilcUInt##bits ret; \
743 /* GCC + i486 or x86_64 */ \
744 __asm __volatile(SILC_SMP_LOCK "xadd" bp " %0, %1" \
745 : "=r" (ret), "+m" (atomic->value) \
747 return ret + value; \
750 #elif defined(__GNUC__) && defined(SILC_IA64)
751 #define SILC_ATOMIC_ADD_INT(bits, bp) \
752 SILC_ATOMIC_ADD_INT_F(bits) \
754 SilcUInt##bits ret; \
755 SilcInt32 val = value;
756 /* GCC + IA64 (GCC builtin atomic operations) */ \
757 ret = __sync_fetch_and_add(&atomic->value, val); \
758 return ret + value; \
761 #elif defined(__GNUC__) && defined(SILC_POWERPC)
762 #define SILC_ATOMIC_ADD_INT(bits, bp) \
763 SILC_ATOMIC_ADD_INT_F(bits) \
766 SilcInt32 val = value; \
767 /* GCC + PowerPC (code adapted from IBM's documentation) */ \
768 __asm __volatile("0: lwarx %0, 0, %2\n" \
769 " add %0, %1, %0\n" \
770 " stwcx. %0, 0, %2\n" \
773 : "r" (val), "r" (&atomic->value) \
778 #else /* SILC_ATOMIC_MUTEX */
779 #define SILC_ATOMIC_ADD_INT(bits, bp) \
780 SILC_ATOMIC_ADD_INT_F(bits) \
782 SilcUInt##bits ret; \
784 silc_mutex_lock(atomic->lock); \
785 ret = atomic->value; \
786 atomic->value += value; \
787 silc_mutex_unlock(atomic->lock); \
788 return ret + value; \
790 #endif /* !SILC_THREADS */
792 SILC_ATOMIC_ADD_INT(8, "b");
793 SILC_ATOMIC_ADD_INT(16, "w");
794 SILC_ATOMIC_ADD_INT(32, "l");
796 /****f* silcutil/SilcAtomicAPI/silc_atomic_sub_int32
801 * SilcUInt32 silc_atomic_sub_int32(SilcAtomic32 *atomic, SilcInt32 value);
805 * Atomically subtracts `value' from 32-bit integer. Returns the value
810 /****f* silcutil/SilcAtomicAPI/silc_atomic_sub_int16
815 * SilcUInt16 silc_atomic_sub_int16(SilcAtomic16 *atomic, SilcInt16 value);
819 * Atomically subtracts `value' from 16-bit integer. Returns the value
824 /****f* silcutil/SilcAtomicAPI/silc_atomic_sub_int8
829 * SilcUInt8 silc_atomic_sub_int8(SilcAtomic8 *atomic, SilcInt8 value);
833 * Atomically subtracts `value' from 8-bit integer. Returns the value
838 #define silc_atomic_sub_int8(a, v) silc_atomic_add_int8(a, (-v))
839 #define silc_atomic_sub_int16(a, v) silc_atomic_add_int16(a, (-v))
840 #define silc_atomic_sub_int32(a, v) silc_atomic_add_int32(a, (-v))
842 /****f* silcutil/SilcAtomicAPI/silc_atomic_inc32
847 * void silc_atomic_inc32(SilcAtomic32 *atomic);
851 * Atomically increments 32-bit integer by one.
855 /****f* silcutil/SilcAtomicAPI/silc_atomic_inc16
860 * void silc_atomic_inc16(SilcAtomic16 *atomic);
864 * Atomically increments 16-bit integer by one.
868 /****f* silcutil/SilcAtomicAPI/silc_atomic_inc8
873 * void silc_atomic_inc8(SilcAtomic8 *atomic);
877 * Atomically increments 8-bit integer by one.
881 #define SILC_ATOMIC_INC_F(bits) \
882 static inline void silc_atomic_inc##bits(SilcAtomic##bits *atomic)
884 #if !defined(SILC_THREADS)
885 #define SILC_ATOMIC_INC(bits, bp) \
886 SILC_ATOMIC_INC_F(bits) \
888 /* No atomic operations */ \
892 #elif defined(SILC_WIN32)
893 #define SILC_ATOMIC_INC(bits, bp) \
894 SILC_ATOMIC_INC_F(bits) \
897 InterlockedIncrement((LONG)&atomic->value); \
900 #elif defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64))
901 #define SILC_ATOMIC_INC(bits, bp) \
902 SILC_ATOMIC_INC_F(bits) \
904 /* GCC + i486 or x86_64 */ \
905 __asm __volatile(SILC_SMP_LOCK "inc" bp " %0" \
906 : "+m" (atomic->value)); \
909 #elif defined(__GNUC__) && defined(SILC_IA64)
910 #define SILC_ATOMIC_INC(bits, bp) \
911 SILC_ATOMIC_INC_F(bits) \
913 /* GCC + IA64 (GCC builtin atomic operations) */ \
914 __sync_fetch_and_add(&atomic->value, 1); \
917 #elif defined(__GNUC__) && defined(SILC_POWERPC)
918 #define SILC_ATOMIC_INC(bits, bp) \
919 SILC_ATOMIC_INC_F(bits) \
923 /* GCC + PowerPC (code adapted from IBM's documentation) */ \
924 __asm __volatile("0: lwarx %0, 0, %2\n" \
925 " add %0, %1, %0\n" \
926 " stwcx. %0, 0, %2\n" \
929 : "r" (val), "r" (&atomic->value) \
933 #else /* SILC_ATOMIC_MUTEX */
934 #define SILC_ATOMIC_INC(bits, bp) \
935 SILC_ATOMIC_INC_F(bits) \
938 silc_mutex_lock(atomic->lock); \
940 silc_mutex_unlock(atomic->lock); \
942 #endif /* !SILC_THREADS */
944 SILC_ATOMIC_INC(8, "b");
945 SILC_ATOMIC_INC(16, "w");
946 SILC_ATOMIC_INC(32, "l");
948 /****f* silcutil/SilcAtomicAPI/silc_atomic_dec32
953 * void silc_atomic_dec32(SilcAtomic32 *atomic);
957 * Atomically decrements 32-bit integer by one.
961 /****f* silcutil/SilcAtomicAPI/silc_atomic_dec16
966 * void silc_atomic_dec16(SilcAtomic16 *atomic);
970 * Atomically decrements 16-bit integer by one.
974 /****f* silcutil/SilcAtomicAPI/silc_atomic_dec8
979 * void silc_atomic_dec8(SilcAtomic8 *atomic);
983 * Atomically decrements 8-bit integer by one.
987 #define SILC_ATOMIC_DEC_F(bits) \
988 static inline void silc_atomic_dec##bits(SilcAtomic##bits *atomic)
990 #if !defined(SILC_THREADS)
991 #define SILC_ATOMIC_DEC(bits, bp) \
992 SILC_ATOMIC_DEC_F(bits) \
994 /* No atomic operations */ \
998 #elif defined(SILC_WIN32)
999 #define SILC_ATOMIC_DEC(bits, bp) \
1000 SILC_ATOMIC_DEC_F(bits) \
1003 InterlockedDecrement((LONG)&atomic->value); \
1006 #elif defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64))
1007 #define SILC_ATOMIC_DEC(bits, bp) \
1008 SILC_ATOMIC_DEC_F(bits) \
1010 /* GCC + i486 or x86_64 */ \
1011 __asm __volatile(SILC_SMP_LOCK "dec" bp " %0" \
1012 : "+m" (atomic->value)); \
1015 #elif defined(__GNUC__) && defined(SILC_IA64)
1016 #define SILC_ATOMIC_DEC(bits, bp) \
1017 SILC_ATOMIC_DEC_F(bits) \
1019 /* GCC + IA64 (GCC builtin atomic operations) */ \
1020 __sync_fetch_and_sub(&atomic->value, 1); \
1023 #elif defined(__GNUC__) && defined(SILC_POWERPC)
1024 #define SILC_ATOMIC_DEC(bits, bp) \
1025 SILC_ATOMIC_DEC_F(bits) \
1028 SilcInt32 val = -1; \
1029 /* GCC + PowerPC (code adapted from IBM's documentation) */ \
1030 __asm __volatile("0: lwarx %0, 0, %2\n" \
1031 " add %0, %1, %0\n" \
1032 " stwcx. %0, 0, %2\n" \
1035 : "r" (val), "r" (&atomic->value) \
1039 #else /* SILC_ATOMIC_MUTEX */
1040 #define SILC_ATOMIC_DEC(bits, bp) \
1041 SILC_ATOMIC_DEC_F(bits) \
1044 silc_mutex_lock(atomic->lock); \
1046 silc_mutex_unlock(atomic->lock); \
1048 #endif /* !SILC_THREADS */
1050 SILC_ATOMIC_DEC(8, "b");
1051 SILC_ATOMIC_DEC(16, "w");
1052 SILC_ATOMIC_DEC(32, "l");
1054 /****f* silcutil/SilcAtomicAPI/silc_atomic_cas32
1059 * SilcBool silc_atomic_cas32(SilcAtomic32 *atomic, SilcUInt32 old_val,
1060 * SilcUInt32 new_val)
1064 * Performs compare and swap (CAS). Atomically compares if the variable
1065 * `atomic' has the value `old_val' and in that case swaps it with the
1066 * value `new_val'. Returns TRUE if the old value was same and it was
1067 * swapped and FALSE if it differed and was not swapped.
1071 /****f* silcutil/SilcAtomicAPI/silc_atomic_cas16
1076 * SilcBool silc_atomic_cas16(SilcAtomic16 *atomic, SilcUInt16 old_val,
1077 * SilcUInt16 new_val)
1081 * Performs compare and swap (CAS). Atomically compares if the variable
1082 * `atomic' has the value `old_val' and in that case swaps it with the
1083 * value `new_val'. Returns TRUE if the old value was same and it was
1084 * swapped and FALSE if it differed and was not swapped.
1088 /****f* silcutil/SilcAtomicAPI/silc_atomic_cas8
1093 * SilcBool silc_atomic_cas8(SilcAtomic8 *atomic, SilcUInt8 old_val,
1094 * SilcUInt8 new_val)
1098 * Performs compare and swap (CAS). Atomically compares if the variable
1099 * `atomic' has the value `old_val' and in that case swaps it with the
1100 * value `new_val'. Returns TRUE if the old value was same and it was
1101 * swapped and FALSE if it differed and was not swapped.
1105 #define SILC_ATOMIC_CAS_F(bits) \
1106 static inline SilcBool silc_atomic_cas##bits(SilcAtomic##bits *atomic, \
1107 SilcInt##bits old_val, \
1108 SilcInt##bits new_val)
1110 #if !defined(SILC_THREADS)
1111 #define SILC_ATOMIC_CAS(bits, bp) \
1112 SILC_ATOMIC_CAS_F(bits) \
1114 /* No atomic operations */ \
1115 if (atomic->value == (SilcUInt##bits)old_val) { \
1116 atomic->value = new_val; \
1122 #elif defined(SILC_WIN32)
1123 #define SILC_ATOMIC_CAS(bits, bp) \
1124 SILC_ATOMIC_CAS_F(bits) \
1127 LONG o = old_val, n = new_val; \
1128 return InterlockedCompareExchange(&atomic->value, n, o) == o; \
1131 #elif defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64))
1132 #define SILC_ATOMIC_CAS(bits, bp) \
1133 SILC_ATOMIC_CAS_F(bits) \
1135 /* GCC + i486 or x86_64 */ \
1136 SilcUInt##bits ret; \
1137 __asm __volatile(SILC_SMP_LOCK "cmpxchg" bp " %2, %1" \
1138 : "=a" (ret), "=m" (atomic->value) \
1139 : "r" (new_val), "m" (atomic->value), "0" (old_val)); \
1140 return ret == (SilcUInt##bits)old_val; \
1143 #elif defined(__GNUC__) && defined(SILC_IA64)
1144 #define SILC_ATOMIC_CAS(bits, bp) \
1145 SILC_ATOMIC_CAS_F(bits) \
1147 /* GCC + IA64 (GCC builtin atomic operations) */ \
1148 SilcUInt32 o = old_val, n = new_val; \
1149 return __sync_bool_compare_and_swap(&atomic->value, o, n); \
1152 #elif defined(__GNUC__) && defined(SILC_POWERPC)
1153 #define SILC_ATOMIC_CAS(bits, bp) \
1154 SILC_ATOMIC_CAS_F(bits) \
1156 /* GCC + PowerPC */ \
1160 #else /* SILC_ATOMIC_MUTEX */
1161 #define SILC_ATOMIC_CAS(bits, bp) \
1162 SILC_ATOMIC_CAS_F(bits) \
1165 silc_mutex_lock(atomic->lock); \
1166 if (atomic->value == (SilcUInt##bits)old_val) { \
1167 atomic->value = new_val; \
1168 silc_mutex_unlock(atomic->lock); \
1171 silc_mutex_unlock(atomic->lock); \
1174 #endif /* !SILC_THREADS */
1176 SILC_ATOMIC_CAS(8, "b");
1177 SILC_ATOMIC_CAS(16, "w");
1178 SILC_ATOMIC_CAS(32, "l");
1180 /****f* silcutil/SilcAtomicAPI/silc_atomic_cas_pointer
1185 * SilcBool silc_atomic_cas_pointer(SilcAtomicPointer *atomic,
1186 * void *old_ptr, void *new_ptr);
1190 * Performs compare and swap (CAS). Atomically compares if the variable
1191 * `atomic' has the pointer `old_ptr' and in that case swaps it with the
1192 * pointer `new_ptr'. Returns TRUE if the old pointer was same and it was
1193 * swapped and FALSE if it differed and was not swapped.
1198 SilcBool silc_atomic_cas_pointer(SilcAtomicPointer *atomic, void *old_val,
1201 #if !defined(SILC_THREADS)
1202 /* No atomic operations */
1203 if (atomic->value == old_val) {
1204 atomic->value = new_val;
1209 #elif defined(SILC_WIN32)
1211 return InterlockedCompareExchangePointer(&atomic->value, n, o) == o;
1213 #elif defined(__GNUC__) && defined(SILC_I486)
1216 __asm __volatile(SILC_SMP_LOCK "cmpxchgl %2, %1"
1217 : "=a" (ret), "=m" (atomic->value)
1218 : "c" (new_val), "m" (atomic->value), "0" (old_val));
1219 return ret == old_val;
1221 #elif defined(__GNUC__) && defined(SILC_X86_64)
1224 __asm __volatile(SILC_SMP_LOCK "cmpxchgq %q2, %1"
1225 : "=a" (ret), "=m" (atomic->value)
1226 : "c" (new_val), "m" (atomic->value), "0" (old_val));
1227 return ret == old_val;
1229 #elif defined(__GNUC__) && defined(SILC_IA64)
1230 /* GCC + IA64 (GCC builtin atomic operations) */
1231 return __sync_bool_compare_and_swap((long)&atomic->value, (long)old_val,
1234 #elif defined(__GNUC__) && defined(SILC_POWERPC)
1240 silc_mutex_lock(atomic->lock);
1241 if (atomic->value == old_val) {
1242 atomic->value = new_val;
1243 silc_mutex_unlock(atomic->lock);
1246 silc_mutex_unlock(atomic->lock);
1251 #endif /* SILCATOMIC_H */