8, 16 and 32-bit atomic integers, 32 and 64 bit atomic pointers.
authorPekka Riikonen <priikone@silcnet.org>
Sat, 11 Nov 2006 17:16:54 +0000 (17:16 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sat, 11 Nov 2006 17:16:54 +0000 (17:16 +0000)
lib/silcutil/silcatomic.h
lib/silcutil/tests/test_silcatomic.c

index 02a71ca9357d2a77ff0e6582b0b0aac7150b717c..b42e77a880cff32d674e36d651f778a8f4845bb2 100644 (file)
  * simple operations with integers atomically.  This enables fast integer
  * additions and subtractions safely in multithreaded environment.  It is
  * especially suited for reference counters and similar and is much faster
- * than using locking.
+ * than using locking.  This interface supports 8, 16 and 32 bit integers
+ * and 32 or 64 bit pointers.
  *
- * If threads were not enabled when compiling the source code, the operations
- * are not atomic.  On some platforms this interface actually use mutual
- * exclusion lock instead of true atomic operations, leading into some
- * performace penalty.
+ * On some platforms this interface actually use mutual exclusion lock
+ * instead of true atomic operations, leading into some performace penalty.
+ * Also on some platforms the 8 and 16 bit integers are actually 32 bit
+ * integers.
+ *
+ * Fast operations are supported on: x86, x86_64, ia64, PPC
  *
  ***/
 
 #ifndef SILCATOMIC_H
 #define SILCATOMIC_H
 
-/****s* silcutil/SilcAtomicAPI/SilcAtomic
+/****s* silcutil/SilcAtomicAPI/SilcAtomic32
+ *
+ * NAME
+ *
+ *    typedef struct { ... } SilcAtomic32;
+ *
+ * DESCRIPTION
+ *
+ *    The atomic operation structure given as argument to all atomic
+ *    operation functions.  It hols the actual 32-bit atomic variable.
+ *
+ * EXAMPLE
+ *
+ *    SilcAtomic32 refcnt;
+ *
+ *    // Initialize atomic variable
+ *    silc_atomic_init32(&refcnt, 0);
+ *
+ *    ...
+ *    // Increment referene counter
+ *    silc_atomic_add_int32(&refcnt, 1);
+ *    ...
+ *
+ *    // Uninitialize atomic variable
+ *    silc_atomic_uninit32(&refcnt);
+ *
+ ***/
+
+/****s* silcutil/SilcAtomicAPI/SilcAtomic16
+ *
+ * NAME
+ *
+ *    typedef struct { ... } SilcAtomic16;
+ *
+ * DESCRIPTION
+ *
+ *    The atomic operation structure given as argument to all atomic
+ *    operation functions.  It hols the actual 16-bit atomic variable.
+ *
+ * EXAMPLE
+ *
+ *    SilcAtomic16 refcnt;
+ *
+ *    // Initialize atomic variable
+ *    silc_atomic_init16(&refcnt, 0);
+ *
+ *    ...
+ *    // Increment referene counter
+ *    silc_atomic_add_int16(&refcnt, 1);
+ *    ...
+ *
+ *    // Uninitialize atomic variable
+ *    silc_atomic_uninit16(&refcnt);
+ *
+ ***/
+
+/****s* silcutil/SilcAtomicAPI/SilcAtomic8
  *
  * NAME
  *
- *    typedef struct { ... } SilcAtomic;
+ *    typedef struct { ... } SilcAtomic8;
  *
  * DESCRIPTION
  *
  *    The atomic operation structure given as argument to all atomic
- *    operation functions.  It hols the actual atomic variable.  On most
- *    platforms its size is 32 bits but on some platforms it may be
- *    larger.
+ *    operation functions.  It hols the actual 8-bit atomic variable.
  *
  * EXAMPLE
  *
- *    SilcAtomic refcnt;
+ *    SilcAtomic8 refcnt;
  *
  *    // Initialize atomic variable
- *    silc_atomic_init(&refcnt, 0);
+ *    silc_atomic_init8(&refcnt, 0);
  *
  *    ...
  *    // Increment referene counter
- *    silc_atomic_add_int(&refcnt, 1);
+ *    silc_atomic_add_int8(&refcnt, 1);
+ *    ...
+ *
+ *    // Uninitialize atomic variable
+ *    silc_atomic_uninit8(&refcnt);
+ *
+ ***/
+
+/****s* silcutil/SilcAtomicAPI/SilcAtomicPointer
+ *
+ * NAME
+ *
+ *    typedef struct { ... } SilcAtomicPointer;
+ *
+ * DESCRIPTION
+ *
+ *    The atomic operation structure given as argument to all atomic
+ *    operation functions.  It hols the actual pointer variable.
+ *
+ * EXAMPLE
+ *
+ *    SilcAtomicPointer ptr;
+ *
+ *    // Initialize atomic variable
+ *    silc_atomic_init_pointer(&ptr, NULL);
+ *
+ *    ...
+ *    // Set pointer
+ *    silc_atomic_set_pointer(&ptr, context);
  *    ...
  *
  *    // Uninitialize atomic variable
- *    silc_atomic_uninit(&refcnt);
+ *    silc_atomic_uninit_pointer(&ptr);
  *
  ***/
+
 #if !defined(SILC_THREADS) || defined(SILC_WIN32) || (defined(__GNUC__) &&  \
     (defined(SILC_I486) || defined(SILC_X86_64) || defined(SILC_IA64) ||    \
      defined(SILC_POWERPC)))
-typedef struct
-{
+typedef struct {
   volatile SilcUInt32 value;
-} SilcAtomic;
+} SilcAtomic32;
+typedef struct {
+  volatile void *pointer;
+} SilcAtomicPointer;
 #else
 #define SILC_ATOMIC_MUTEX
