diff options
author | brianp <brianp@13f79535-47bb-0310-9956-ffa450edef68> | 2003-09-25 04:37:08 +0000 |
---|---|---|
committer | brianp <brianp@13f79535-47bb-0310-9956-ffa450edef68> | 2003-09-25 04:37:08 +0000 |
commit | c329bc53d949a8d0bbc30b91802205244d627ca4 (patch) | |
tree | bc311967603a4552f35661d40eab1b3c33cbae80 | |
parent | 550054941ed363d731770939a658a4548d4c73ec (diff) | |
download | libapr-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-- | CHANGES | 3 | ||||
-rw-r--r-- | atomic/unix/apr_atomic.c | 135 | ||||
-rw-r--r-- | include/apr_atomic.h | 135 | ||||
-rw-r--r-- | test/testatomic.c | 83 |
4 files changed, 351 insertions, 5 deletions
@@ -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, |