From 6bc07a1a4175d3630257f8f6ae149ee0a1cdd3d9 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Sun, 11 Feb 2007 18:07:03 +0000 Subject: [PATCH] Reorganized silcatomi.h. Added silc_atomic_[inc|dec][8|16|32]. --- lib/silcutil/silcatomic.h | 1050 +++++++++++++------------- lib/silcutil/tests/Makefile.am | 3 +- lib/silcutil/tests/test_silcatomic.c | 21 +- lib/silcutil/tests/test_silcmutex.c | 225 ++++++ 4 files changed, 766 insertions(+), 533 deletions(-) create mode 100644 lib/silcutil/tests/test_silcmutex.c diff --git a/lib/silcutil/silcatomic.h b/lib/silcutil/silcatomic.h index 65d8b99d..e2719b4c 100644 --- a/lib/silcutil/silcatomic.h +++ b/lib/silcutil/silcatomic.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - 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 @@ -40,6 +40,16 @@ #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; } diff --git a/lib/silcutil/tests/Makefile.am b/lib/silcutil/tests/Makefile.am index 6a57f788..1bf2f09b 100644 --- a/lib/silcutil/tests/Makefile.am +++ b/lib/silcutil/tests/Makefile.am @@ -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 diff --git a/lib/silcutil/tests/test_silcatomic.c b/lib/silcutil/tests/test_silcatomic.c index 89405a4d..23105f4e 100644 --- a/lib/silcutil/tests/test_silcatomic.c +++ b/lib/silcutil/tests/test_silcatomic.c @@ -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 index 00000000..1b4da618 --- /dev/null +++ b/lib/silcutil/tests/test_silcmutex.c @@ -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 \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; +} -- 2.24.0