-typedef struct
-{
+typedef struct {
+  SilcMutex lock;
+  volatile SilcUInt32 value;
+} SilcAtomic32;
+typedef struct {
+  SilcMutex lock;
+  volatile void *pointer;
+} SilcAtomicPointer;
+#endif
+
+#if !defined(SILC_THREADS) || (defined(__GNUC__) && (defined(SILC_I486) ||  \
+                                                    defined(SILC_X86_64)))
+typedef struct {
+  volatile SilcUInt16 value;
+} SilcAtomic16;
+#elif defined(SILC_WIN32) || (defined(__GNUC__) && (defined(SILC_IA64) ||   \
+                                                   defined(SILC_POWERPC)))
+typedef struct {
+  volatile SilcUInt32 value;
+} SilcAtomic16;
+#else
+typedef struct {
+  SilcMutex lock;
+  volatile SilcUInt16 value;
+} SilcAtomic16;
+#endif
+
+#if !defined(SILC_THREADS) || (defined(__GNUC__) && (defined(SILC_I486) ||  \
+                                                    defined(SILC_X86_64)))
+typedef struct {
+  volatile SilcUInt8 value;
+} SilcAtomic8;
+#elif defined(SILC_WIN32) || (defined(__GNUC__) && (defined(SILC_IA64) ||   \
+                                                   defined(SILC_POWERPC)))
+typedef struct {
   volatile SilcUInt32 value;
+} SilcAtomic8;
+#else
+typedef struct {
   SilcMutex lock;
-} SilcAtomic;
+  volatile SilcUInt8 value;
+} SilcAtomic8;
 #endif
 
-/****f* silcutil/SilcAtomicAPI/silc_atomic_init
+/****f* silcutil/SilcAtomicAPI/silc_atomic_init32
  *
  * SYNOPSIS
  *
  *    static inline
- *    SilcBool silc_atomic_init(SilcAtomic *atomic, int value);
+ *    SilcBool silc_atomic_init32(SilcAtomic32 *atomic, SilcUInt32 value);
  *
  * DESCRIPTION
  *
  *    Initializes the atomic variable `atomic', and sets the `value' as its
  *    inital value.  Returns FALSE on error.  To uninitialize call the
- *    silc_atomic_uninit function.
+ *    silc_atomic_uninit32 function.
  *
  ***/
 
 static inline
-SilcBool silc_atomic_init(SilcAtomic *atomic, int value)
+SilcBool silc_atomic_init32(SilcAtomic32 *atomic, SilcUInt32 value)
 {
   atomic->value = value;
 
@@ -110,152 +235,1029 @@ SilcBool silc_atomic_init(SilcAtomic *atomic, int value)
   return TRUE;
 }
 
-/****f* silcutil/SilcAtomicAPI/silc_atomic_uninit
+/****f* silcutil/SilcAtomicAPI/silc_atomic_init16
  *
  * SYNOPSIS
  *
  *    static inline
- *    void silc_atomic_uninit(SilcAtomic *atomic);
+ *    SilcBool silc_atomic_init16(SilcAtomic16 *atomic, SilcUInt16 value);
  *
  * DESCRIPTION
  *
- *    Uninitializes the atomic variable `atomic'.  This should alwyas be
- *    called after the atomic variable is not used anymore.
+ *    Initializes the atomic variable `atomic', and sets the `value' as its
+ *    inital value.  Returns FALSE on error.  To uninitialize call the
+ *    silc_atomic_uninit32 function.
  *
  ***/
 
 static inline
-void silc_atomic_uninit(SilcAtomic *atomic)
+SilcBool silc_atomic_init16(SilcAtomic16 *atomic, SilcUInt16 value)
 {
-  atomic->value = 0;
+  atomic->value = value;
+
 #if defined(SILC_ATOMIC_MUTEX)
-  silc_mutex_free(atomic->lock);
+  if (!silc_mutex_alloc(&atomic->lock))
+    return FALSE;
 #endif /* SILC_ATOMIC_MUTEX */
+
+  return TRUE;
 }
 
-/****f* silcutil/SilcAtomicAPI/silc_atomic_add_int
+/****f* silcutil/SilcAtomicAPI/silc_atomic_init8
  *
  * SYNOPSIS
  *
  *    static inline
- *    SilcUInt32 silc_atomic_add_int(SilcAtomic *atomic, int value);
+ *    SilcBool silc_atomic_init8(SilcAtomic8 *atomic, SilcUInt8 value);
  *
  * DESCRIPTION
  *
- *    Atomically adds `value' to 32-bit integer.  Returns the value after
- *    addition.
+ *    Initializes the atomic variable `atomic', and sets the `value' as its
+ *    inital value.  Returns FALSE on error.  To uninitialize call the
+ *    silc_atomic_uninit8 function.
  *
  ***/
 
 static inline
-SilcUInt32 silc_atomic_add_int(SilcAtomic *atomic, int value)
+SilcBool silc_atomic_init8(SilcAtomic8 *atomic, SilcUInt8 value)
 {
-  SilcUInt32 ret;
+  atomic->value = value;
 
-#if !defined(SILC_THREADS)
-  /* No atomic operations */
-  ret = atomic->value;
-  atomic->value += value;
+#if defined(SILC_ATOMIC_MUTEX)
+  if (!silc_mutex_alloc(&atomic->lock))
+    return FALSE;
+#endif /* SILC_ATOMIC_MUTEX */
 
-#elif defined(SILC_WIN32)
-  /* Windows */
-  ret = InterlockedExchangeAdd(&atomic->value, (LONG)value);
+  return TRUE;
+}
 
-#elif defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64))
-  /* GCC + i486 or x86_64 */
-  __asm __volatile("lock; xaddl %0, %1"
-                  : "=r" (ret), "+m" (atomic->value)
-                  : "0" (value));
+/****f* silcutil/SilcAtomicAPI/silc_atomic_init_pointer
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    SilcBool silc_atomic_init_pointer(SilcAtomicPointer *atomic,
+ *                                      void *pointer);
+ *
+ * DESCRIPTION
+ *
+ *    Initializes the atomic pointer variable `atomic', and sets the `pointer'
+ *    as its inital pointer.  Returns FALSE on error.  To uninitialize call
+ *    the silc_atomic_uninit_pointer function.
+ *
+ ***/
 
-#elif defined(__GNUC__) && defined(SILC_IA64)
-  /* GCC + IA64 (GCC builtin atomic operations) */
-  ret = __sync_fetch_and_add(&atomic->value, value);
+static inline
+SilcBool silc_atomic_init_pointer(SilcAtomicPointer *atomic, void *pointer)
+{
+  atomic->pointer = pointer;
 
-#elif defined(__GNUC__) && defined(SILC_POWERPC)
-  /* GCC + PowerPC (code adapted from IBM's documentation) */
-  /* XXX Hmm.. should I sync and isync this?... */
-  __asm __volatile("0: lwarx  %0,  0, %2\n"
-                  "   add    %0, %1, %0\n"
-                  "   stwcx. %0,  0, %2\n"
-                  "   bne-   0b"
-                  : "=&r" (ret)
-                  : "r" (value), "r" (&atomic->value)
-                  : "cc");
-  return ret;
+#if defined(SILC_ATOMIC_MUTEX)
+  if (!silc_mutex_alloc(&atomic->lock))
+    return FALSE;
+#endif /* SILC_ATOMIC_MUTEX */
 
-#else
-  /* Mutex */
-  silc_mutex_lock(atomic->lock);
-  ret = atomic->value;
-  atomic->value += value;
-  silc_mutex_unlock(atomic->lock);
-#endif
+  return TRUE;
+}
 
