8, 16 and 32-bit atomic integers, 32 and 64 bit atomic pointers.
[silc.git] / lib / silcutil / silcatomic.h
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
 }