diff options
author | wtc%google.com <devnull@localhost> | 2008-01-27 01:50:19 +0000 |
---|---|---|
committer | wtc%google.com <devnull@localhost> | 2008-01-27 01:50:19 +0000 |
commit | 35f3aeee25848f5708f211c7b6fc072fbf372595 (patch) | |
tree | 21a4912bb42184a9bd1ce261f1ea7d03431bcf97 | |
parent | b20b507ca0796b5d6900945b7c067ea858705c3a (diff) | |
download | nspr-hg-35f3aeee25848f5708f211c7b6fc072fbf372595.tar.gz |
Bug 334826: added macro versions of atomic operations, which may be
implemented as compiler intrinsics. The patch is contributed by Steve
Snyder <swsnyder@insightbb.com>. r=wtc
Modified files: pratom.h atomic.c
-rw-r--r-- | pr/include/pratom.h | 51 | ||||
-rw-r--r-- | pr/tests/atomic.c | 81 |
2 files changed, 132 insertions, 0 deletions
diff --git a/pr/include/pratom.h b/pr/include/pratom.h index 57d069b0..2e4967c2 100644 --- a/pr/include/pratom.h +++ b/pr/include/pratom.h @@ -95,6 +95,57 @@ NSPR_API(PRInt32) PR_AtomicSet(PRInt32 *val, PRInt32 newval); NSPR_API(PRInt32) PR_AtomicAdd(PRInt32 *ptr, PRInt32 val); /* +** MACRO: PR_ATOMIC_INCREMENT +** MACRO: PR_ATOMIC_DECREMENT +** MACRO: PR_ATOMIC_SET +** MACRO: PR_ATOMIC_ADD +** DESCRIPTION: +** Macro versions of the atomic operations. They may be implemented +** as compiler intrinsics. +*/ +#if defined(_WIN32) && (_MSC_VER >= 1310) + +long __cdecl _InterlockedIncrement(long volatile *Addend); +#pragma intrinsic(_InterlockedIncrement) + +long __cdecl _InterlockedDecrement(long volatile *Addend); +#pragma intrinsic(_InterlockedDecrement) + +long __cdecl _InterlockedExchange(long volatile *Target, long Value); +#pragma intrinsic(_InterlockedExchange) + +long __cdecl _InterlockedExchangeAdd(long volatile *Addend, long Value); +#pragma intrinsic(_InterlockedExchangeAdd) + +#define PR_ATOMIC_INCREMENT(val) _InterlockedIncrement(val) +#define PR_ATOMIC_DECREMENT(val) _InterlockedDecrement(val) +#define PR_ATOMIC_SET(val, newval) _InterlockedExchange(val, newval) +#define PR_ATOMIC_ADD(ptr, val) (_InterlockedExchangeAdd(ptr, val) + (val)) + +#elif ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && \ + (defined(__i386__) || defined(__ia64__) || defined(__x86_64__) || \ + defined(__powerpc__) || defined(__ppc__) || defined(__alpha)) +/* + * Because the GCC manual warns that some processors may support + * reduced functionality of __sync_lock_test_and_set, we test for the + * processors that we believe support a full atomic exchange operation. + */ + +#define PR_ATOMIC_INCREMENT(val) __sync_add_and_fetch(val, 1) +#define PR_ATOMIC_DECREMENT(val) __sync_sub_and_fetch(val, 1) +#define PR_ATOMIC_SET(val, newval) __sync_lock_test_and_set(val, newval) +#define PR_ATOMIC_ADD(ptr, val) __sync_add_and_fetch(ptr, val) + +#else + +#define PR_ATOMIC_INCREMENT(val) PR_AtomicIncrement(val) +#define PR_ATOMIC_DECREMENT(val) PR_AtomicDecrement(val) +#define PR_ATOMIC_SET(val, newval) PR_AtomicSet(val, newval) +#define PR_ATOMIC_ADD(ptr, val) PR_AtomicAdd(ptr, val) + +#endif + +/* ** LIFO linked-list (stack) */ typedef struct PRStackElemStr PRStackElem; diff --git a/pr/tests/atomic.c b/pr/tests/atomic.c index 1295b297..4b454fee 100644 --- a/pr/tests/atomic.c +++ b/pr/tests/atomic.c @@ -44,6 +44,10 @@ PRIntn main(PRIntn argc, char **argv) PRInt32 rv, oldval, test, result = 0; PRFileDesc *output = PR_GetSpecialFD(PR_StandardOutput); + /***********************/ + /* Test the functions. */ + /***********************/ + oldval = test = -2; rv = PR_AtomicIncrement(&test); result = result | ((rv == -1) ? 0 : 1); @@ -117,6 +121,83 @@ PRIntn main(PRIntn argc, char **argv) output, "PR_AtomicSet(%d, %d) == %d: %s\n", oldval, -2, rv, ((rv == -2) && (test == -2)) ? "PASSED" : "FAILED"); + /***********************/ + /* Test the macros. */ + /***********************/ + + oldval = test = -2; + rv = PR_ATOMIC_INCREMENT(&test); + result = result | ((rv == -1) ? 0 : 1); + PR_fprintf( + output, "PR_ATOMIC_INCREMENT(%d) == %d: %s\n", + oldval, rv, (rv == -1) ? "PASSED" : "FAILED"); + oldval = test; + rv = PR_ATOMIC_INCREMENT(&test); + result = result | ((rv == 0) ? 0 : 1); + PR_fprintf( + output, "PR_ATOMIC_INCREMENT(%d) == %d: %s\n", + oldval, rv, (rv == 0) ? "PASSED" : "FAILED"); + oldval = test; + rv = PR_ATOMIC_INCREMENT(&test); + result = result | ((rv == 1) ? 0 : 1); + PR_fprintf( + output, "PR_ATOMIC_INCREMENT(%d) == %d: %s\n", + oldval, rv, (rv == 1) ? "PASSED" : "FAILED"); + + oldval = test = -2; + rv = PR_ATOMIC_ADD(&test,1); + result = result | ((rv == -1) ? 0 : 1); + PR_fprintf( + output, "PR_ATOMIC_ADD(%d,%d) == %d: %s\n", + oldval, 1, rv, (rv == -1) ? "PASSED" : "FAILED"); + oldval = test; + rv = PR_ATOMIC_ADD(&test, 4); + result = result | ((rv == 3) ? 0 : 1); + PR_fprintf( + output, "PR_ATOMIC_ADD(%d,%d) == %d: %s\n", + oldval, 4, rv, (rv == 3) ? "PASSED" : "FAILED"); + oldval = test; + rv = PR_ATOMIC_ADD(&test, -6); + result = result | ((rv == -3) ? 0 : 1); + PR_fprintf( + output, "PR_ATOMIC_ADD(%d,%d) == %d: %s\n", + oldval, -6, rv, (rv == -3) ? "PASSED" : "FAILED"); + + oldval = test = 2; + rv = PR_ATOMIC_DECREMENT(&test); + result = result | ((rv == 1) ? 0 : 1); + PR_fprintf( + output, "PR_ATOMIC_DECREMENT(%d) == %d: %s\n", + oldval, rv, (rv == 1) ? "PASSED" : "FAILED"); + oldval = test; + rv = PR_ATOMIC_DECREMENT(&test); + result = result | ((rv == 0) ? 0 : 1); + PR_fprintf( + output, "PR_ATOMIC_DECREMENT(%d) == %d: %s\n", + oldval, rv, (rv == 0) ? "PASSED" : "FAILED"); + oldval = test; + rv = PR_ATOMIC_DECREMENT(&test); + result = result | ((rv == -1) ? 0 : 1); + PR_fprintf( + output, "PR_ATOMIC_DECREMENT(%d) == %d: %s\n", + oldval, rv, (rv == -1) ? "PASSED" : "FAILED"); + + /* set to a different value */ + oldval = test = -2; + rv = PR_ATOMIC_SET(&test, 2); + result = result | (((rv == -2) && (test == 2)) ? 0 : 1); + PR_fprintf( + output, "PR_ATOMIC_SET(%d, %d) == %d: %s\n", + oldval, 2, rv, ((rv == -2) && (test == 2)) ? "PASSED" : "FAILED"); + + /* set to the same value */ + oldval = test = -2; + rv = PR_ATOMIC_SET(&test, -2); + result = result | (((rv == -2) && (test == -2)) ? 0 : 1); + PR_fprintf( + output, "PR_ATOMIC_SET(%d, %d) == %d: %s\n", + oldval, -2, rv, ((rv == -2) && (test == -2)) ? "PASSED" : "FAILED"); + PR_fprintf( output, "Atomic operations test %s\n", (result == 0) ? "PASSED" : "FAILED"); |