-  return ret + value;
+/****f* silcutil/SilcAtomicAPI/silc_atomic_uninit32
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    void silc_atomic_uninit32(SilcAtomic32 *atomic);
+ *
+ * DESCRIPTION
+ *
+ *    Uninitializes the atomic variable `atomic'.  This should alwyas be
+ *    called after the atomic variable is not used anymore.
+ *
+ ***/
+
+static inline
+void silc_atomic_uninit32(SilcAtomic32 *atomic)
+{
+  atomic->value = 0;
+#if defined(SILC_ATOMIC_MUTEX)
+  silc_mutex_free(atomic->lock);
+#endif /* SILC_ATOMIC_MUTEX */
 }
 
-/****f* silcutil/SilcAtomicAPI/silc_atomic_sub_int
+/****f* silcutil/SilcAtomicAPI/silc_atomic_uninit16
  *
  * SYNOPSIS
  *
  *    static inline
- *    SilcUInt32 silc_atomic_sub_int(SilcAtomic *atomic, int value);
+ *    void silc_atomic_uninit16(SilcAtomic16 *atomic);
  *
  * DESCRIPTION
  *
- *    Atomically subtracts `value' from 32-bit integer.  Returns the value
- *    after subtraction.
+ *    Uninitializes the atomic variable `atomic'.  This should alwyas be
+ *    called after the atomic variable is not used anymore.
  *
  ***/
 
 static inline
-SilcUInt32 silc_atomic_sub_int(SilcAtomic *atomic, int value)
+void silc_atomic_uninit16(SilcAtomic16 *atomic)
 {
-  return silc_atomic_add_int(atomic, -value);
+  atomic->value = 0;
+#if defined(SILC_ATOMIC_MUTEX)
+  silc_mutex_free(atomic->lock);
+#endif /* SILC_ATOMIC_MUTEX */
 }
 
-/****f* silcutil/SilcAtomicAPI/silc_atomic_get_int
+/****f* silcutil/SilcAtomicAPI/silc_atomic_uninit8
  *
  * SYNOPSIS
  *
  *    static inline
- *    SilcUInt32 silc_atomic_get_int(SilcAtomic *atomic);
+ *    void silc_atomic_uninit8(SilcAtomic8 *atomic);
  *
  * DESCRIPTION
  *
- *    Returns the current value of the atomic variable.
+ *    Uninitializes the atomic variable `atomic'.  This should alwyas be
+ *    called after the atomic variable is not used anymore.
  *
  ***/
 
 static inline
-SilcUInt32 silc_atomic_get_int(SilcAtomic *atomic)
+void silc_atomic_uninit8(SilcAtomic8 *atomic)
 {
-  SilcUInt32 ret;
+  atomic->value = 0;
+#if defined(SILC_ATOMIC_MUTEX)
+  silc_mutex_free(atomic->lock);
+#endif /* SILC_ATOMIC_MUTEX */
+}
+
+/****f* silcutil/SilcAtomicAPI/silc_atomic_uninit_pointer
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    void silc_atomic_uninit_pointer(SilcAtomicPointer *atomic);
+ *
+ * DESCRIPTION
+ *
+ *    Uninitializes the atomic variable `atomic'.  This should alwyas be
+ *    called after the atomic variable is not used anymore.
+ *
+ ***/
+
+static inline
+void silc_atomic_uninit_pointer(SilcAtomicPointer *atomic)
+{
+  atomic->pointer = NULL;
+#if defined(SILC_ATOMIC_MUTEX)
+  silc_mutex_free(atomic->lock);
+#endif /* SILC_ATOMIC_MUTEX */
+}
+
+/****f* silcutil/SilcAtomicAPI/silc_atomic_set_int32
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    void silc_atomic_set_int32(SilcAtomic32 *atomic, SilcUInt32 value);
+ *
+ * DESCRIPTION
+ *
+ *    Atomically sets `value' to 32-bit integer.
+ *
+ ***/
 
+static inline
+void silc_atomic_set_int32(SilcAtomic32 *atomic, SilcUInt32 value)
+{
 #if !defined(SILC_THREADS) || defined(SILC_WIN32) ||                    \
      (defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64)))
   /* No threads, Windows, i486 or x86_64, no memory barrier needed */
-  ret = atomic->value;
-  return ret;
+  atomic->value = value;
 
 #elif defined(__GNUC__) && defined(SILC_IA64)
   /* IA64, memory barrier needed */
+  atomic->value = value;
   __sync_synchronize();
-  ret = atomic->value;
-  return ret;
 
 #elif defined(__GNUC__) && defined(SILC_POWERPC)
   /* PowerPC, memory barrier needed */
+  atomic->value = value;
   __asm("sync" : : : "memory");
-  ret = atomic->value;
-  return ret;
 
 #else
   /* Mutex */
   silc_mutex_lock(atomic->lock);
-  ret = atomic->value;
+  atomic->value = value;
   silc_mutex_unlock(atomic->lock);
