Reorganized silcatomi.h.
authorPekka Riikonen <priikone@silcnet.org>
Sun, 11 Feb 2007 18:07:03 +0000 (18:07 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sun, 11 Feb 2007 18:07:03 +0000 (18:07 +0000)
Added silc_atomic_[inc|dec][8|16|32].

lib/silcutil/silcatomic.h
lib/silcutil/tests/Makefile.am
lib/silcutil/tests/test_silcatomic.c
lib/silcutil/tests/test_silcmutex.c [new file with mode: 0644]

index 65d8b99d142afd4c6c49c5af3d2233f2f83388e2..e2719b4c62a537d59310f8613790ea46a78217fb 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2006 Pekka Riikonen
+  Copyright (C) 2006 - 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
 #ifndef SILCATOMIC_H
 #define SILCATOMIC_H
 
+/* For now we always assume SMP */
+#define SILC_SMP 1
+
+/* Use lock prefix only on true SMP systems */
+#ifdef SILC_SMP
+#define SILC_SMP_LOCK "lock; "
+#else
+#define SILC_SMP_LOCK
+#endif /* SILC_SMP */
+
 /****s* silcutil/SilcAtomicAPI/SilcAtomic32
  *
  * NAME
@@ -159,7 +169,7 @@ typedef struct {
   volatile SilcUInt32 value;
 } SilcAtomic32;
 typedef struct {
-  volatile void *pointer;
+  volatile void *value;
 } SilcAtomicPointer;
 #else
 #define SILC_ATOMIC_MUTEX
@@ -169,7 +179,7 @@ typedef struct {
 } SilcAtomic32;
 typedef struct {
   SilcMutex lock;
-  volatile void *pointer;
+  volatile void *value;
 } SilcAtomicPointer;
 #endif
 
@@ -222,19 +232,6 @@ typedef struct {
  *
  ***/
 
-static inline
-SilcBool silc_atomic_init32(SilcAtomic32 *atomic, SilcUInt32 value)
-{
-  atomic->value = value;
-
-#if defined(SILC_ATOMIC_MUTEX)
-  if (!silc_mutex_alloc(&atomic->lock))
-    return FALSE;
-#endif /* SILC_ATOMIC_MUTEX */
-
-  return TRUE;
-}
-
 /****f* silcutil/SilcAtomicAPI/silc_atomic_init16
  *
  * SYNOPSIS
@@ -250,19 +247,6 @@ SilcBool silc_atomic_init32(SilcAtomic32 *atomic, SilcUInt32 value)
  *
  ***/
 
-static inline
-SilcBool silc_atomic_init16(SilcAtomic16 *atomic, SilcUInt16 value)
-{
-  atomic->value = value;
-
-#if defined(SILC_ATOMIC_MUTEX)
-  if (!silc_mutex_alloc(&atomic->lock))
-    return FALSE;
-#endif /* SILC_ATOMIC_MUTEX */
-
-  return TRUE;
-}
-
 /****f* silcutil/SilcAtomicAPI/silc_atomic_init8
  *
  * SYNOPSIS
@@ -278,19 +262,6 @@ SilcBool silc_atomic_init16(SilcAtomic16 *atomic, SilcUInt16 value)
  *
  ***/
 
-static inline
-SilcBool silc_atomic_init8(SilcAtomic8 *atomic, SilcUInt8 value)
-{
-  atomic->value = value;
-
-#if defined(SILC_ATOMIC_MUTEX)
-  if (!silc_mutex_alloc(&atomic->lock))
-    return FALSE;
-#endif /* SILC_ATOMIC_MUTEX */
-
-  return TRUE;
-}
-
 /****f* silcutil/SilcAtomicAPI/silc_atomic_init_pointer
  *
  * SYNOPSIS
@@ -307,18 +278,30 @@ SilcBool silc_atomic_init8(SilcAtomic8 *atomic, SilcUInt8 value)
  *
  ***/
 
-static inline
-SilcBool silc_atomic_init_pointer(SilcAtomicPointer *atomic, void *pointer)
-{
-  atomic->pointer = pointer;
+#define SILC_ATOMIC_INIT_F(name, bits, type)                           \
+static inline                                                          \
+SilcBool silc_atomic_init##name(SilcAtomic##bits *atomic, type value)
 
 #if defined(SILC_ATOMIC_MUTEX)
-  if (!silc_mutex_alloc(&atomic->lock))
-    return FALSE;
+#define SILC_ATOMIC_INIT(name, bits, type)                             \
+SILC_ATOMIC_INIT_F(name, bits, type)                                   \
+{                                                                      \
+  atomic->value = value;                                               \
+  return silc_mutex_alloc(&atomic->lock);                              \
+}
+#else
+#define SILC_ATOMIC_INIT(name, bits, type)                             \
+SILC_ATOMIC_INIT_F(name, bits, type)                                   \
+{                                                                      \
+  atomic->value = value;                                               \
+  return TRUE;                                                         \
+}
 #endif /* SILC_ATOMIC_MUTEX */
 
-  return TRUE;
-}
+SILC_ATOMIC_INIT(8, 8, SilcUInt8);
+SILC_ATOMIC_INIT(16, 16, SilcUInt16);
+SILC_ATOMIC_INIT(32, 32, SilcUInt32);
+SILC_ATOMIC_INIT(_pointer, Pointer, void *);
 
 /****f* silcutil/SilcAtomicAPI/silc_atomic_uninit32
  *
@@ -334,15 +317,6 @@ SilcBool silc_atomic_init_pointer(SilcAtomicPointer *atomic, void *pointer)
  *
  ***/
 
-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_uninit16
  *
  * SYNOPSIS
@@ -357,15 +331,6 @@ void silc_atomic_uninit32(SilcAtomic32 *atomic)
  *
  ***/
 
-static inline
-void silc_atomic_uninit16(SilcAtomic16 *atomic)
-{
-  atomic->value = 0;
-#if defined(SILC_ATOMIC_MUTEX)
-  silc_mutex_free(atomic->lock);
-#endif /* SILC_ATOMIC_MUTEX */
-}
-
 /****f* silcutil/SilcAtomicAPI/silc_atomic_uninit8
  *
  * SYNOPSIS
@@ -380,15 +345,6 @@ void silc_atomic_uninit16(SilcAtomic16 *atomic)
  *
  ***/
 
-static inline
-void silc_atomic_uninit8(SilcAtomic8 *atomic)
-{
-  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
@@ -403,14 +359,26 @@ void silc_atomic_uninit8(SilcAtomic8 *atomic)
  *
  ***/
 
-static inline
-void silc_atomic_uninit_pointer(SilcAtomicPointer *atomic)
-{
-  atomic->pointer = NULL;
+#define SILC_ATOMIC_UNINIT_F(bits, t)                                  \
+static inline void silc_atomic_uninit##bits(SilcAtomic##t *atomic)
+
 #if defined(SILC_ATOMIC_MUTEX)
-  silc_mutex_free(atomic->lock);
-#endif /* SILC_ATOMIC_MUTEX */
+#define SILC_ATOMIC_UNINIT(bits, t)                                    \
+SILC_ATOMIC_UNINIT_F(bits, t)                                          \
+{                                                                      \
+  silc_mutex_free(atomic->lock);                                       \
+}
+#else
+#define SILC_ATOMIC_UNINIT(bits, t)                                    \
+SILC_ATOMIC_UNINIT_F(bits, t)                                          \
+{                                                                      \
 }
+#endif /* SILC_ATOMIC_MUTEX */
+
+SILC_ATOMIC_UNINIT(8, 8);
+SILC_ATOMIC_UNINIT(16, 16);
+SILC_ATOMIC_UNINIT(32, 32);
+SILC_ATOMIC_UNINIT(_pointer, Pointer);
 
 /****f* silcutil/SilcAtomicAPI/silc_atomic_set_int32
  *
@@ -425,32 +393,6 @@ void silc_atomic_uninit_pointer(SilcAtomicPointer *atomic)
  *
  ***/
 
-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 */
-  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_int16
  *
  * SYNOPSIS
@@ -464,32 +406,6 @@ void silc_atomic_set_int32(SilcAtomic32 *atomic, SilcUInt32 value)
  *
  ***/
 
-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
@@ -503,31 +419,68 @@ void silc_atomic_set_int16(SilcAtomic16 *atomic, SilcUInt16 value)
  *
  ***/
 
-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;
+#define SILC_ATOMIC_SET_INT_F(bits)                                    \
+static inline void silc_atomic_set_int##bits(SilcAtomic##bits *atomic, \
+                                            SilcUInt##bits value)
+
+#if !defined(SILC_THREADS)
+#define SILC_ATOMIC_SET_INT(bits, bp, bp2)                             \
+SILC_ATOMIC_SET_INT_F(bits)                                            \
+{                                                                      \
+  /* No atomic operations */                                           \
+  atomic->value = value;                                               \
+}
+
+#elif defined(SILC_WIN32)
+#define SILC_ATOMIC_SET_INT(bits, bp, bp2)                             \
+SILC_ATOMIC_SET_INT_F(bits)                                            \
+{                                                                      \
+  /* Windows */                                                                \
+  InterlockedExchange((LONG)&atomic->value, (LONG)value);              \
+}
+
+#elif defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64))
+#define SILC_ATOMIC_SET_INT(bits, bp, bp2)                             \
+SILC_ATOMIC_SET_INT_F(bits)                                            \
+{                                                                      \
+  /* GCC + i486 or x86_64 */                                           \
+  __asm __volatile("xchg" bp " %" bp2 "0, %1"                          \
+                  : "=r" (value)                                       \
+                  : "m" (atomic->value), "0" (value));                 \
+}
 
 #elif defined(__GNUC__) && defined(SILC_IA64)
-  /* IA64, memory barrier needed */
-  atomic->value = value;
-  __sync_synchronize();
+#define SILC_ATOMIC_SET_INT(bits, bp, bp2)                             \
+SILC_ATOMIC_SET_INT_F(bits)                                            \
+{                                                                      \
+  /* 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");
+#define SILC_ATOMIC_SET_INT(bits, bp, bp2)                             \
+SILC_ATOMIC_SET_INT_F(bits)                                            \
+{                                                                      \
+  /* 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
+#else /* SILC_ATOMIC_MUTEX */
+#define SILC_ATOMIC_SET_INT(bits, bp, bp2)                             \
+SILC_ATOMIC_SET_INT_F(bits)                                            \
+{                                                                      \
+  /* Mutex */                                                          \
+  silc_mutex_lock(atomic->lock);                                       \
+  atomic->value = value;                                               \
+  silc_mutex_unlock(atomic->lock);                                     \
 }
+#endif /* !SILC_THREADS */
+
+SILC_ATOMIC_SET_INT(8, "b", "b");
+SILC_ATOMIC_SET_INT(16, "w", "w");
+SILC_ATOMIC_SET_INT(32, "l", "");
 
 /****f* silcutil/SilcAtomicAPI/silc_atomic_set_pointer
  *
@@ -545,25 +498,28 @@ void silc_atomic_set_int8(SilcAtomic8 *atomic, SilcUInt8 value)
 static inline
 void silc_atomic_set_pointer(SilcAtomicPointer *atomic, void *pointer)
 {
-#if !defined(SILC_THREADS) || defined(SILC_WIN32) ||                    \
+#if !defined(SILC_THREADS) ||                   \
      (defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64)))
   /* No threads, Windows, i486 or x86_64, no memory barrier needed */
-  atomic->pointer = pointer;
+  atomic->value = pointer;
+
+#elif defined(SILC_WIN32)
+  InterlockedExchangePointer(&atomic->value, pointer);
 
 #elif defined(__GNUC__) && defined(SILC_IA64)
   /* IA64, memory barrier needed */
-  atomic->pointer = pointer;
+  atomic->value = pointer;
   __sync_synchronize();
 
 #elif defined(__GNUC__) && defined(SILC_POWERPC)
   /* PowerPC, memory barrier needed */
-  atomic->pointer = pointer;
+  atomic->value = pointer;
   __asm("sync" : : : "memory");
 
 #else
   /* Mutex */
   silc_mutex_lock(atomic->lock);
-  atomic->pointer = pointer;
+  atomic->value = pointer;
   silc_mutex_unlock(atomic->lock);
 #endif
 }
@@ -581,38 +537,6 @@ void silc_atomic_set_pointer(SilcAtomicPointer *atomic, void *pointer)
  *
  ***/
 
-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
@@ -626,38 +550,6 @@ SilcUInt32 silc_atomic_get_int32(SilcAtomic32 *atomic)
  *
  ***/
 
-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
@@ -671,37 +563,63 @@ SilcUInt16 silc_atomic_get_int16(SilcAtomic16 *atomic)
  *
  ***/
 
-static inline
-SilcUInt8 silc_atomic_get_int8(SilcAtomic8 *atomic)
-{
-  SilcUInt8 ret;
+#define SILC_ATOMIC_GET_INT_F(bits)                                    \
+static inline                                                          \
+SilcUInt##bits silc_atomic_get_int##bits(SilcAtomic##bits *atomic)
 
-#if !defined(SILC_THREADS) || defined(SILC_WIN32) ||                    \
+#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;
+#define SILC_ATOMIC_GET_INT(bits)                                      \
+SILC_ATOMIC_GET_INT_F(bits)                                            \
+{                                                                      \
+  SilcUInt##bits ret;                                                  \
+                                                                       \
+  /* 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 & 0xff;
-  return ret;
+#define SILC_ATOMIC_GET_INT(bits)                                      \
+SILC_ATOMIC_GET_INT_F(bits)                                            \
+{                                                                      \
+  SilcUInt##bits ret;                                                  \
+                                                                       \
+  /* 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 & 0xff;
-  return ret;
+#define SILC_ATOMIC_GET_INT(bits)                                      \
+SILC_ATOMIC_GET_INT_F(bits)                                            \
+{                                                                      \
+  SilcUInt##bits ret;                                                  \
+                                                                       \
+  /* PowerPC, memory barrier needed */                                 \
+  __asm("sync" : : : "memory");                                                \
+  ret = atomic->value;                                                 \
+  return ret;                                                          \
+}
 
-#else
-  /* Mutex */
-  silc_mutex_lock(atomic->lock);
-  ret = atomic->value & 0xff;
-  silc_mutex_unlock(atomic->lock);
-  return ret;
-#endif
+#else /* SILC_ATOMIC_MUTEX */
+#define SILC_ATOMIC_GET_INT(bits)                                      \
+SILC_ATOMIC_GET_INT_F(bits)                                            \
+{                                                                      \
+  SilcUInt##bits ret;                                                  \
+                                                                       \
+  /* Mutex */                                                          \
+  silc_mutex_lock(atomic->lock);                                       \
+  ret = atomic->value;                                                 \
+  silc_mutex_unlock(atomic->lock);                                     \
+  return ret;                                                          \
 }
+#endif /* !SILC_THREADS */
+
+SILC_ATOMIC_GET_INT(8);
+SILC_ATOMIC_GET_INT(16);
+SILC_ATOMIC_GET_INT(32);
 
 /****f* silcutil/SilcAtomicAPI/silc_atomic_get_pointer
  *
@@ -724,25 +642,25 @@ void *silc_atomic_get_pointer(SilcAtomicPointer *atomic)
 #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;
+  ret = (void *)atomic->value;
   return ret;
 
 #elif defined(__GNUC__) && defined(SILC_IA64)
   /* IA64, memory barrier needed */
   __sync_synchronize();
-  ret = (void *)atomic->pointer;
+  ret = (void *)atomic->value;
   return ret;
 
 #elif defined(__GNUC__) && defined(SILC_POWERPC)
   /* PowerPC, memory barrier needed */
   __asm("sync" : : : "memory");
-  ret = (void *)atomic->pointer;
+  ret = (void *)atomic->value;
   return ret;
 
 #else
   /* Mutex */
   silc_mutex_lock(atomic->lock);
-  ret = (void *)atomic->pointer;
+  ret = (void *)atomic->value;
   silc_mutex_unlock(atomic->lock);
   return ret;
 #endif
@@ -762,52 +680,6 @@ void *silc_atomic_get_pointer(SilcAtomicPointer *atomic)
  *
  ***/
 
-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
@@ -822,56 +694,6 @@ SilcUInt32 silc_atomic_add_int32(SilcAtomic32 *atomic, SilcInt32 value)
  *
  ***/
 
-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
@@ -886,55 +708,90 @@ SilcUInt16 silc_atomic_add_int16(SilcAtomic16 *atomic, SilcInt16 value)
  *
  ***/
 
-static inline
-SilcUInt8 silc_atomic_add_int8(SilcAtomic8 *atomic, SilcInt8 value)
-{
-  SilcUInt8 ret;
+#define SILC_ATOMIC_ADD_INT_F(bits)                                    \
+static inline                                                          \
+SilcUInt##bits silc_atomic_add_int##bits(SilcAtomic##bits *atomic,     \
+                                        SilcInt##bits value)
 
 #if !defined(SILC_THREADS)
-  /* No atomic operations */
-  ret = atomic->value;
-  atomic->value += value;
+#define SILC_ATOMIC_ADD_INT(bits, bp)                                  \
+SILC_ATOMIC_ADD_INT_F(bits)                                            \
+{                                                                      \
+  SilcUInt##bits ret;                                                  \
+  /* No atomic operations */                                           \
+  ret = atomic->value;                                                 \
+  atomic->value += value;                                              \
+  return ret + value;                                                  \
+}
 
 #elif defined(SILC_WIN32)
-  /* Windows */
-  LONG v = value;
-  ret = InterlockedExchangeAdd(&atomic->value, v);
+#define SILC_ATOMIC_ADD_INT(bits, bp)                                  \
+SILC_ATOMIC_ADD_INT_F(bits)                                            \
+{                                                                      \
+  SilcUInt##bits ret;                                                  \
+  LONG val = value;                                                    \
+  /* Windows */                                                                \
+  ret = InterlockedExchangeAdd(&atomic->value, val);                   \
+  return ret + value;                                                  \
+}
 
 #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));
+#define SILC_ATOMIC_ADD_INT(bits, bp)                                  \
+SILC_ATOMIC_ADD_INT_F(bits)                                            \
+{                                                                      \
+  SilcUInt##bits ret;                                                  \
+  /* GCC + i486 or x86_64 */                                           \
+  __asm __volatile(SILC_SMP_LOCK "xadd" bp " %0, %1"                   \
+                  : "=r" (ret), "+m" (atomic->value)                   \
+                  : "0" (value));                                      \
+  return ret + value;                                                  \
+}
 
 #elif defined(__GNUC__) && defined(SILC_IA64)
-  /* GCC + IA64 (GCC builtin atomic operations) */
-  SilcInt32 v = value;
-  ret = __sync_fetch_and_add(&atomic->value, v);
+#define SILC_ATOMIC_ADD_INT(bits, bp)                                  \
+SILC_ATOMIC_ADD_INT_F(bits)                                            \
+{                                                                      \
+  SilcUInt##bits ret;                                                  \
+  SilcInt32 val = value;
+  /* GCC + IA64 (GCC builtin atomic operations) */                     \
+  ret = __sync_fetch_and_add(&atomic->value, val);                     \
+  return ret + value;                                                  \
+}
 
 #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
+#define SILC_ATOMIC_ADD_INT(bits, bp)                                  \
+SILC_ATOMIC_ADD_INT_F(bits)                                            \
+{                                                                      \
+  SilcUInt32 ret;                                                      \
+  SilcInt32 val = value;                                               \
+  /* 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" (val), "r" (&atomic->value)                    \
+                  : "cc");                                             \
+  return ret;                                                          \
+}
 
-  return ret + value;
+#else /* SILC_ATOMIC_MUTEX */
+#define SILC_ATOMIC_ADD_INT(bits, bp)                                  \
+SILC_ATOMIC_ADD_INT_F(bits)                                            \
+{                                                                      \
+  SilcUInt##bits ret;                                                  \
+  /* Mutex */                                                          \
+  silc_mutex_lock(atomic->lock);                                       \
+  ret = atomic->value;                                                 \
+  atomic->value += value;                                              \
+  silc_mutex_unlock(atomic->lock);                                     \
+  return ret + value;                                                  \
 }
+#endif /* !SILC_THREADS */
+
+SILC_ATOMIC_ADD_INT(8, "b");
+SILC_ATOMIC_ADD_INT(16, "w");
+SILC_ATOMIC_ADD_INT(32, "l");
 
 /****f* silcutil/SilcAtomicAPI/silc_atomic_sub_int32
  *
@@ -950,12 +807,6 @@ SilcUInt8 silc_atomic_add_int8(SilcAtomic8 *atomic, SilcInt8 value)
  *
  ***/
 
-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
@@ -970,12 +821,6 @@ SilcUInt32 silc_atomic_sub_int32(SilcAtomic32 *atomic, SilcInt32 value)
  *
  ***/
 
-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
@@ -990,138 +835,255 @@ SilcUInt16 silc_atomic_sub_int16(SilcAtomic16 *atomic, SilcInt16 value)
  *
  ***/
 
-static inline
-SilcUInt8 silc_atomic_sub_int8(SilcAtomic8 *atomic, SilcInt8 value)
-{
-  return silc_atomic_add_int8(atomic, -value);
-}
+#define silc_atomic_sub_int8(a, v) silc_atomic_add_int8(a, (-v))
+#define silc_atomic_sub_int16(a, v) silc_atomic_add_int16(a, (-v))
+#define silc_atomic_sub_int32(a, v) silc_atomic_add_int32(a, (-v))
 
-/****f* silcutil/SilcAtomicAPI/silc_atomic_cas32
+/****f* silcutil/SilcAtomicAPI/silc_atomic_inc32
  *
  * SYNOPSIS
  *
  *    static inline
- *    SilcBool silc_atomic_cas32(SilcAtomic32 *atomic, SilcUInt32 old_val,
- *                               SilcUInt32 new_val)
+ *    void silc_atomic_inc32(SilcAtomic32 *atomic);
  *
  * 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.
+ *    Atomically increments 32-bit integer by one.
  *
  ***/
 
-static inline
-SilcBool silc_atomic_cas32(SilcAtomic32 *atomic, SilcUInt32 old_val,
-                          SilcUInt32 new_val)
-{
+/****f* silcutil/SilcAtomicAPI/silc_atomic_inc16
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    void silc_atomic_inc16(SilcAtomic16 *atomic);
+ *
+ * DESCRIPTION
+ *
+ *    Atomically increments 16-bit integer by one.
+ *
+ ***/
+
+/****f* silcutil/SilcAtomicAPI/silc_atomic_inc8
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    void silc_atomic_inc8(SilcAtomic8 *atomic);
+ *
+ * DESCRIPTION
+ *
+ *    Atomically increments 8-bit integer by one.
+ *
+ ***/
+
+#define SILC_ATOMIC_INC_F(bits)                                                \
+static inline void silc_atomic_inc##bits(SilcAtomic##bits *atomic)
+
 #if !defined(SILC_THREADS)
-  /* No atomic operations */
-  if (atomic->value == old_val) {
-    atomic->value = new_val;
-    return TRUE;
-  }
-  return FALSE;
+#define SILC_ATOMIC_INC(bits, bp)                                      \
+SILC_ATOMIC_INC_F(bits)                                                        \
+{                                                                      \
+  /* No atomic operations */                                           \
+  ++atomic->value;                                                     \
+}
 
 #elif defined(SILC_WIN32)
-  /* Windows */
-  return InterlockedCompareExchange(&atomic->value, (LONG)new_val,
-                                   (LONG)old_val) == old_val;
+#define SILC_ATOMIC_INC(bits, bp)                                      \
+SILC_ATOMIC_INC_F(bits)                                                        \
+{                                                                      \
+  /* Windows */                                                                \
+  InterlockedIncrement((LONG)&atomic->value);                          \
+}
 
 #elif defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64))
-  /* GCC + i486 or x86_64 */
-  SilcUInt32 ret;
-  __asm __volatile("lock; cmpxchgl %2, %1"
-                  : "=a" (ret), "=m" (atomic->value)
-                  : "r" (new_val), "m" (atomic->value), "0" (old_val));
-  return ret == old_val;
+#define SILC_ATOMIC_INC(bits, bp)                                      \
+SILC_ATOMIC_INC_F(bits)                                                        \
+{                                                                      \
+  /* GCC + i486 or x86_64 */                                           \
+  __asm __volatile(SILC_SMP_LOCK "inc" bp " %0"                                \
+                  : "+m" (atomic->value));                             \
+}
 
 #elif defined(__GNUC__) && defined(SILC_IA64)
-  /* GCC + IA64 (GCC builtin atomic operations) */
-  return  __sync_bool_compare_and_swap(&atomic->value, old_val, new_val);
+#define SILC_ATOMIC_INC(bits, bp)                                      \
+SILC_ATOMIC_INC_F(bits)                                                        \
+{                                                                      \
+  /* GCC + IA64 (GCC builtin atomic operations) */                     \
+  __sync_fetch_and_add(&atomic->value, 1);                             \
+}
 
 #elif defined(__GNUC__) && defined(SILC_POWERPC)
-  /* GCC + PowerPC */
-  /* XXX TODO */
+#define SILC_ATOMIC_INC(bits, bp)                                      \
+SILC_ATOMIC_INC_F(bits)                                                        \
+{                                                                      \
+  SilcUInt32 ret;                                                      \
+  SilcInt32 val = 1;                                                   \
+  /* 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" (val), "r" (&atomic->value)                    \
+                  : "cc");                                             \
+}
 
-#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
+#else /* SILC_ATOMIC_MUTEX */
+#define SILC_ATOMIC_INC(bits, bp)                                      \
+SILC_ATOMIC_INC_F(bits)                                                        \
+{                                                                      \
+  /* Mutex */                                                          \
+  silc_mutex_lock(atomic->lock);                                       \
+  ++atomic->value;                                                     \
+  silc_mutex_unlock(atomic->lock);                                     \
 }
+#endif /* !SILC_THREADS */
 
-/****f* silcutil/SilcAtomicAPI/silc_atomic_cas16
+SILC_ATOMIC_INC(8, "b");
+SILC_ATOMIC_INC(16, "w");
+SILC_ATOMIC_INC(32, "l");
+
+/****f* silcutil/SilcAtomicAPI/silc_atomic_dec32
  *
  * SYNOPSIS
  *
  *    static inline
- *    SilcBool silc_atomic_cas16(SilcAtomic16 *atomic, SilcUInt16 old_val,
- *                               SilcUInt16 new_val)
+ *    void silc_atomic_dec32(SilcAtomic32 *atomic);
  *
  * 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.
+ *    Atomically decrements 32-bit integer by one.
  *
  ***/
 
-static inline
-SilcBool silc_atomic_cas16(SilcAtomic16 *atomic, SilcUInt16 old_val,
-                          SilcUInt16 new_val)
-{
+/****f* silcutil/SilcAtomicAPI/silc_atomic_dec16
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    void silc_atomic_dec16(SilcAtomic16 *atomic);
+ *
+ * DESCRIPTION
+ *
+ *    Atomically decrements 16-bit integer by one.
+ *
+ ***/
+
+/****f* silcutil/SilcAtomicAPI/silc_atomic_dec8
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    void silc_atomic_dec8(SilcAtomic8 *atomic);
+ *
+ * DESCRIPTION
+ *
+ *    Atomically decrements 8-bit integer by one.
+ *
+ ***/
+
+#define SILC_ATOMIC_DEC_F(bits)                                                \
+static inline void silc_atomic_dec##bits(SilcAtomic##bits *atomic)
+
 #if !defined(SILC_THREADS)
-  /* No atomic operations */
-  if (atomic->value == old_val) {
-    atomic->value = new_val;
-    return TRUE;
-  }
-  return FALSE;
+#define SILC_ATOMIC_DEC(bits, bp)                                      \
+SILC_ATOMIC_DEC_F(bits)                                                        \
+{                                                                      \
+  /* No atomic operations */                                           \
+  --atomic->value;                                                     \
+}
 
 #elif defined(SILC_WIN32)
-  /* Windows */
-  LONG o = old_val, n = new_val;
-  return InterlockedCompareExchange(&atomic->value, n, o) == o;
+#define SILC_ATOMIC_DEC(bits, bp)                                      \
+SILC_ATOMIC_DEC_F(bits)                                                        \
+{                                                                      \
+  /* Windows */                                                                \
+  InterlockedDecrement((LONG)&atomic->value);                          \
+}
 
 #elif defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64))
-  /* GCC + i486 or x86_64 */
-  SilcUInt16 ret;
-  __asm __volatile("lock; cmpxchgw %2, %1"
-                  : "=a" (ret), "=m" (atomic->value)
-                  : "c" (new_val), "m" (atomic->value), "0" (old_val));
-  return ret == old_val;
+#define SILC_ATOMIC_DEC(bits, bp)                                      \
+SILC_ATOMIC_DEC_F(bits)                                                        \
+{                                                                      \
+  /* GCC + i486 or x86_64 */                                           \
+  __asm __volatile(SILC_SMP_LOCK "dec" bp " %0"                                \
+                  : "+m" (atomic->value));                             \
+}
 
 #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);
+#define SILC_ATOMIC_DEC(bits, bp)                                      \
+SILC_ATOMIC_DEC_F(bits)                                                        \
+{                                                                      \
+  /* GCC + IA64 (GCC builtin atomic operations) */                     \
+  __sync_fetch_and_sub(&atomic->value, 1);                             \
+}
 
 #elif defined(__GNUC__) && defined(SILC_POWERPC)
-  /* GCC + PowerPC */
-  /* XXX TODO */
+#define SILC_ATOMIC_DEC(bits, bp)                                      \
+SILC_ATOMIC_DEC_F(bits)                                                        \
+{                                                                      \
+  SilcUInt32 ret;                                                      \
+  SilcInt32 val = -1;                                                  \
+  /* 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" (val), "r" (&atomic->value)                    \
+                  : "cc");                                             \
+}
 
-#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
+#else /* SILC_ATOMIC_MUTEX */
+#define SILC_ATOMIC_DEC(bits, bp)                                      \
+SILC_ATOMIC_DEC_F(bits)                                                        \
+{                                                                      \
+  /* Mutex */                                                          \
+  silc_mutex_lock(atomic->lock);                                       \
+  --atomic->value;                                                     \
+  silc_mutex_unlock(atomic->lock);                                     \
 }
+#endif /* !SILC_THREADS */
+
+SILC_ATOMIC_DEC(8, "b");
+SILC_ATOMIC_DEC(16, "w");
+SILC_ATOMIC_DEC(32, "l");
+
+/****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.
+ *
+ ***/
+
+/****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.
+ *
+ ***/
 
 /****f* silcutil/SilcAtomicAPI/silc_atomic_cas8
  *
@@ -1140,52 +1102,80 @@ SilcBool silc_atomic_cas16(SilcAtomic16 *atomic, SilcUInt16 old_val,
  *
  ***/
 
-static inline
-SilcBool silc_atomic_cas8(SilcAtomic8 *atomic, SilcUInt8 old_val,
-                         SilcUInt8 new_val)
-{
+#define SILC_ATOMIC_CAS_F(bits)                                                \
+static inline SilcBool silc_atomic_cas##bits(SilcAtomic##bits *atomic,  \
+                                            SilcInt##bits old_val,     \
+                                            SilcInt##bits new_val)
+
 #if !defined(SILC_THREADS)
-  /* No atomic operations */
-  if (atomic->value == old_val) {
-    atomic->value = new_val;
-    return TRUE;
-  }
-  return FALSE;
+#define SILC_ATOMIC_CAS(bits, bp)                                      \
+SILC_ATOMIC_CAS_F(bits)                                                        \
+{                                                                      \
+  /* No atomic operations */                                           \
+  if (atomic->value == (SilcUInt##bits)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;
+#define SILC_ATOMIC_CAS(bits, bp)                                      \
+SILC_ATOMIC_CAS_F(bits)                                                        \
+{                                                                      \
+  /* 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 */
-  SilcUInt8 ret;
-  __asm __volatile("lock; cmpxchgb %2, %1"
-                  : "=a" (ret), "=m" (atomic->value)
-                  : "c" (new_val), "m" (atomic->value), "0" (old_val));
-  return ret == old_val;
+#define SILC_ATOMIC_CAS(bits, bp)                                      \
+SILC_ATOMIC_CAS_F(bits)                                                        \
+{                                                                      \
+  /* GCC + i486 or x86_64 */                                           \
+  SilcUInt##bits ret;                                                  \
+  __asm __volatile(SILC_SMP_LOCK "cmpxchg" bp " %2, %1"                        \
+                  : "=a" (ret), "=m" (atomic->value)                   \
+                  : "r" (new_val), "m" (atomic->value), "0" (old_val)); \
+  return ret == (SilcUInt##bits)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);
+#define SILC_ATOMIC_CAS(bits, bp)                                      \
+SILC_ATOMIC_CAS_F(bits)                                                        \
+{                                                                      \
+  /* 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 */
+#define SILC_ATOMIC_CAS(bits, bp)                                      \
+SILC_ATOMIC_CAS_F(bits)                                                        \
+{                                                                      \
+  /* 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
+#else /* SILC_ATOMIC_MUTEX */
+#define SILC_ATOMIC_CAS(bits, bp)                                      \
+SILC_ATOMIC_CAS_F(bits)                                                        \
+{                                                                      \
+  /* Mutex */                                                          \
+  silc_mutex_lock(atomic->lock);                                       \
+  if (atomic->value == (SilcUInt##bits)old_val) {                      \
+    atomic->value = new_val;                                           \
+    silc_mutex_unlock(atomic->lock);                                   \
+    return TRUE;                                                       \
+  }                                                                    \
+  silc_mutex_unlock(atomic->lock);                                     \
+  return FALSE;                                                                \
 }
+#endif /* !SILC_THREADS */
+
+SILC_ATOMIC_CAS(8, "b");
+SILC_ATOMIC_CAS(16, "w");
+SILC_ATOMIC_CAS(32, "l");
 
 /****f* silcutil/SilcAtomicAPI/silc_atomic_cas_pointer
  *
@@ -1210,35 +1200,35 @@ SilcBool silc_atomic_cas_pointer(SilcAtomicPointer *atomic, void *old_val,
 {
 #if !defined(SILC_THREADS)
   /* No atomic operations */
-  if (atomic->pointer == old_val) {
-    atomic->pointer = new_val;
+  if (atomic->value == old_val) {
+    atomic->value = new_val;
     return TRUE;
   }
   return FALSE;
 
 #elif defined(SILC_WIN32)
   /* Windows */
-  return InterlockedCompareExchangePointer(&atomic->pointer, n, o) == o;
+  return InterlockedCompareExchangePointer(&atomic->value, n, o) == o;
 
 #elif defined(__GNUC__) && defined(SILC_I486)
   /* GCC + i486 */
   void *ret;
-  __asm __volatile("lock; cmpxchgl %2, %1"
-                  : "=a" (ret), "=m" (atomic->pointer)
-                  : "c" (new_val), "m" (atomic->pointer), "0" (old_val));
+  __asm __volatile(SILC_SMP_LOCK "cmpxchgl %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_X86_64)
   /* GCC + x86_64 */
   void *ret;
-  __asm __volatile("lock; cmpxchgq %q2, %1"
-                  : "=a" (ret), "=m" (atomic->pointer)
-                  : "c" (new_val), "m" (atomic->pointer), "0" (old_val));
+  __asm __volatile(SILC_SMP_LOCK "cmpxchgq %q2, %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) */
-  return  __sync_bool_compare_and_swap((long)&atomic->pointer, (long)old_val,
+  return  __sync_bool_compare_and_swap((long)&atomic->value, (long)old_val,
                                       (long)new_val);
 
 #elif defined(__GNUC__) && defined(SILC_POWERPC)
@@ -1248,8 +1238,8 @@ SilcBool silc_atomic_cas_pointer(SilcAtomicPointer *atomic, void *old_val,
 #else
   /* Mutex */
   silc_mutex_lock(atomic->lock);
-  if (atomic->pointer == old_val) {
-    atomic->pointer = new_val;
+  if (atomic->value == old_val) {
+    atomic->value = new_val;
     silc_mutex_unlock(atomic->lock);
     return TRUE;
   }
index 6a57f7887a538e0c0ab310966ba0c30ec354403d..1bf2f09bc7ecae530b5bdfe7f12c302eac19e5d0 100644 (file)
@@ -20,7 +20,7 @@ AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
 bin_PROGRAMS =         test_silcstrutil test_silcstringprep test_silchashtable \
        test_silclist test_silcfsm test_silcasync test_silcschedule \
        test_silcnet test_silcstack test_silcmime test_silcfdstream \
-       test_silcatomic
+       test_silcatomic test_silcmutex
 
 test_silcstrutil_SOURCES = test_silcstrutil.c
 test_silcstringprep_SOURCES = test_silcstringprep.c
@@ -34,6 +34,7 @@ test_silcnet_SOURCES = test_silcnet.c
 test_silcstack_SOURCES = test_silcstack.c
 test_silcfdstream_SOURCES = test_silcfdstream.c
 test_silcatomic_SOURCES = test_silcatomic.c
+test_silcmutex_SOURCES = test_silcmutex.c
 
 LIBS = $(SILC_COMMON_LIBS)
 LDADD = -L.. -L../.. -lsilc
index 89405a4dbf61a8a09a7fd178bda574acd54cf783..23105f4ee01dc6f607c56fc511b2b6f3ab3b46e7 100644 (file)
@@ -40,8 +40,8 @@ int main(int argc, char **argv)
   SILC_LOG_DEBUG(("ref16: 31022 + 34000 = %d (65022)", ret16));
   ret16 = silc_atomic_sub_int16(&ref16, 0);
   SILC_LOG_DEBUG(("ref16: 65022 - 0 = %d (65022)", ret16));
-  ret16 = silc_atomic_sub_int16(&ref16, 0xffff);
-  SILC_LOG_DEBUG(("ref16: 65022 - 0xfff = %d (65023) (underflow)", ret16));
+  ret16 = silc_atomic_sub_int16(&ref16, (SilcInt16)0xffff);
+  SILC_LOG_DEBUG(("ref16: 65022 - 0xffff = %d (65023) (underflow)", ret16));
 
   SILC_LOG_DEBUG(("Current value: %d (-513)",
                  (SilcInt16)silc_atomic_get_int16(&ref16)));
@@ -87,6 +87,23 @@ int main(int argc, char **argv)
   SILC_LOG_DEBUG(("Current ptr: %p (NULL)",
                  silc_atomic_get_pointer(&refptr)));
 
+  SILC_LOG_DEBUG(("Setting val 34322111 (32-bit)"));
+  silc_atomic_set_int32(&ref32, 34322111);
+  if (silc_atomic_get_int32(&ref32) != 34322111)
+    goto err;
+  SILC_LOG_DEBUG(("Setting val 1432211119 (32-bit)"));
+  silc_atomic_set_int32(&ref32, 1432211119);
+  if (silc_atomic_get_int32(&ref32) != 1432211119)
+    goto err;
+  SILC_LOG_DEBUG(("Setting val 23422 (16-bit)"));
+  silc_atomic_set_int16(&ref16, 23422);
+  if (silc_atomic_get_int16(&ref16) != 23422)
+    goto err;
+  SILC_LOG_DEBUG(("Setting val 124 (8-bit)"));
+  silc_atomic_set_int8(&ref8, 124);
+  if (silc_atomic_get_int8(&ref8) != 124)
+    goto err;
+
   silc_atomic_uninit8(&ref8);
   silc_atomic_uninit16(&ref16);
   silc_atomic_uninit32(&ref32);
diff --git a/lib/silcutil/tests/test_silcmutex.c b/lib/silcutil/tests/test_silcmutex.c
new file mode 100644 (file)
index 0000000..1b4da61
--- /dev/null
@@ -0,0 +1,225 @@
+/* Locking performance tests.  Gives locsk&unlocks/second. */
+/* Version 1.0 */
+
+#include "silc.h"
+
+typedef struct {
+  SilcThread thread;
+  SilcInt64 time;
+} Context;
+
+#define MAX_ROUND 8
+#define MAX_MUL 4
+#define MAX_THREADS 4
+#define MAX_LOCKS 271234567
+
+SilcMutex mutex;
+SilcUInt64 cpu_freq = 0;
+int max_locks, max_locks2;
+
+/* RDTSC */
+#ifdef SILC_I486
+static __inline__ unsigned long long rdtsc(void)
+{
+  unsigned long long int x;
+  __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
+  return x;
+}
+
+#elif SILC_X86_64
+typedef unsigned long long int unsigned long long;
+static __inline__ unsigned long long rdtsc(void)
+{
+  unsigned hi, lo;
+  __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+  return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
+}
+
+#elif SILC_POWERPC
+typedef unsigned long long int unsigned long long;
+static __inline__ unsigned long long rdtsc(void)
+{
+  unsigned long long int result = 0;
+  unsigned long int upper, lower,tmp;
+  __asm__ volatile(
+                "0:                  \n"
+                "\tmftbu   %0           \n"
+                "\tmftb    %1           \n"
+                "\tmftbu   %2           \n"
+                "\tcmpw    %2,%0        \n"
+                "\tbne     0b         \n"
+                : "=r"(upper),"=r"(lower),"=r"(tmp)
+                );
+  result = upper;
+  result = result << 32;
+  result = result | lower;
+
+  return result;
+}
+#endif
+
+void *mutex_thread(void *context)
+{
+  Context *c = context;
+  SilcInt64 s;
+  register int i;
+
+  s = rdtsc();
+  for (i = 0; i < max_locks; i++) {
+    silc_mutex_lock(mutex);
+    silc_mutex_unlock(mutex);
+  }
+  c->time = rdtsc() - s;
+  c->time /= cpu_freq;
+
+  return NULL;
+}
+
+SilcUInt64 hval;
+SilcUInt64 hval2;
+SilcUInt64 hval3;
+
+void *mutex_thread_hold(void *context)
+{
+  Context *c = context;
+  SilcInt64 s;
+  register int i;
+
+  s = rdtsc();
+  for (i = 0; i < max_locks / 4; i++) {
+    silc_mutex_lock(mutex);
+    hval2 = i;
+    hval3 = 0;
+    hval += hval;
+    hval3 = hval2 + i;
+    if (hval > max_locks)
+      hval = 0;
+    if (hval < max_locks)
+      hval = max_locks;
+    hval += hval;
+    hval3 += hval;
+    if (silc_unlikely(hval3 != hval2 + i + hval)) {
+      fprintf(stderr, "MUTEX CORRUPT 1\n");
+      exit(1);
+    }
+    if (silc_unlikely(hval2 != i)) {
+      fprintf(stderr, "MUTEX CORRUPT 2 (%llu != %d)\n", hval2, i);
+      exit(1);
+    }
+    silc_mutex_unlock(mutex);
+  }
+  c->time = rdtsc() - s;
+  c->time /= cpu_freq;
+
+  return NULL;
+}
+
+int main(int argc, char **argv)
+{
+  Context c[MAX_THREADS * MAX_MUL];
+  SilcInt64 val;
+  int k, i, j, o = 0;
+  SilcBool success;
+
+  if (argc <= 1) {
+    fprintf(stderr, "Usage: ./test_silcmutex <cpu_freq_mhz>\n");
+    fprintf(stderr, "Example: ./test_silcmutex 3000\n");
+    exit(1);
+  }
+  cpu_freq = (SilcUInt64)atoi(argv[1]);
+  cpu_freq *= 1000;    /* Will give us milliseconds */
+
+  max_locks = MAX_LOCKS;
+
+  fprintf(stderr, "lock/unlock per second\n");
+
+  for (j = 0; j < MAX_ROUND; j++) {
+    for (i = 0; i < 1; i++)
+      c[i].thread = silc_thread_create(mutex_thread, &c[i], TRUE);
+
+    val = 0;
+    for (i = 0; i < 1; i++) {
+      silc_thread_wait(c[i].thread, NULL);
+      val += c[i].time;
+    }
+    fprintf(stderr, "%llu mutex lock/unlock per second (%d threads)\n",
+                     (1000LL * max_locks * 1) / val, 1);
+
+    if (o == 0) {
+      /* If MAX_LOCKS is too large for this CPU, optimize.  We don't want to
+        wait a whole day for this test. */
+      if ((SilcInt64)(max_locks / 10) >
+         (SilcInt64)((1000LL * max_locks) / val))
+       max_locks /= 10;
+      o = 1;
+    }
+  }
+  puts("");
+
+  max_locks2 = max_locks;
+  for (k = 0; k < MAX_MUL; k++) {
+    sleep(16);
+    max_locks = max_locks2 / (k + 1);
+    for (j = 0; j < MAX_ROUND; j++) {
+      for (i = 0; i < MAX_THREADS * (k + 1); i++)
+       c[i].thread = silc_thread_create(mutex_thread, &c[i], TRUE);
+
+      val = 0;
+      for (i = 0; i < MAX_THREADS * (k + 1); i++) {
+       silc_thread_wait(c[i].thread, NULL);
+       val += c[i].time;
+      }
+      fprintf(stderr, "%llu mutex lock/unlock per second (%d threads)\n",
+                     (1000LL * max_locks * (MAX_THREADS * (k + 1))) / val,
+                     MAX_THREADS * (k + 1));
+    }
+    puts("");
+  }
+  max_locks = max_locks2;
+
+  fprintf(stderr, "Spinning/holding lock, lock/unlock per second\n");
+
+  sleep(16);
+  for (j = 0; j < MAX_ROUND; j++) {
+    for (i = 0; i < 1; i++)
+      c[i].thread = silc_thread_create(mutex_thread_hold, &c[i], TRUE);
+
+    val = 0;
+    for (i = 0; i < 1; i++) {
+      silc_thread_wait(c[i].thread, NULL);
+      val += c[i].time;
+    }
+    fprintf(stderr, "%llu mutex lock/unlock per second (%d threads)\n",
+                     (1000LL * (max_locks / 4)) / val, 1);
+  }
+  puts("");
+
+  max_locks2 = max_locks;
+  for (k = 0; k < MAX_MUL; k++) {
+    sleep(16);
+    max_locks = max_locks2 / (k + 1);
+    for (j = 0; j < MAX_ROUND; j++) {
+      hval = hval2 = 1;
+      for (i = 0; i < MAX_THREADS * (k + 1); i++)
+       c[i].thread = silc_thread_create(mutex_thread, &c[i], TRUE);
+
+      val = 0;
+      for (i = 0; i < MAX_THREADS * (k + 1); i++) {
+       silc_thread_wait(c[i].thread, NULL);
+       val += c[i].time;
+      }
+      fprintf(stderr, "%llu mutex lock/unlock per second (%d threads)\n",
+                     (1000LL * (max_locks / 4) *
+                      (MAX_THREADS * (k + 1))) / val,
+                     MAX_THREADS * (k + 1));
+    }
+    puts("");
+  }
+  max_locks = max_locks2;
+
+  success = TRUE;
+
+  fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
+
+  return success;
+}