summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwtc%google.com <devnull@localhost>2008-01-27 01:50:19 +0000
committerwtc%google.com <devnull@localhost>2008-01-27 01:50:19 +0000
commit35f3aeee25848f5708f211c7b6fc072fbf372595 (patch)
tree21a4912bb42184a9bd1ce261f1ea7d03431bcf97
parentb20b507ca0796b5d6900945b7c067ea858705c3a (diff)
downloadnspr-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.h51
-rw-r--r--pr/tests/atomic.c81
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");