-  return ret;
+#endif
+}
+
+/****f* silcutil/SilcAtomicAPI/silc_atomic_set_int16
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    void silc_atomic_set_int16(SilcAtomic16 *atomic, SilcUInt16 value);
+ *
+ * DESCRIPTION
+ *
+ *    Atomically sets `value' to 16-bit integer.
+ *
+ ***/
+
+static inline
+void silc_atomic_set_int16(SilcAtomic16 *atomic, SilcUInt16 value)
+{
+#if !defined(SILC_THREADS) || defined(SILC_WIN32) ||                    \
+     (defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64)))
+  /* No threads, Windows, i486 or x86_64, no memory barrier needed */
+  atomic->value = value;
+
+#elif defined(__GNUC__) && defined(SILC_IA64)
+  /* IA64, memory barrier needed */
+  atomic->value = value;
+  __sync_synchronize();
+
+#elif defined(__GNUC__) && defined(SILC_POWERPC)
+  /* PowerPC, memory barrier needed */
+  atomic->value = value;
+  __asm("sync" : : : "memory");
+
+#else
+  /* Mutex */
+  silc_mutex_lock(atomic->lock);
+  atomic->value = value;
+  silc_mutex_unlock(atomic->lock);
+#endif
+}
+
+/****f* silcutil/SilcAtomicAPI/silc_atomic_set_int8
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    void silc_atomic_set_int8(SilcAtomic8 *atomic, SilcUInt8 value);
+ *
+ * DESCRIPTION
+ *
+ *    Atomically sets `value' to 8-bit integer.
+ *
+ ***/
+
+static inline
+void silc_atomic_set_int8(SilcAtomic8 *atomic, SilcUInt8 value)
+{
+#if !defined(SILC_THREADS) || defined(SILC_WIN32) ||                    \
+     (defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64)))
+  /* No threads, Windows, i486 or x86_64, no memory barrier needed */
+  atomic->value = value;
+
+#elif defined(__GNUC__) && defined(SILC_IA64)
+  /* IA64, memory barrier needed */
+  atomic->value = value;
+  __sync_synchronize();
+
+#elif defined(__GNUC__) && defined(SILC_POWERPC)
+  /* PowerPC, memory barrier needed */
+  atomic->value = value;
+  __asm("sync" : : : "memory");
+
+#else
+  /* Mutex */
+  silc_mutex_lock(atomic->lock);
+  atomic->value = value;
+  silc_mutex_unlock(atomic->lock);
+#endif
+}
+
+/****f* silcutil/SilcAtomicAPI/silc_atomic_set_pointer
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    void silc_atomic_set_pointer(SilcAtomicPointer *atomic, void *pointer);
+ *
+ * DESCRIPTION
+ *
+ *    Atomically sets `pointer' to the atomic variable.
+ *
+ ***/
+
+static inline
+void silc_atomic_set_pointer(SilcAtomicPointer *atomic, void *pointer)
+{
+#if !defined(SILC_THREADS) || defined(SILC_WIN32) ||                    \
+     (defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64)))
+  /* No threads, Windows, i486 or x86_64, no memory barrier needed */
+  atomic->pointer = pointer;
+
+#elif defined(__GNUC__) && defined(SILC_IA64)
+  /* IA64, memory barrier needed */
+  atomic->pointer = pointer;
+  __sync_synchronize();
+
+#elif defined(__GNUC__) && defined(SILC_POWERPC)
+  /* PowerPC, memory barrier needed */
+  atomic->pointer = pointer;
+  __asm("sync" : : : "memory");
+
+#else
+  /* Mutex */
+  silc_mutex_lock(atomic->lock);
+  atomic->pointer = pointer;
+  silc_mutex_unlock(atomic->lock);
+#endif
+}
+
+/****f* silcutil/SilcAtomicAPI/silc_atomic_get_int32
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    SilcUInt32 silc_atomic_get_int32(SilcAtomic32 *atomic);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the current value of the atomic variable.
+ *
+ ***/
+
+static inline
+SilcUInt32 silc_atomic_get_int32(SilcAtomic32 *atomic)
+{
+  SilcUInt32 ret;
+
+#if !defined(SILC_THREADS) || defined(SILC_WIN32) ||                    \
+     (defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64)))
+  /* No threads, Windows, i486 or x86_64, no memory barrier needed */
+  ret = atomic->value;
+  return ret;
+
+#elif defined(__GNUC__) && defined(SILC_IA64)
+  /* IA64, memory barrier needed */
+  __sync_synchronize();
+  ret = atomic->value;
+  return ret;
+
+#elif defined(__GNUC__) && defined(SILC_POWERPC)
+  /* PowerPC, memory barrier needed */
+  __asm("sync" : : : "memory");
+  ret = atomic->value;
+  return ret;
+
+#else
+  /* Mutex */
+  silc_mutex_lock(atomic->lock);
+  ret = atomic->value;
+  silc_mutex_unlock(atomic->lock);
+  return ret;
+#endif
+}
+
+/****f* silcutil/SilcAtomicAPI/silc_atomic_get_int16
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    SilcUInt32 silc_atomic_get_int16(SilcAtomic16 *atomic);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the current value of the atomic variable.
+ *
+ ***/
+
+static inline
+SilcUInt16 silc_atomic_get_int16(SilcAtomic16 *atomic)
+{
+  SilcUInt16 ret;
+
+#if !defined(SILC_THREADS) || defined(SILC_WIN32) ||                    \
+     (defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64)))
+  /* No threads, Windows, i486 or x86_64, no memory barrier needed */
+  ret = atomic->value & 0xffff;
+  return ret;
+
+#elif defined(__GNUC__) && defined(SILC_IA64)
+  /* IA64, memory barrier needed */
+  __sync_synchronize();
+  ret = atomic->value & 0xffff;
+  return ret;
+
+#elif defined(__GNUC__) && defined(SILC_POWERPC)
+  /* PowerPC, memory barrier needed */
+  __asm("sync" : : : "memory");
+  ret = atomic->value & 0xffff;
+  return ret;
+
+#else
+  /* Mutex */
+  silc_mutex_lock(atomic->lock);
+  ret = atomic->value & 0xffff;
+  silc_mutex_unlock(atomic->lock);
+  return ret;
+#endif
+}
+
+/****f* silcutil/SilcAtomicAPI/silc_atomic_get_int8
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    SilcUInt32 silc_atomic_get_int8(SilcAtomic8 *atomic);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the current value of the atomic variable.
+ *
+ ***/
+
+static inline
+SilcUInt8 silc_atomic_get_int8(SilcAtomic8 *atomic)
+{
+  SilcUInt8 ret;
+
+#if !defined(SILC_THREADS) || defined(SILC_WIN32) ||                    \
+     (defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64)))
+  /* No threads, Windows, i486 or x86_64, no memory barrier needed */
+  ret = atomic->value & 0xff;
+  return ret;
+
+#elif defined(__GNUC__) && defined(SILC_IA64)
+  /* IA64, memory barrier needed */
+  __sync_synchronize();
+  ret = atomic->value & 0xff;
+  return ret;
+
+#elif defined(__GNUC__) && defined(SILC_POWERPC)
+  /* PowerPC, memory barrier needed */
+  __asm("sync" : : : "memory");
+  ret = atomic->value & 0xff;
+  return ret;
+
+#else
+  /* Mutex */
+  silc_mutex_lock(atomic->lock);
+  ret = atomic->value & 0xff;
+  silc_mutex_unlock(atomic->lock);
+  return ret;
+#endif
+}
+
+/****f* silcutil/SilcAtomicAPI/silc_atomic_get_pointer
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    SilcUInt8 silc_atomic_get_pointer(SilcAtomicPointer *atomic)
+ *
+ * DESCRIPTION
+ *
+ *    Returns the current pointer value of the atomic variable.
+ *
+ ***/
+
+static inline
+void *silc_atomic_get_pointer(SilcAtomicPointer *atomic)
+{
+  void *ret;
+
+#if !defined(SILC_THREADS) || defined(SILC_WIN32) ||                    \
+     (defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64)))
+  /* No threads, Windows, i486 or x86_64, no memory barrier needed */
+  ret = (void *)atomic->pointer;
+  return ret;
+
+#elif defined(__GNUC__) && defined(SILC_IA64)
+  /* IA64, memory barrier needed */
+  __sync_synchronize();
+  ret = (void *)atomic->pointer;
+  return ret;
+
+#elif defined(__GNUC__) && defined(SILC_POWERPC)
+  /* PowerPC, memory barrier needed */
+  __asm("sync" : : : "memory");
+  ret = (void *)atomic->pointer;
+  return ret;
+
+#else
+  /* Mutex */
+  silc_mutex_lock(atomic->lock);
+  ret = (void *)atomic->pointer;
+  silc_mutex_unlock(atomic->lock);
+  return ret;
+#endif
+}
+
+/****f* silcutil/SilcAtomicAPI/silc_atomic_add_int32
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    SilcUInt32 silc_atomic_add_int32(SilcAtomic32 *atomic, SilcInt32 value);
+ *
+ * DESCRIPTION
+ *
+ *    Atomically adds `value' to 32-bit integer.  Returns the value after
+ *    addition.
+ *
+ ***/
+
+static inline
+SilcUInt32 silc_atomic_add_int32(SilcAtomic32 *atomic, SilcInt32 value)
+{
+  SilcUInt32 ret;
+
+#if !defined(SILC_THREADS)
+  /* No atomic operations */
+  ret = atomic->value;
+  atomic->value += value;
+
+#elif defined(SILC_WIN32)
+  /* Windows */
+  ret = InterlockedExchangeAdd(&atomic->value, (LONG)value);
+
+#elif defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64))
+  /* GCC + i486 or x86_64 */
+  __asm __volatile("lock; xaddl %0, %1"
+                  : "=r" (ret), "+m" (atomic->value)
+                  : "0" (value));
+
+#elif defined(__GNUC__) && defined(SILC_IA64)
+  /* GCC + IA64 (GCC builtin atomic operations) */
+  ret = __sync_fetch_and_add(&atomic->value, value);
+
+#elif defined(__GNUC__) && defined(SILC_POWERPC)
+  /* GCC + PowerPC (code adapted from IBM's documentation) */
+  __asm __volatile("0: lwarx  %0,  0, %2\n"
+                  "   add    %0, %1, %0\n"
+                  "   stwcx. %0,  0, %2\n"
+                  "   bne-   0b"
+                  : "=&r" (ret)
+                  : "r" (value), "r" (&atomic->value)
+                  : "cc");
+  return ret;
+
+#else
+  /* Mutex */
+  silc_mutex_lock(atomic->lock);
+  ret = atomic->value;
+  atomic->value += value;
+  silc_mutex_unlock(atomic->lock);
+#endif
+
+  return ret + value;
+}
+
+/****f* silcutil/SilcAtomicAPI/silc_atomic_add_int32
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    SilcUInt16 silc_atomic_add_int16(SilcAtomic16 *atomic, SilcInt16 value);
+ *
+ * DESCRIPTION
+ *
+ *    Atomically adds `value' to 16-bit integer.  Returns the value after
+ *    addition.
+ *
+ ***/
+
+static inline
+SilcUInt16 silc_atomic_add_int16(SilcAtomic16 *atomic, SilcInt16 value)
+{
+  SilcUInt16 ret;
+
+#if !defined(SILC_THREADS)
+  /* No atomic operations */
+  ret = atomic->value;
+  atomic->value += value;
+
+#elif defined(SILC_WIN32)
+  /* Windows */
+  LONG v = value;
+  ret = InterlockedExchangeAdd(&atomic->value, v);
+
+#elif defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64))
+  /* GCC + i486 or x86_64 */
+  __asm __volatile("lock; xaddw %0, %1"
+                  : "=c" (ret), "+m" (atomic->value)
+                  : "0" (value));
+
+#elif defined(__GNUC__) && defined(SILC_IA64)
+  /* GCC + IA64 (GCC builtin atomic operations) */
+  SilcInt32 v = value;
+  ret = __sync_fetch_and_add(&atomic->value, v);
+
+#elif defined(__GNUC__) && defined(SILC_POWERPC)
+  /* GCC + PowerPC (code adapted from IBM's documentation) */
+  SilcUInt32 ret32;
+  SilcInt32 v = value;
+  __asm __volatile("0: lwarx  %0,  0, %2\n"
+                  "   add    %0, %1, %0\n"
+                  "   stwcx. %0,  0, %2\n"
+                  "   bne-   0b"
+                  : "=&r" (ret32)
+                  : "r" (v), "r" (&atomic->value)
+                  : "cc");
+  return ret32 & 0xffff;
+
+#else
+  /* Mutex */
+  silc_mutex_lock(atomic->lock);
+  ret = atomic->value;
+  atomic->value += value;
+  silc_mutex_unlock(atomic->lock);
+#endif
+
+  return ret + value;
+}
+
+/****f* silcutil/SilcAtomicAPI/silc_atomic_add_int8
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    SilcUInt8 silc_atomic_add_int8(SilcAtomic8 *atomic, SilcInt8 value);
+ *
+ * DESCRIPTION
+ *
+ *    Atomically adds `value' to 8-bit integer.  Returns the value after
+ *    addition.
+ *
+ ***/
+
+static inline
+SilcUInt8 silc_atomic_add_int8(SilcAtomic8 *atomic, SilcInt8 value)
+{
+  SilcUInt8 ret;
+
+#if !defined(SILC_THREADS)
+  /* No atomic operations */
+  ret = atomic->value;
+  atomic->value += value;
+
+#elif defined(SILC_WIN32)
+  /* Windows */
+  LONG v = value;
+  ret = InterlockedExchangeAdd(&atomic->value, v);
+
+#elif defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64))
+  /* GCC + i486 or x86_64 */
+  __asm __volatile("lock; xaddb %0, %1"
+                  : "=c" (ret), "+m" (atomic->value)
+                  : "0" (value));
+
+#elif defined(__GNUC__) && defined(SILC_IA64)
+  /* GCC + IA64 (GCC builtin atomic operations) */
+  SilcInt32 v = value;
+  ret = __sync_fetch_and_add(&atomic->value, v);
+
+#elif defined(__GNUC__) && defined(SILC_POWERPC)
+  /* GCC + PowerPC (code adapted from IBM's documentation) */
+  SilcUInt32 ret32;
+  SilcInt32 v = value;
+  __asm __volatile("0: lwarx  %0,  0, %2\n"
+                  "   add    %0, %1, %0\n"
+                  "   stwcx. %0,  0, %2\n"
+                  "   bne-   0b"
+                  : "=&r" (ret32)
+                  : "r" (v), "r" (&atomic->value)
+                  : "cc");
+  return ret32 & 0xff;
+
+#else
+  /* Mutex */
+  silc_mutex_lock(atomic->lock);
+  ret = atomic->value;
+  atomic->value += value;
+  silc_mutex_unlock(atomic->lock);
+#endif
+
+  return ret + value;
+}
+
+/****f* silcutil/SilcAtomicAPI/silc_atomic_sub_int32
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    SilcUInt32 silc_atomic_sub_int32(SilcAtomic32 *atomic, SilcInt32 value);
+ *
+ * DESCRIPTION
+ *
+ *    Atomically subtracts `value' from 32-bit integer.  Returns the value
+ *    after subtraction.
+ *
+ ***/
+
+static inline
+SilcUInt32 silc_atomic_sub_int32(SilcAtomic32 *atomic, SilcInt32 value)
+{
+  return silc_atomic_add_int32(atomic, -value);
+}
+
+/****f* silcutil/SilcAtomicAPI/silc_atomic_sub_int16
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    SilcUInt16 silc_atomic_sub_int16(SilcAtomic16 *atomic, SilcInt16 value);
+ *
+ * DESCRIPTION
+ *
+ *    Atomically subtracts `value' from 16-bit integer.  Returns the value
+ *    after subtraction.
+ *
+ ***/
+
+static inline
+SilcUInt16 silc_atomic_sub_int16(SilcAtomic16 *atomic, SilcInt16 value)
+{
+  return silc_atomic_add_int16(atomic, -value);
+}
+
+/****f* silcutil/SilcAtomicAPI/silc_atomic_sub_int8
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    SilcUInt8 silc_atomic_sub_int8(SilcAtomic8 *atomic, SilcInt8 value);
+ *
+ * DESCRIPTION
+ *
+ *    Atomically subtracts `value' from 8-bit integer.  Returns the value
+ *    after subtraction.
+ *
+ ***/
+
+static inline
+SilcUInt8 silc_atomic_sub_int8(SilcAtomic8 *atomic, SilcInt8 value)
+{
+  return silc_atomic_add_int8(atomic, -value);
+}
+
+/****f* silcutil/SilcAtomicAPI/silc_atomic_cas32
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    SilcBool silc_atomic_cas32(SilcAtomic32 *atomic, SilcUInt32 old_val,
+ *                               SilcUInt32 new_val)
+ *
+ * DESCRIPTION
+ *
+ *    Performs compare and swap (CAS).  Atomically compares if the variable
+ *    `atomic' has the value `old_val' and in that case swaps it with the
+ *    value `new_val'.  Returns TRUE if the old value was same and it was
+ *    swapped and FALSE if it differed and was not swapped.
+ *
+ ***/
+
+static inline
+SilcBool silc_atomic_cas32(SilcAtomic32 *atomic, SilcUInt32 old_val,
+                          SilcUInt32 new_val)
+{
+  SilcUInt32 ret;
+
+#if !defined(SILC_THREADS)
+  /* No atomic operations */
+  if (atomic->value == old_val) {
+    atomic->value = new_val;
+    return TRUE;
+  }
+  return FALSE;
+
+#elif defined(SILC_WIN32)
+  /* Windows */
+  return InterlockedCompareExchange(&atomic->value, (LONG)new_val,
+                                   (LONG)old_val) == old_val;
+
+#elif defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64))
+  /* GCC + i486 or x86_64 */
+  __asm __volatile("lock; cmpxchgl %2, %1"
+                  : "=a" (ret), "=m" (atomic->value)
+                  : "r" (new_val), "m" (atomic->value), "0" (old_val));
+  return ret == old_val;
+
+#elif defined(__GNUC__) && defined(SILC_IA64)
+  /* GCC + IA64 (GCC builtin atomic operations) */
+  return  __sync_bool_compare_and_swap(&atomic->value, old_val, new_val);
+
+#elif defined(__GNUC__) && defined(SILC_POWERPC)
+  /* GCC + PowerPC */
+  /* XXX TODO */
+
+#else
+  /* Mutex */
+  silc_mutex_lock(atomic->lock);
+  if (atomic->value == old_val) {
+    atomic->value = new_val;
+    silc_mutex_unlock(atomic->lock);
+    return TRUE;
+  }
+  silc_mutex_unlock(atomic->lock);
+  return FALSE;
+#endif
+}
+
+/****f* silcutil/SilcAtomicAPI/silc_atomic_cas16
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    SilcBool silc_atomic_cas16(SilcAtomic16 *atomic, SilcUInt16 old_val,
+ *                               SilcUInt16 new_val)
+ *
+ * DESCRIPTION
+ *
+ *    Performs compare and swap (CAS).  Atomically compares if the variable
+ *    `atomic' has the value `old_val' and in that case swaps it with the
+ *    value `new_val'.  Returns TRUE if the old value was same and it was
+ *    swapped and FALSE if it differed and was not swapped.
+ *
+ ***/
+
+static inline
+SilcBool silc_atomic_cas16(SilcAtomic16 *atomic, SilcUInt16 old_val,
+                          SilcUInt16 new_val)
+{
+  SilcUInt16 ret;
+
+#if !defined(SILC_THREADS)
+  /* No atomic operations */
+  if (atomic->value == old_val) {
+    atomic->value = new_val;
+    return TRUE;
+  }
+  return FALSE;
+
+#elif defined(SILC_WIN32)
+  /* Windows */
+  LONG o = old_val, n = new_val;
+  return InterlockedCompareExchange(&atomic->value, n, o) == o;
+
+#elif defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64))
+  /* GCC + i486 or x86_64 */
+  __asm __volatile("lock; cmpxchgw %2, %1"
+                  : "=a" (ret), "=m" (atomic->value)
+                  : "c" (new_val), "m" (atomic->value), "0" (old_val));
+  return ret == old_val;
+
+#elif defined(__GNUC__) && defined(SILC_IA64)
+  /* GCC + IA64 (GCC builtin atomic operations) */
+  SilcUInt32 o = old_val, n = new_val;
+  return  __sync_bool_compare_and_swap(&atomic->value, o, n);
+
+#elif defined(__GNUC__) && defined(SILC_POWERPC)
+  /* GCC + PowerPC */
+  /* XXX TODO */
+
+#else
+  /* Mutex */
+  silc_mutex_lock(atomic->lock);
+  if (atomic->value == old_val) {
+    atomic->value = new_val;
+    silc_mutex_unlock(atomic->lock);
+    return TRUE;
+  }
+  silc_mutex_unlock(atomic->lock);
+  return FALSE;
+#endif
+}
+
+/****f* silcutil/SilcAtomicAPI/silc_atomic_cas8
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    SilcBool silc_atomic_cas8(SilcAtomic8 *atomic, SilcUInt8 old_val,
+ *                              SilcUInt8 new_val)
+ *
+ * DESCRIPTION
+ *
+ *    Performs compare and swap (CAS).  Atomically compares if the variable
+ *    `atomic' has the value `old_val' and in that case swaps it with the
+ *    value `new_val'.  Returns TRUE if the old value was same and it was
+ *    swapped and FALSE if it differed and was not swapped.
+ *
+ ***/
+
+static inline
+SilcBool silc_atomic_cas8(SilcAtomic8 *atomic, SilcUInt8 old_val,
+                         SilcUInt8 new_val)
+{
+  SilcUInt8 ret;
+
+#if !defined(SILC_THREADS)
+  /* No atomic operations */
+  if (atomic->value == old_val) {
+    atomic->value = new_val;
+    return TRUE;
+  }
+  return FALSE;
+
+#elif defined(SILC_WIN32)
+  /* Windows */
+  LONG o = old_val, n = new_val;
+  return InterlockedCompareExchange(&atomic->value, n, o) == o;
+
+#elif defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64))
+  /* GCC + i486 or x86_64 */
+  __asm __volatile("lock; cmpxchgb %2, %1"
+                  : "=a" (ret), "=m" (atomic->value)
+                  : "c" (new_val), "m" (atomic->value), "0" (old_val));
+  return ret == old_val;
+
+#elif defined(__GNUC__) && defined(SILC_IA64)
+  /* GCC + IA64 (GCC builtin atomic operations) */
+  SilcUInt32 o = old_val, n = new_val;
+  return  __sync_bool_compare_and_swap(&atomic->value, o, n);
+
+#elif defined(__GNUC__) && defined(SILC_POWERPC)
+  /* GCC + PowerPC */
+  /* XXX TODO */
+
+#else
+  /* Mutex */
+  silc_mutex_lock(atomic->lock);
+  if (atomic->value == old_val) {
+    atomic->value = new_val;
+    silc_mutex_unlock(atomic->lock);
+    return TRUE;
+  }
+  silc_mutex_unlock(atomic->lock);
+  return FALSE;
+#endif
+}
+
+/****f* silcutil/SilcAtomicAPI/silc_atomic_cas_pointer
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    SilcBool silc_atomic_cas_pointer(SilcAtomicPointer *atomic,
+ *                                     void *old_ptr, void *new_ptr);
+ *
+ * DESCRIPTION
+ *
+ *    Performs compare and swap (CAS).  Atomically compares if the variable
+ *    `atomic' has the pointer `old_ptr' and in that case swaps it with the
+ *    pointer `new_ptr'.  Returns TRUE if the old pointer was same and it was
+ *    swapped and FALSE if it differed and was not swapped.
+ *
+ ***/
+
+static inline
+SilcBool silc_atomic_cas_pointer(SilcAtomicPointer *atomic, void *old_val,
+                                void *new_val)
+{
+  void *ret;
+
+#if !defined(SILC_THREADS)
+  /* No atomic operations */
+  if (atomic->pointer == old_val) {
+    atomic->pointer = new_val;
+    return TRUE;
+  }
+  return FALSE;
+
+#elif defined(SILC_WIN32)
+  /* Windows */
+  return InterlockedCompareExchangePointer(&atomic->pointer, n, o) == o;
+
+#elif defined(__GNUC__) && defined(SILC_I486)
+  /* GCC + i486 */
+  __asm __volatile("lock; cmpxchgl %2, %1"
+                  : "=a" (ret), "=m" (atomic->pointer)
+                  : "c" (new_val), "m" (atomic->pointer), "0" (old_val));
+  return ret == old_val;
+
+#elif defined(__GNUC__) && defined(SILC_X86_64)
+  /* GCC + x86_64 */
+  __asm __volatile("lock; cmpxchgq %q2, %1"
+                  : "=a" (ret), "=m" (atomic->pointer)
+                  : "c" (new_val), "m" (atomic->pointer), "0" (old_val));
+  return ret == old_val;
+
+#elif defined(__GNUC__) && defined(SILC_IA64)
+  /* GCC + IA64 (GCC builtin atomic operations) */
+  return  __sync_bool_compare_and_swap((long)&atomic->pointer, (long)old_val,
+                                      (long)new_val);
+
+#elif defined(__GNUC__) && defined(SILC_POWERPC)
+  /* GCC + PowerPC */
+  /* XXX TODO */
+
+#else
+  /* Mutex */
+  silc_mutex_lock(atomic->lock);
+  if (atomic->pointer == old_val) {
+    atomic->pointer = new_val;
+    silc_mutex_unlock(atomic->lock);
+    return TRUE;
+  }
+  silc_mutex_unlock(atomic->lock);
+  return FALSE;
 #endif
 }
 
