From 7a5041b7a7cc8dd973f356e53d979cc8cd7c64ed Mon Sep 17 00:00:00 2001 From: davi Date: Tue, 10 Jul 2007 16:35:45 +0000 Subject: Introduce apr_atomic_xchgptr, which atomically exchanges a pair of pointer values. Missing OS/390 implementation. git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@554995 13f79535-47bb-0310-9956-ffa450edef68 --- atomic/netware/apr_atomic.c | 5 +++++ atomic/unix/builtins.c | 7 +++++++ atomic/unix/ia32.c | 19 +++++++++++++++++++ atomic/unix/mutex.c | 13 +++++++++++++ atomic/unix/ppc.c | 31 +++++++++++++++++++++++++++++++ atomic/unix/s390.c | 23 +++++++++++++++++++++++ atomic/unix/solaris.c | 5 +++++ atomic/win32/apr_atomic.c | 13 +++++++++++++ include/apr_atomic.h | 8 ++++++++ test/testatomic.c | 12 ++++++++++++ 10 files changed, 136 insertions(+) diff --git a/atomic/netware/apr_atomic.c b/atomic/netware/apr_atomic.c index 94a354977..b5d965b09 100644 --- a/atomic/netware/apr_atomic.c +++ b/atomic/netware/apr_atomic.c @@ -68,3 +68,8 @@ APR_DECLARE(void *) apr_atomic_casptr(volatile void **mem, void *with, const voi { return (void*)atomic_cmpxchg((unsigned long *)mem,(unsigned long)cmp,(unsigned long)with); } + +APR_DECLARE(void*) apr_atomic_xchgptr(volatile void **mem, void *with) +{ + return (void*)atomic_xchg((unsigned long *)mem,(unsigned long)with); +} diff --git a/atomic/unix/builtins.c b/atomic/unix/builtins.c index 274599614..745acf155 100644 --- a/atomic/unix/builtins.c +++ b/atomic/unix/builtins.c @@ -71,4 +71,11 @@ APR_DECLARE(void*) apr_atomic_casptr(volatile void **mem, void *with, const void return (void*) __sync_val_compare_and_swap(mem, cmp, with); } +APR_DECLARE(void*) apr_atomic_xchgptr(volatile void **mem, void *with) +{ + __sync_synchronize(); + + return (void*) __sync_lock_test_and_set(mem, with); +} + #endif /* USE_ATOMICS_BUILTINS */ diff --git a/atomic/unix/ia32.c b/atomic/unix/ia32.c index bcf9d5661..191298c4a 100644 --- a/atomic/unix/ia32.c +++ b/atomic/unix/ia32.c @@ -108,4 +108,23 @@ APR_DECLARE(void*) apr_atomic_casptr(volatile void **mem, void *with, const void return prev; } +APR_DECLARE(void*) apr_atomic_xchgptr(volatile void **mem, void *with) +{ + void *prev; +#if APR_SIZEOF_VOIDP == 4 + asm volatile ("lock; xchgl %2, %1" + : "=a" (prev), "=m" (*mem) + : "r" (with), "m" (*mem) + : "memory"); +#elif APR_SIZEOF_VOIDP == 8 + asm volatile ("lock; xchgq %q2, %1" + : "=a" (prev), "=m" (*mem) + : "r" ((unsigned long)with), "m" (*mem) + : "memory"); +#else +#error APR_SIZEOF_VOIDP value not supported +#endif + return prev; +} + #endif /* USE_ATOMICS_IA32 */ diff --git a/atomic/unix/mutex.c b/atomic/unix/mutex.c index 17b605fcd..cb23ede34 100644 --- a/atomic/unix/mutex.c +++ b/atomic/unix/mutex.c @@ -189,4 +189,17 @@ APR_DECLARE(void*) apr_atomic_casptr(volatile void **mem, void *with, const void return prev; } +APR_DECLARE(void*) apr_atomic_xchgptr(volatile void **mem, void *with) +{ + void *prev; + DECLARE_MUTEX_LOCKED(mutex, mem); + + prev = *mem; + *mem = with; + + MUTEX_UNLOCK(mutex); + + return prev; +} + #endif /* USE_ATOMICS_GENERIC */ diff --git a/atomic/unix/ppc.c b/atomic/unix/ppc.c index 149347eae..d7673d5ee 100644 --- a/atomic/unix/ppc.c +++ b/atomic/unix/ppc.c @@ -175,4 +175,35 @@ APR_DECLARE(void*) apr_atomic_casptr(volatile void **mem, void *with, const void return prev; } +APR_DECLARE(void*) apr_atomic_xchgptr(volatile void **mem, void *with) +{ + void *prev; +#if APR_SIZEOF_VOIDP == 4 + asm volatile (PPC_SYNC + "loop_%=:\n" /* lost reservation */ + " lwarx %0,0,%1\n" /* load and reserve */ + PPC405_ERR77_SYNC /* ppc405 Erratum 77 */ + " stwcx. %2,0,%1\n" /* store new value */ + " bne- loop_%=\n" /* loop if lost */ + " isync\n" /* memory barrier */ + : "=&r" (prev) + : "b" (mem), "r" (with) + : "cc", "memory"); +#elif APR_SIZEOF_VOIDP == 8 + asm volatile (PPC_SYNC + "loop_%=:\n" /* lost reservation */ + " ldarx %0,0,%1\n" /* load and reserve */ + PPC405_ERR77_SYNC /* ppc405 Erratum 77 */ + " stdcx. %2,0,%1\n" /* store new value */ + " bne- loop_%=\n" /* loop if lost */ + " isync\n" /* memory barrier */ + : "=&r" (prev) + : "b" (mem), "r" (with) + : "cc", "memory"); +#else +#error APR_SIZEOF_VOIDP value not supported +#endif + return prev; +} + #endif /* USE_ATOMICS_PPC */ diff --git a/atomic/unix/s390.c b/atomic/unix/s390.c index a81ffdd16..3e2332077 100644 --- a/atomic/unix/s390.c +++ b/atomic/unix/s390.c @@ -129,4 +129,27 @@ APR_DECLARE(void*) apr_atomic_casptr(volatile void **mem, void *with, const void return prev; } +APR_DECLARE(void*) apr_atomic_xchgptr(volatile void **mem, void *with) +{ + void *prev = (void *) *mem; +#if APR_SIZEOF_VOIDP == 4 + asm volatile ("loop_%=:\n" + " cs %0,%2,%1\n" + " jl loop_%=\n" + : "+d" (prev), "=Q" (*mem) + : "d" (with), "m" (*mem) + : "cc", "memory"); +#elif APR_SIZEOF_VOIDP == 8 + asm volatile ("loop_%=:\n" + " csg %0,%2,%1\n" + " jl loop_%=\n" + : "+d" (prev), "=Q" (*mem) + : "d" (with), "m" (*mem) + : "cc", "memory"); +#else +#error APR_SIZEOF_VOIDP value not supported +#endif + return prev; +} + #endif /* USE_ATOMICS_S390 */ diff --git a/atomic/unix/solaris.c b/atomic/unix/solaris.c index f74a7ef2d..ba544522f 100644 --- a/atomic/unix/solaris.c +++ b/atomic/unix/solaris.c @@ -71,4 +71,9 @@ APR_DECLARE(void*) apr_atomic_casptr(volatile void **mem, void *with, const void return atomic_cas_ptr(mem, cmp, with); } +APR_DECLARE(void*) apr_atomic_xchgptr(volatile void **mem, void *with) +{ + return atomic_swap_ptr(mem, with); +} + #endif /* USE_ATOMICS_SOLARIS */ diff --git a/atomic/win32/apr_atomic.c b/atomic/win32/apr_atomic.c index e88f2e256..44e8ca2dd 100644 --- a/atomic/win32/apr_atomic.c +++ b/atomic/win32/apr_atomic.c @@ -38,6 +38,9 @@ typedef WINBASEAPI apr_uint32_t (WINAPI * apr_atomic_win32_ptr_val_val_fn) typedef WINBASEAPI void * (WINAPI * apr_atomic_win32_ptr_ptr_ptr_fn) (volatile void **, void *, const void *); +typedef WINBASEAPI void * (WINAPI * apr_atomic_win32_ptr_ptr_fn) + (volatile void **, + void *); APR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val) { @@ -135,3 +138,13 @@ APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint return ((apr_atomic_win32_ptr_val_fn)InterlockedExchange)(mem, val); #endif } + +APR_DECLARE(void*) apr_atomic_xchgptr(volatile void **mem, void *with) +{ +#if (defined(_M_IA64) || defined(_M_AMD64) || defined(__MINGW32__)) && !defined(RC_INVOKED) + return InterlockedExchangePointer((void**)mem, with); +#else + /* Too many VC6 users have stale win32 API files, stub this */ + return ((apr_atomic_win32_ptr_ptr_fn)InterlockedExchangePointer)(mem, with); +#endif +} diff --git a/include/apr_atomic.h b/include/apr_atomic.h index 714780fe5..60e4bb54d 100644 --- a/include/apr_atomic.h +++ b/include/apr_atomic.h @@ -123,6 +123,14 @@ APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint */ APR_DECLARE(void*) apr_atomic_casptr(volatile void **mem, void *with, const void *cmp); +/** + * exchange a pair of pointer values + * @param mem pointer to the pointer + * @param with what to swap it with + * @return the old value of the pointer + */ +APR_DECLARE(void*) apr_atomic_xchgptr(volatile void **mem, void *with); + /** @} */ #ifdef __cplusplus diff --git a/test/testatomic.c b/test/testatomic.c index b9fe6279d..0d09d004e 100644 --- a/test/testatomic.c +++ b/test/testatomic.c @@ -81,6 +81,17 @@ static void test_xchg32(abts_case *tc, void *data) ABTS_INT_EQUAL(tc, 50, y32); } +static void test_xchgptr(abts_case *tc, void *data) +{ + int a; + volatile void *target_ptr = NULL; + void *old_ptr; + + old_ptr = apr_atomic_xchgptr(&target_ptr, &a); + ABTS_PTR_EQUAL(tc, NULL, old_ptr); + ABTS_PTR_EQUAL(tc, &a, (void *) target_ptr); +} + static void test_cas_equal(abts_case *tc, void *data) { apr_uint32_t casval = 0; @@ -489,6 +500,7 @@ abts_suite *testatomic(abts_suite *suite) abts_run_test(suite, test_read32, NULL); abts_run_test(suite, test_dec32, NULL); abts_run_test(suite, test_xchg32, NULL); + abts_run_test(suite, test_xchgptr, NULL); abts_run_test(suite, test_cas_equal, NULL); abts_run_test(suite, test_cas_equal_nonnull, NULL); abts_run_test(suite, test_cas_notequal, NULL); -- cgit v1.2.1