Index: apr/atomic/unix/builtins.c =================================================================== --- apr.orig/atomic/unix/builtins.c +++ apr/atomic/unix/builtins.c @@ -75,4 +75,11 @@ APR_DECLARE(void*) apr_atomic_casptr(voi return (void*) __sync_val_compare_and_swap(mem, cmp, with); } +APR_DECLARE(void*) apr_atomic_xchgptr(void **mem, void *with) +{ + __sync_synchronize(); + + return __sync_lock_test_and_set(mem, with); +} + #endif /* USE_ATOMICS_BUILTINS */ Index: apr/atomic/unix/solaris.c =================================================================== --- apr.orig/atomic/unix/solaris.c +++ apr/atomic/unix/solaris.c @@ -75,4 +75,9 @@ APR_DECLARE(void*) apr_atomic_casptr(voi return atomic_cas_ptr(mem, cmp, with); } +APR_DECLARE(void*) apr_atomic_xchgptr(void **mem, void *with) +{ + return atomic_swap_ptr(mem, with); +} + #endif /* USE_ATOMICS_SOLARIS */ Index: apr/include/apr_atomic.h =================================================================== --- apr.orig/include/apr_atomic.h +++ apr/include/apr_atomic.h @@ -122,6 +122,14 @@ APR_DECLARE(apr_uint32_t) apr_atomic_xch */ APR_DECLARE(void*) apr_atomic_casptr(void **mem, void *with, 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(void **mem, void *with); + /** @} */ #ifdef __cplusplus Index: apr/atomic/unix/ia32.c =================================================================== --- apr.orig/atomic/unix/ia32.c +++ apr/atomic/unix/ia32.c @@ -120,4 +120,23 @@ APR_DECLARE(void*) apr_atomic_casptr(voi return prev; } +APR_DECLARE(void*) apr_atomic_xchgptr(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 */ Index: apr/atomic/unix/mutex.c =================================================================== --- apr.orig/atomic/unix/mutex.c +++ apr/atomic/unix/mutex.c @@ -189,4 +189,17 @@ APR_DECLARE(void*) apr_atomic_casptr(voi return prev; } +APR_DECLARE(void*) apr_atomic_xchgptr(void **mem, void *with) +{ + void *prev; + DECLARE_MUTEX_LOCKED(mutex, mem); + + prev = *mem; + *mem = with; + + MUTEX_UNLOCK(mutex); + + return prev; +} + #endif /* USE_ATOMICS_GENERIC */ Index: apr/atomic/netware/apr_atomic.c =================================================================== --- apr.orig/atomic/netware/apr_atomic.c +++ apr/atomic/netware/apr_atomic.c @@ -68,3 +68,8 @@ APR_DECLARE(void *) apr_atomic_casptr(vo { return (void*)atomic_cmpxchg((unsigned long *)mem,(unsigned long)cmp,(unsigned long)with); } + +APR_DECLARE(void*) apr_atomic_xchgptr(void **mem, void *with) +{ + return (void*)atomic_xchg((unsigned long *)mem,(unsigned long)with); +} Index: apr/atomic/unix/ppc.c =================================================================== --- apr.orig/atomic/unix/ppc.c +++ apr/atomic/unix/ppc.c @@ -204,4 +204,35 @@ APR_DECLARE(void*) apr_atomic_casptr(voi return prev; } +APR_DECLARE(void*) apr_atomic_xchgptr(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 */ Index: apr/atomic/win32/apr_atomic.c =================================================================== --- apr.orig/atomic/win32/apr_atomic.c +++ apr/atomic/win32/apr_atomic.c @@ -38,6 +38,9 @@ typedef WINBASEAPI apr_uint32_t (WINAPI typedef WINBASEAPI void * (WINAPI * apr_atomic_win32_ptr_ptr_ptr_fn) (void **, void *, const void *); +typedef WINBASEAPI void * (WINAPI * apr_atomic_win32_ptr_ptr_fn) + (void **, + void *); APR_DECLARE(apr_uint32_t) apr_atomic_add32(apr_uint32_t *mem, apr_uint32_t val) { @@ -135,3 +138,13 @@ APR_DECLARE(apr_uint32_t) apr_atomic_xch return ((apr_atomic_win32_ptr_val_fn)InterlockedExchange)(mem, val); #endif } + +APR_DECLARE(void*) apr_atomic_xchgptr(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 +} Index: apr/test/testatomic.c =================================================================== --- apr.orig/test/testatomic.c +++ apr/test/testatomic.c @@ -81,6 +81,17 @@ static void test_xchg32(abts_case *tc, v ABTS_INT_EQUAL(tc, 50, y32); } +static void test_xchgptr(abts_case *tc, void *data) +{ + int a; + 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; @@ -493,6 +504,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);