index feaf2895ee2d8fb586b44aa689f0f13733c9234a..89405a4dbf61a8a09a7fd178bda574acd54cf783 100644 (file)
@@ -6,7 +6,10 @@
 int main(int argc, char **argv)
 {
   SilcBool success = FALSE;
-  SilcAtomic ref;
+  SilcAtomic32 ref32;
+  SilcAtomic16 ref16;
+  SilcAtomic8 ref8;
+  SilcAtomicPointer refptr;
   SilcUInt8 ret8;
   SilcUInt16 ret16;
   SilcUInt32 ret32;
@@ -17,34 +20,77 @@ int main(int argc, char **argv)
     silc_log_set_debug_string("*atomic*");
   }
 
-  silc_atomic_init(&ref, 1);
+  silc_atomic_init8(&ref8, 1);
+  silc_atomic_init16(&ref16, 1);
+  silc_atomic_init32(&ref32, 1);
+  silc_atomic_init_pointer(&refptr, SILC_32_TO_PTR(0xdeadbeef));
 
-  ret8 = silc_atomic_add_int(&ref, 7);
+  ret8 = silc_atomic_add_int8(&ref8, 7);
   SILC_LOG_DEBUG(("ref8: 1 + 7 = %d (8)", ret8));
-  ret8 = silc_atomic_add_int(&ref, 3);
+  ret8 = silc_atomic_add_int8(&ref8, 3);
   SILC_LOG_DEBUG(("ref8: 8 + 3 = %d (11)", ret8));
