summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbrianp <brianp@13f79535-47bb-0310-9956-ffa450edef68>2003-09-25 04:37:08 +0000
committerbrianp <brianp@13f79535-47bb-0310-9956-ffa450edef68>2003-09-25 04:37:08 +0000
commitc329bc53d949a8d0bbc30b91802205244d627ca4 (patch)
treebc311967603a4552f35661d40eab1b3c33cbae80
parent550054941ed363d731770939a658a4548d4c73ec (diff)
downloadlibapr-c329bc53d949a8d0bbc30b91802205244d627ca4.tar.gz
new version of atomic API that works specifically on apr_uint32_t values for greater portability
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@64639 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--CHANGES3
-rw-r--r--atomic/unix/apr_atomic.c135
-rw-r--r--include/apr_atomic.h135
-rw-r--r--test/testatomic.c83
4 files changed, 351 insertions, 5 deletions
diff --git a/CHANGES b/CHANGES
index 7e18bfc3f..4f557127b 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,8 @@
Changes with APR 1.0
+ *) Added new versions of the apr_atomic functions for
+ use with 32-bit ints [Brian Pane]
+
*) The following deprecated interfaces have been removed:
apr_accept -> apr_socket_accept
diff --git a/atomic/unix/apr_atomic.c b/atomic/unix/apr_atomic.c
index 496f71b8c..97bbb669d 100644
--- a/atomic/unix/apr_atomic.c
+++ b/atomic/unix/apr_atomic.c
@@ -184,6 +184,139 @@ apr_uint32_t apr_atomic_cas(volatile apr_uint32_t *mem, long with, long cmp)
}
#endif /*!defined(apr_atomic_cas) && !defined(APR_OVERRIDE_ATOMIC_CAS) */
+#if !defined(apr_atomic_add32) && !defined(APR_OVERRIDE_ATOMIC_ADD32)
+void apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val)
+{
+#if APR_HAS_THREADS
+ apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
+
+ if (apr_thread_mutex_lock(lock) == APR_SUCCESS) {
+ *mem += val;
+ apr_thread_mutex_unlock(lock);
+ }
+#else
+ *mem += val;
+#endif /* APR_HAS_THREADS */
+}
+#endif /*!defined(apr_atomic_sub32) && !defined(APR_OVERRIDE_ATOMIC_SUB32) */
+
+#if !defined(apr_atomic_sub32) && !defined(APR_OVERRIDE_ATOMIC_SUB32)
+void apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val)
+{
+#if APR_HAS_THREADS
+ apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
+
+ if (apr_thread_mutex_lock(lock) == APR_SUCCESS) {
+ *mem -= val;
+ apr_thread_mutex_unlock(lock);
+ }
+#else
+ *mem -= val;
+#endif /* APR_HAS_THREADS */
+}
+#endif /*!defined(apr_atomic_sub32) && !defined(APR_OVERRIDE_ATOMIC_SUB32) */
+
+#if !defined(apr_atomic_set32) && !defined(APR_OVERRIDE_ATOMIC_SET32)
+void apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val)
+{
+#if APR_HAS_THREADS
+ apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
+
+ if (apr_thread_mutex_lock(lock) == APR_SUCCESS) {
+ *mem = val;
+ apr_thread_mutex_unlock(lock);
+ }
+#else
+ *mem = val;
+#endif /* APR_HAS_THREADS */
+}
+#endif /*!defined(apr_atomic_set32) && !defined(APR_OVERRIDE_ATOMIC_SET32) */
+
+#if !defined(apr_atomic_inc32) && !defined(APR_OVERRIDE_ATOMIC_INC32)
+void apr_atomic_inc32(volatile apr_uint32_t *mem)
+{
+#if APR_HAS_THREADS
+ apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
+
+ if (apr_thread_mutex_lock(lock) == APR_SUCCESS) {
+ (*mem)++;
+ apr_thread_mutex_unlock(lock);
+ }
+#else
+ (*mem)++;
+#endif /* APR_HAS_THREADS */
+}
+#endif /*!defined(apr_atomic_inc32) && !defined(APR_OVERRIDE_ATOMIC_INC32) */
+
+#if !defined(apr_atomic_dec32) && !defined(APR_OVERRIDE_ATOMIC_DEC32)
+int apr_atomic_dec32(volatile apr_uint32_t *mem)
+{
+#if APR_HAS_THREADS
+ apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
+ apr_uint32_t new;
+
+ if (apr_thread_mutex_lock(lock) == APR_SUCCESS) {
+ (*mem)--;
+ new = *mem;
+ apr_thread_mutex_unlock(lock);
+ return new;
+ }
+#else
+ (*mem)--;
+#endif /* APR_HAS_THREADS */
+ return *mem;
+}
+#endif /*!defined(apr_atomic_dec32) && !defined(APR_OVERRIDE_ATOMIC_DEC32) */
+
+#if !defined(apr_atomic_cas32) && !defined(APR_OVERRIDE_ATOMIC_CAS32)
+apr_uint32_t apr_atomic_cas32(volatile apr_uint32_t *mem, apr_uint32_t with,
+ apr_uint32_t cmp)
+{
+ apr_uint32_t prev;
+#if APR_HAS_THREADS
+ apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
+
+ if (apr_thread_mutex_lock(lock) == APR_SUCCESS) {
+ prev = *mem;
+ if (prev == cmp) {
+ *mem = with;
+ }
+ apr_thread_mutex_unlock(lock);
+ return prev;
+ }
+ return *mem;
+#else
+ prev = *mem;
+ if (prev == cmp) {
+ *mem = with;
+ }
+ return prev;
+#endif /* APR_HAS_THREADS */
+}
+#endif /*!defined(apr_atomic_cas32) && !defined(APR_OVERRIDE_ATOMIC_CAS32) */
+
+#if !defined(apr_atomic_xchg32) && !defined(APR_OVERRIDE_ATOMIC_XCHG32)
+apr_uint32_t apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val)
+{
+ apr_uint32_t prev;
+#if APR_HAS_THREADS
+ apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
+
+ if (apr_thread_mutex_lock(lock) == APR_SUCCESS) {
+ prev = *mem;
+ *mem = val;
+ apr_thread_mutex_unlock(lock);
+ return val;
+ }
+ return *mem;
+#else
+ prev = *mem;
+ *mem = val;
+ return prev;
+#endif /* APR_HAS_THREADS */
+}
+#endif /*!defined(apr_atomic_xchg32) && !defined(APR_OVERRIDE_ATOMIC_XCHG32) */
+
#if !defined(apr_atomic_casptr) && !defined(APR_OVERRIDE_ATOMIC_CASPTR)
void *apr_atomic_casptr(volatile void **mem, void *with, const void *cmp)
{
@@ -208,4 +341,4 @@ void *apr_atomic_casptr(volatile void **mem, void *with, const void *cmp)
return prev;
#endif /* APR_HAS_THREADS */
}
-#endif /*!defined(apr_atomic_cas) && !defined(APR_OVERRIDE_ATOMIC_CAS) */
+#endif /*!defined(apr_atomic_casptr) && !defined(APR_OVERRIDE_ATOMIC_CASPTR) */
diff --git a/include/apr_atomic.h b/include/apr_atomic.h
index eeeee07be..bf4d93943 100644
--- a/include/apr_atomic.h
+++ b/include/apr_atomic.h
@@ -104,24 +104,28 @@ apr_status_t apr_atomic_init(apr_pool_t *p);
* @param mem the pointer
* @warning on certain platforms this number is not stored
* directly in the pointer. in others it is
+ * @deprecated
*/
apr_uint32_t apr_atomic_read(volatile apr_atomic_t *mem);
/**
* set the value for atomic.
* @param mem the pointer
* @param val the value
+ * @deprecated
*/
void apr_atomic_set(volatile apr_atomic_t *mem, apr_uint32_t val);
/**
* Add 'val' to the atomic variable
* @param mem pointer to the atomic value
* @param val the addition
+ * @deprecated
*/
void apr_atomic_add(volatile apr_atomic_t *mem, apr_uint32_t val);
/**
* increment the atomic variable by 1
* @param mem pointer to the atomic value
+ * @deprecated
*/
void apr_atomic_inc(volatile apr_atomic_t *mem);
@@ -129,6 +133,7 @@ void apr_atomic_inc(volatile apr_atomic_t *mem);
* decrement the atomic variable by 1
* @param mem pointer to the atomic value
* @return zero if the value is zero, otherwise non-zero
+ * @deprecated
*/
int apr_atomic_dec(volatile apr_atomic_t *mem);
@@ -140,10 +145,76 @@ int apr_atomic_dec(volatile apr_atomic_t *mem);
* @param cmp the value to compare it to
* @return the old value of the atomic
* @warning do not mix apr_atomic's with the CAS function.
+ * @deprecated
* on some platforms they may be implemented by different mechanisms
*/
apr_uint32_t apr_atomic_cas(volatile apr_uint32_t *mem, long with, long cmp);
+
+/*
+ * Atomic operations on 32-bit values
+ * Note: Each of these functions internally implements a memory barrier
+ * on platforms that require it
+ */
+
+/**
+ * atomically read an apr_uint32_t from memory
+ * @param mem the pointer
+ */
+apr_uint32_t apr_atomic_read32(volatile apr_uint32_t *mem);
+
+/**
+ * atomically set an apr_uint32_t in memory
+ * @param mem pointer to the object
+ */
+void apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val);
+
+/**
+ * atomically add 'val' to an apr_uint32_t
+ * @param mem pointer to the object
+ * @param val amount to add
+ */
+void apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val);
+
+/**
+ * atomically subtract 'val' from an apr_uint32_t
+ * @param mem pointer to the object
+ * @param val amount to subtract
+ */
+void apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val);
+
+/**
+ * atomically increment an apr_uint32_t by 1
+ * @param mem pointer to the object
+ */
+void apr_atomic_inc32(volatile apr_uint32_t *mem);
+
+/**
+ * atomically decrement an apr_uint32_t by 1
+ * @param mem pointer to the atomic value
+ * @return zero if the value becomes zero on decrement, otherwise non-zero
+ */
+int apr_atomic_dec32(volatile apr_uint32_t *mem);
+
+/**
+ * compare an apr_uint32_t's value with 'cmp'.
+ * If they are the same swap the value with 'with'
+ * @param mem pointer to the value
+ * @param with what to swap it with
+ * @param cmp the value to compare it to
+ * @return the old value of *mem
+ */
+apr_uint32_t apr_atomic_cas32(volatile apr_uint32_t *mem, apr_uint32_t with,
+ apr_uint32_t cmp);
+
+/**
+ * exchange an apr_uint32_t's value with 'val'.
+ * @param mem pointer to the value
+ * @param val what to swap it with
+ * @return the old value of *mem
+ */
+apr_uint32_t apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val);
+
/**
* compare the pointer's value with cmp.
* If they are the same swap the value with 'with'
@@ -172,7 +243,7 @@ void *apr_atomic_casptr(volatile void **mem, void *with, const void *cmp);
#define apr_atomic_set(mem, val) InterlockedExchange(mem, val)
#define apr_atomic_read(mem) (*mem)
#define apr_atomic_cas(mem,with,cmp) InterlockedCompareExchange(mem,with,cmp)
-#define apr_atomic_init(pool) APR_SUCCESS
+ /*#define apr_atomic_init(pool) APR_SUCCESS*/
#define apr_atomic_casptr(mem,with,cmp) InterlockedCompareExchangePointer(mem,with,cmp)
#elif defined(NETWARE)
@@ -183,7 +254,7 @@ void *apr_atomic_casptr(volatile void **mem, void *with, const void *cmp);
#define apr_atomic_inc(mem) atomic_inc(mem)
#define apr_atomic_set(mem, val) (*mem = val)
#define apr_atomic_read(mem) (*mem)
-#define apr_atomic_init(pool) APR_SUCCESS
+ /*#define apr_atomic_init(pool) APR_SUCCESS*/
#define apr_atomic_cas(mem,with,cmp) atomic_cmpxchg((unsigned long *)(mem),(unsigned long)(cmp),(unsigned long)(with))
int apr_atomic_dec(apr_atomic_t *mem);
@@ -211,6 +282,12 @@ inline void *apr_atomic_casptr(void **mem, void *with, const void *cmp)
#define apr_atomic_set(mem, val) atomic_set_int(mem, val)
#define apr_atomic_read(mem) (*mem)
+#define apr_atomic_add32(mem, val) apr_atomic_add(mem, val)
+#define apr_atomic_dec32(mem) apr_atomic_dec(mem)
+#define apr_atomic_inc32(mem) apr_atomic_inc(mem)
+#define apr_atomic_set32(mem) apr_atomic_set(mem)
+#define apr_atomic_read32(mem) apr_atomic_read(mem)
+
#elif (defined(__linux__) || defined(__EMX__)) && defined(__i386__) && !APR_FORCE_ATOMIC_GENERIC
#define apr_atomic_t apr_uint32_t
@@ -228,6 +305,12 @@ inline void *apr_atomic_casptr(void **mem, void *with, const void *cmp)
: "m" (*(mem)), "r" (val) \
: "memory")
+#define apr_atomic_sub(mem, val) \
+ asm volatile ("lock; subl %1, %0" \
+ : \
+ : "m" (*(mem)), "r" (val) \
+ : "memory")
+
#define apr_atomic_dec(mem) \
({ int prev; \
asm volatile ("mov $0, %%eax;\n\t" \
@@ -247,7 +330,16 @@ inline void *apr_atomic_casptr(void **mem, void *with, const void *cmp)
#define apr_atomic_set(mem, val) (*(mem) = val)
#define apr_atomic_read(mem) (*(mem))
-#define apr_atomic_init(pool) APR_SUCCESS
+
+#define apr_atomic_cas32(mem, with, cmp) apr_atomic_cas(mem, with, cmp)
+#define apr_atomic_add32(mem, val) apr_atomic_add(mem, val)
+#define apr_atomic_sub32(mem, val) apr_atomic_sub(mem, val)
+#define apr_atomic_dec32(mem) apr_atomic_dec(mem)
+#define apr_atomic_inc32(mem) apr_atomic_inc(mem)
+#define apr_atomic_set32(mem, val) apr_atomic_set(mem, val)
+#define apr_atomic_read32(mem) apr_atomic_read(mem)
+
+/*#define apr_atomic_init(pool) APR_SUCCESS*/
#elif defined(__MVS__) /* OS/390 */
@@ -261,7 +353,7 @@ apr_uint32_t apr_atomic_cas(volatile apr_atomic_t *mem, apr_uint32_t swap,
#define apr_atomic_inc(mem) apr_atomic_add(mem, 1)
#define apr_atomic_dec(mem) apr_atomic_add(mem, -1)
-#define apr_atomic_init(pool) APR_SUCCESS
+/*#define apr_atomic_init(pool) APR_SUCCESS*/
/* warning: the following two operations, _read and _set, are atomic
* if the memory variables are aligned (the usual case).
@@ -325,6 +417,41 @@ apr_uint32_t apr_atomic_cas(volatile apr_uint32_t *mem,long with,long cmp);
#define APR_ATOMIC_NEED_DEFAULT_INIT 1
#endif
+#if !defined(apr_atomic_read32) && !defined(APR_OVERRIDE_ATOMIC_READ32)
+#define apr_atomic_read32(p) *p
+#endif
+
+#if !defined(apr_atomic_set32) && !defined(APR_OVERRIDE_ATOMIC_SET32)
+void apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val);
+#define APR_ATOMIC_NEED_DEFAULT_INIT 1
+#endif
+
+#if !defined(apr_atomic_add32) && !defined(APR_OVERRIDE_ATOMIC_ADD32)
+void apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val);
+#define APR_ATOMIC_NEED_DEFAULT_INIT 1
+#endif
+
+#if !defined(apr_atomic_inc32) && !defined(APR_OVERRIDE_ATOMIC_INC32)
+void apr_atomic_inc32(volatile apr_uint32_t *mem);
+#define APR_ATOMIC_NEED_DEFAULT_INIT 1
+#endif
+
+#if !defined(apr_atomic_dec32) && !defined(APR_OVERRIDE_ATOMIC_DEC32)
+int apr_atomic_dec32(volatile apr_uint32_t *mem);
+#define APR_ATOMIC_NEED_DEFAULT_INIT 1
+#endif
+
+#if !defined(apr_atomic_cas32) && !defined(APR_OVERRIDE_ATOMIC_CAS32)
+apr_uint32_t apr_atomic_cas32(volatile apr_uint32_t *mem, apr_uint32_t with,
+ apr_uint32_t cmp);
+#define APR_ATOMIC_NEED_DEFAULT_INIT 1
+#endif
+
+#if !defined(apr_atomic_xchg32) && !defined(APR_OVERRIDE_ATOMIC_XCHG32)
+apr_uint32_t apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val);
+#define APR_ATOMIC_NEED_DEFAULT_INIT 1
+#endif
+
#if !defined(apr_atomic_casptr) && !defined(APR_OVERRIDE_ATOMIC_CASPTR)
#if APR_SIZEOF_VOIDP == 4
#define apr_atomic_casptr(mem, with, cmp) (void *)apr_atomic_cas((apr_uint32_t *)(mem), (long)(with), (long)cmp)
diff --git a/test/testatomic.c b/test/testatomic.c
index de4669560..f7c1e9dc9 100644
--- a/test/testatomic.c
+++ b/test/testatomic.c
@@ -70,6 +70,7 @@
apr_pool_t *context;
apr_atomic_t y; /* atomic locks */
+apr_uint32_t y32;
static apr_status_t check_basic_atomics(void)
{
@@ -164,6 +165,75 @@ static apr_status_t check_basic_atomics(void)
return APR_SUCCESS;
}
+static apr_status_t check_basic_atomics32()
+{
+ apr_uint32_t oldval;
+ apr_uint32_t casval = 0;
+
+ apr_atomic_set32(&y32, 2);
+ printf("%-60s", "testing apr_atomic_dec32");
+ if (apr_atomic_dec32(&y32) == 0) {
+ fprintf(stderr, "Failed\noldval =%d should not be zero\n",
+ apr_atomic_read32(&y32));
+ return APR_EGENERAL;
+ }
+ if (apr_atomic_dec32(&y32) != 0) {
+ fprintf(stderr, "Failed\noldval =%d should be zero\n",
+ apr_atomic_read32(&y32));
+ return APR_EGENERAL;
+ }
+ printf("OK\n");
+
+ printf("%-60s", "testing apr_atomic_cas32");
+ oldval = apr_atomic_cas32(&casval, 12, 0);
+ if (oldval != 0) {
+ fprintf(stderr, "Failed\noldval =%d should be zero\n", oldval);
+ return APR_EGENERAL;
+ }
+ printf("OK\n");
+ printf("%-60s", "testing apr_atomic_cas32 - match non-null");
+ oldval = apr_atomic_cas32(&casval, 23, 12);
+ if (oldval != 12) {
+ fprintf(stderr, "Failed\noldval =%d should be 12 y=%d\n",
+ oldval, casval);
+ return APR_EGENERAL;
+ }
+ printf("OK\n");
+ printf("%-60s", "testing apr_atomic_cas32 - no match");
+ oldval = apr_atomic_cas32(&casval, 23, 12);
+ if (oldval != 23) {
+ fprintf(stderr, "Failed\noldval =%d should be 23 y=%d\n",
+ oldval, casval);
+ return APR_EGENERAL;
+ }
+ printf("OK\n");
+
+ printf("%-60s", "testing apr_atomic_add32");
+ apr_atomic_set32(&y32, 23);
+ apr_atomic_add32(&y32, 4);
+ if ((oldval = apr_atomic_read32(&y32)) != 27) {
+ fprintf(stderr,
+ "Failed\nAtomic Add doesn't add up ;( expected 27 got %d\n",
+ oldval);
+ return APR_EGENERAL;
+ }
+
+ printf("OK\n");
+ printf("%-60s", "testing add32/inc32/sub32");
+ apr_atomic_set32(&y32, 0);
+ apr_atomic_add32(&y32, 20);
+ apr_atomic_inc32(&y32);
+ apr_atomic_sub32(&y32, 10);
+ if (apr_atomic_read32(&y32) != 11) {
+ fprintf(stderr, "Failed.\natomics do not add up: expected 11 got %d\n",
+ apr_atomic_read32(&y32));
+ return APR_EGENERAL;
+ }
+ fprintf(stdout, "OK\n");
+
+ return APR_SUCCESS;
+}
+
#if !APR_HAS_THREADS
int main(void)
{
@@ -189,6 +259,12 @@ int main(void)
fprintf(stderr, "Failed.\n");
exit(-1);
}
+
+ rv = check_basic_atomics32();
+ if (rv != APR_SUCCESS) {
+ fprintf(stderr, "Failed.\n");
+ exit(-1);
+ }
return 0;
}
#else /* !APR_HAS_THREADS */
@@ -302,6 +378,13 @@ int main(int argc, char**argv)
}
apr_atomic_set(&y, 0);
+ rv = check_basic_atomics32();
+ if (rv != APR_SUCCESS) {
+ fprintf(stderr, "Failed.\n");
+ exit(-1);
+ }
+
+
printf("%-60s", "Starting all the threads");
for (i = 0; i < NUM_THREADS; i++) {
r1[i] = apr_thread_create(&t1[i], NULL,