-  ret8 = silc_atomic_sub_int(&ref, 10);
+  ret8 = silc_atomic_sub_int8(&ref8, 10);
   SILC_LOG_DEBUG(("ref8: 11 - 10 = %d (1)", ret8));
 
-  ret16 = silc_atomic_add_int(&ref, 1);
+  ret16 = silc_atomic_add_int16(&ref16, 1);
   SILC_LOG_DEBUG(("ref16: 1 + 1 = %d (2)", ret16));
-  ret16 = silc_atomic_add_int(&ref, 31020);
+  ret16 = silc_atomic_add_int16(&ref16, 31020);
   SILC_LOG_DEBUG(("ref16: 2 + 31020 = %d (31022)", ret16));
-  ret16 = silc_atomic_add_int(&ref, 34000);
+  ret16 = silc_atomic_add_int16(&ref16, 34000);
   SILC_LOG_DEBUG(("ref16: 31022 + 34000 = %d (65022)", ret16));
-  ret16 = silc_atomic_sub_int(&ref, 0);
+  ret16 = silc_atomic_sub_int16(&ref16, 0);
   SILC_LOG_DEBUG(("ref16: 65022 - 0 = %d (65022)", ret16));
-  ret16 = silc_atomic_sub_int(&ref, 0xffff);
-  SILC_LOG_DEBUG(("ref16: 65022 - 0xffff = %d (65023) (underflow)", ret16));
+  ret16 = silc_atomic_sub_int16(&ref16, 0xffff);
+  SILC_LOG_DEBUG(("ref16: 65022 - 0xfff = %d (65023) (underflow)", ret16));
 
-  SILC_LOG_DEBUG(("Current value: %d (-513)", silc_atomic_get_int(&ref)));
+  SILC_LOG_DEBUG(("Current value: %d (-513)",
+                 (SilcInt16)silc_atomic_get_int16(&ref16)));
 
-  SILC_LOG_DEBUG(("Swapping -513 with 8739200"));
-  if (!silc_atomic_cas(&ref, silc_atomic_get_int(&ref), 8739200))
+  SILC_LOG_DEBUG(("Swapping -513 with 57392"));
+  if (!silc_atomic_cas16(&ref16, silc_atomic_get_int16(&ref16), 57392))
     goto err;
-  SILC_LOG_DEBUG(("Current value: %d (8739200)", silc_atomic_get_int(&ref)));
+  SILC_LOG_DEBUG(("Current value: %d (57392)",
+                 silc_atomic_get_int16(&ref16)));
+  SILC_LOG_DEBUG(("Swapping 57392 with -500"));
+  if (!silc_atomic_cas16(&ref16, silc_atomic_get_int16(&ref16), -500))
+    goto err;
+  SILC_LOG_DEBUG(("Current value: %d (-500)",
+                 (SilcInt16)silc_atomic_get_int16(&ref16)));
+
+  ret32 = silc_atomic_add_int32(&ref32, 1);
+  SILC_LOG_DEBUG(("ref32: 1 + 1 = %d (2)", ret32));
+  ret32 = silc_atomic_add_int32(&ref32, 310200);
+  SILC_LOG_DEBUG(("ref32: 2 + 310200 = %d (310202)", ret32));
+  ret32 = silc_atomic_add_int32(&ref32, 34000000);
+  SILC_LOG_DEBUG(("ref32: 310202 + 34000000 = %d (34310202)", ret32));
+  ret32 = silc_atomic_sub_int32(&ref32, 0);
+  SILC_LOG_DEBUG(("ref32: 34310202 - 0 = %d (34310202)", ret32));
+  ret32 = silc_atomic_sub_int32(&ref32, 0xfffffff);
+  SILC_LOG_DEBUG(("ref32: 34310202 - 0xfffffff = %d (-234125253) "
+                 "(underflow)", ret32));
+
+  SILC_LOG_DEBUG(("Current value: %d (-234125253)",
+                 silc_atomic_get_int32(&ref32)));
+
+  SILC_LOG_DEBUG(("Swapping -234125253 with 76327681"));
+  if (!silc_atomic_cas32(&ref32, silc_atomic_get_int32(&ref32), 76327681))
+    goto err;
+  SILC_LOG_DEBUG(("Current value: %d (76327681)",
+                 silc_atomic_get_int32(&ref32)));
+
+  SILC_LOG_DEBUG(("Current ptr: %p (0xdeadbeef)",
+                 silc_atomic_get_pointer(&refptr)));
+  SILC_LOG_DEBUG(("Swapping %p with NULL", silc_atomic_get_pointer(&refptr)));
+  if (!silc_atomic_cas_pointer(&refptr,
+                              silc_atomic_get_pointer(&refptr), NULL))
+    goto err;
+  SILC_LOG_DEBUG(("Current ptr: %p (NULL)",
+                 silc_atomic_get_pointer(&refptr)));
 
-  silc_atomic_uninit(&ref);
+  silc_atomic_uninit8(&ref8);
+  silc_atomic_uninit16(&ref16);
+  silc_atomic_uninit32(&ref32);
+  silc_atomic_uninit_pointer(&refptr);
 
   success = TRUE;