apr-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Colin <share-apa...@think42.com>
Subject Re: various atomic operations
Date Fri, 20 Oct 2006 15:35:47 GMT
On Thu, Oct 19, 2006 at 05:04:12PM -0700, Garrett Rooney wrote:
> On 10/19/06, Colin <share-apache@think42.com> wrote:
> >Hi Again,
> >
> >I have finally found a few minutes to write down all issues that I
> >found in apr_atomic.c ... I would now like to know whether, and
> >for which of the points, there is interest in further discussion
> >and/or finally a patch.
> 
> If you actually have patches to correct whatever problems there are,
> then great, send them in.  You're considerably more likely to get a
> response from an actual patch (preferably that fixes one specific
> problem) than by just describing the problem.

Ok ... below is the output of 'svn diff', and attached is a .tgz with
the diff and the two changed files. Nothing else was touched yet, as
it is probably better to wait which changes actually get accepted.
Please feel free to ask about any details of the changes... A brief
list of changed points, and other relevant notes, is at the head of
the .c file.

Regards, Colin


Index: atomic/unix/apr_atomic.c
===================================================================
--- atomic/unix/apr_atomic.c	(revision 466020)
+++ atomic/unix/apr_atomic.c	(working copy)
@@ -21,60 +21,235 @@
 #include "apr_private.h"
 
 #include <stdlib.h>
-#if (defined(SOLARIS2) && SOLARIS2 >= 10)
-#include <atomic.h>
-#endif
 
-#if defined(__GNUC__) && defined(__STRICT_ANSI__) && !defined(USE_GENERIC_ATOMICS)
+
+/* This note is by Colin Hirsch <share-apache@think42.com>
+
+   Changes:
+   - Added atomic primitives for Darwin/Mac OS X; these require
+     Mac OS 10.4 or higher, and therefore a change to the build
+     system to detect these cases and define a symbol similar to
+     how SOLARIS2 is defined.
+   - Removed 'volatile' from all prototypes; memory objects are
+     not volatile: accesses are. Note that for apr_atomic_casptr
+     the volatile was completely bogus since it declared the
+     pointee of the pointee volatile; in all other cases the
+     volatile is not, in general, sufficient, and leads to code
+     pessimisation in the no-thread case.
+   - Similarly 'const void *cmp' for the third argument of
+     apr_atomic_casptr is bogus since it again declares the
+     pointee const.
+   - Added apr_atomic_read32 for i386 and x86-64.
+   - Changed operating-system dependent include files to be
+     included only when needed.
+   - Added #if !defined to all specific implementations.
+   - Added apr_atomic_casptr for Solaris 10 implementation.
+   - Moved !APR_HAS_THREADS implementations to top of file,
+     "out of the way"...
+   - Replaced the additional USE_GENERIC_ATOMICS define
+     by the more aptly named FORBID_INLINE_ASSEMBLER and
+     changed to appropriate use of these two macros.
+   - Added implementation of PowerPC atomic read and set.
+   - Added Darwin implementations of all atomic operations.
+   - Fixed the Solaris 10 implementations to use the _nv
+     variants wherever necessary.
+   - Added memory barriers to Solaris 10 read32/set32.
+   - Added Solaris 10 add32/sub32 implementations.
+   - Changed generic implementations to force consistent
+     per-object locking by either only using the mutex,
+     or only using cas32/read32 (whenever available).
+   - Changed num_atomic_hash from macro to constant.
+   - Renamed CHECK macro to APR_CHECK; less likely collisions.
+   - Split the generic mutex implementations from the generic
+     implementations that use cas32/read32.
+   - Added Sparc v9 implementations of read32/set32/cas32.
+
+   Notes:
+   - This version was tested on the following systems:
+   - The Sparc assembler implementations require a Sparc v9 and,
+     on older GCCs, also an appropriate compile switch; requires
+     changes to the build system for detecting the cpu type, and
+     passing -mcpu=v9 to the compiler.
+   - The Darwin implementations require Mac OS X 10.4 or greater;
+     the build system must be changed to set the DARWIN macro to
+     some value that can then be tested in this file...
+   - Building on Solaris 8 initially failed because a getpass()
+     function was redefined in the apr source.
+   - Testing on Linux initially had USE_GENERIC_ATOMICS defined,
+     I am no expert on automake/autoconf etc. so I can't tell why.
+   - Mixing atomic functions that use a mutex, and atomic
+     functions that use assembler or other 'direct' locking, is NOT
+     in general safe.
+   - For the consistent locking to work, every specific implementation
+     MUST either provide both cas32 and read32, or MUST be completely
+     removed.
+   - The PowerPC inline implemenations can produce livelocks:
+http://www-306.ibm.com/chips/techlib/techlib.nsf/techdocs/79B6E24422AA101287256E93006C957E/$file/PowerPC_970FX_errata_DD3.X_V1.7.pdf
+
+   Tested:
+   A test consisted of compiling apr and running testatomic.
+   - 4-way PPC 970/Apple GCC 5363/Darwin 8.8.0/32bit
+   - 8-way UltraSparc II/GCC 4.0.2/Solaris 8/32bit
+     (requires CFLAGS="-mcpu=v9" ./configure)
+   - 2/4-way Intel Xeon/GCC 4.0.2/Linux 2.4.20-8smp/32bit
+*/
+
+
+#if !defined(APR_HAS_THREADS)
+
+/*****************************************/
+
+APR_DECLARE(apr_status_t) apr_atomic_init(apr_pool_t *p)
+{
+   return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_uint32_t) apr_atomic_read32(apr_uint32_t *mem)
+{
+   return *mem;
+}
+
+APR_DECLARE(void) apr_atomic_set32(apr_uint32_t *mem, apr_uint32_t val)
+{
+   *mem = val;
+}
+
+APR_DECLARE(apr_uint32_t) apr_atomic_add32(apr_uint32_t *mem, apr_uint32_t val)
+{
+   apr_uint32_t nrv = *mem;
+   *mem += val;
+   return nrv;
+}
+
+APR_DECLARE(void) apr_atomic_sub32(apr_uint32_t *mem, apr_uint32_t val)
+{
+   *mem -= val;
+}
+
+APR_DECLARE(apr_uint32_t) apr_atomic_inc32(apr_uint32_t *mem)
+{
+   apr_uint32_t nrv = *mem;
+   ++*mem;
+   return nrv;
+}
+
+APR_DECLARE(int) apr_atomic_dec32(apr_uint32_t *mem)
+{
+   return --*mem;
+}
+
+APR_DECLARE(apr_uint32_t) apr_atomic_cas32(apr_uint32_t *mem,
+                                           apr_uint32_t with,
+                                           apr_uint32_t cmp)
+{
+   apr_uint32_t nrv = *mem;
+
+   if (nrv == cmp)
+      *mem = with;
+
+   return nrv;
+}
+
+APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(apr_uint32_t *mem,
+                                            apr_uint32_t val)
+{
+   apr_uint32_t nrv = *mem;
+   *mem = val;
+   return nrv;
+}
+
+APR_DECLARE(void*) apr_atomic_casptr(void **mem,
+                                     void *with,
+                                     void *cmp)
+{
+   void *nrv = *mem;
+
+   if (nrv == cmp)
+      *mem = with;
+
+   return nrv;
+}
+
+#else /* APR_HAS_THREADS */
+
+/*****************************************/
+
+#if (defined(__GNUC__) && defined(__STRICT_ANSI__)) || defined(USE_GENERIC_ATOMICS)
 /* force use of generic atomics if building e.g. with -std=c89, which
  * doesn't allow inline asm */
-#define USE_GENERIC_ATOMICS
+#define FORBID_INLINE_ASSEMBLER
 #endif
 
+/*****************************************/
+
 #if (defined(__i386__) || defined(__x86_64__)) \
-    && defined(__GNUC__) && !defined(USE_GENERIC_ATOMICS)
+    && defined(__GNUC__) && !defined(FORBID_INLINE_ASSEMBLER)
 
-APR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t *mem, 
+#if !defined(APR_OVERRIDE_ATOMIC_READ32)
+APR_DECLARE(apr_uint32_t) apr_atomic_read32(apr_uint32_t *mem)
+{
+   return *(volatile apr_uint32_t *)mem;
+}
+#define APR_OVERRIDE_ATOMIC_READ32
+#endif
+
+#if !defined(APR_OVERRIDE_ATOMIC_SET32)
+APR_DECLARE(void) apr_atomic_set32(apr_uint32_t *mem,
+                                   apr_uint32_t val)
+{
+   *(volatile apr_uint32_t *)mem = val;
+}
+#define APR_OVERRIDE_ATOMIC_SET32
+#endif
+
+#if !defined(APR_OVERRIDE_ATOMIC_CAS32)
+APR_DECLARE(apr_uint32_t) apr_atomic_cas32(apr_uint32_t *mem, 
                                            apr_uint32_t with,
                                            apr_uint32_t cmp)
 {
     apr_uint32_t prev;
 
-    asm volatile ("lock; cmpxchgl %1, %2"             
-                  : "=a" (prev)               
-                  : "r" (with), "m" (*(mem)), "0"(cmp) 
+    asm volatile ("lock; cmpxchgl %1,%2"
+                  : "=a" (prev)
+                  : "r" (with), "m" (*mem), "0"(cmp) 
                   : "memory", "cc");
     return prev;
 }
 #define APR_OVERRIDE_ATOMIC_CAS32
+#endif
 
-static apr_uint32_t inline intel_atomic_add32(volatile apr_uint32_t *mem, 
+static apr_uint32_t inline intel_atomic_add32(apr_uint32_t *mem, 
                                               apr_uint32_t val)
 {
     asm volatile ("lock; xaddl %0,%1"
-                  : "=r"(val), "=m"(*mem) /* outputs */
-                  : "0"(val), "m"(*mem)   /* inputs */
+                  : "=r"(val), "=m"(*mem)
+                  : "0"(val), "m"(*mem)
                   : "memory", "cc");
     return val;
 }
 
-APR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem, 
+#if !defined(APR_OVERRIDE_ATOMIC_ADD32)
+APR_DECLARE(apr_uint32_t) apr_atomic_add32(apr_uint32_t *mem, 
                                            apr_uint32_t val)
 {
     return intel_atomic_add32(mem, val);
 }
 #define APR_OVERRIDE_ATOMIC_ADD32
+#endif
 
-APR_DECLARE(void) apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val)
+#if !defined(APR_OVERRIDE_ATOMIC_SUB32)
+APR_DECLARE(void) apr_atomic_sub32(apr_uint32_t *mem, apr_uint32_t val)
 {
-    asm volatile ("lock; subl %1, %0"
+    asm volatile ("lock; subl %1,%0"
                   :
-                  : "m" (*(mem)), "r" (val)
+                  : "m" (*mem), "r" (val)
                   : "memory", "cc");
 }
 #define APR_OVERRIDE_ATOMIC_SUB32
+#endif
 
-APR_DECLARE(int) apr_atomic_dec32(volatile apr_uint32_t *mem)
+#if !defined(APR_OVERRIDE_ATOMIC_DEC32)
+APR_DECLARE(int) apr_atomic_dec32(apr_uint32_t *mem)
 {
     unsigned char prev;
 
@@ -86,39 +261,100 @@
     return prev;
 }
 #define APR_OVERRIDE_ATOMIC_DEC32
+#endif
 
-APR_DECLARE(apr_uint32_t) apr_atomic_inc32(volatile apr_uint32_t *mem)
+#if !defined(APR_OVERRIDE_ATOMIC_INC32)
+APR_DECLARE(apr_uint32_t) apr_atomic_inc32(apr_uint32_t *mem)
 {
     return intel_atomic_add32(mem, 1);
 }
 #define APR_OVERRIDE_ATOMIC_INC32
+#endif
 
-APR_DECLARE(void) apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val)
+#if !defined(APR_OVERRIDE_ATOMIC_XCHG32)
+APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(apr_uint32_t *mem, apr_uint32_t val)
 {
-    *mem = val;
-}
-#define APR_OVERRIDE_ATOMIC_SET32
-
-APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val)
-{
     apr_uint32_t prev = val;
 
     asm volatile ("lock; xchgl %0, %1"
                   : "=r" (prev)
-                  : "m" (*(mem)), "0"(prev)
+                  : "m" (*mem), "0"(prev)
                   : "memory");
     return prev;
 }
 #define APR_OVERRIDE_ATOMIC_XCHG32
+#endif
 
-/*#define apr_atomic_init(pool)        APR_SUCCESS*/
+#endif /* __i386__ || __x86_64__ && __GNUC__ */
 
-#endif /* (__linux__ || __EMX__ || __FreeBSD__) && __i386__ */
+/*****************************************/
 
-#if (defined(__PPC__) || defined(__ppc__)) && defined(__GNUC__) \
-    && !defined(USE_GENERIC_ATOMICS)
+#if defined(__sparc__) && defined(__GNUC__)     \
+      && !defined(FORBID_INLINE_ASSEMBLER)
 
-APR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t *mem,
+#if !defined(APR_OVERRIDE_ATOMIC_READ32)
+APR_DECLARE(apr_uint32_t) apr_atomic_read32(apr_uint32_t *mem)
+{
+   asm volatile( "membar #StoreLoad | #LoadLoad" : : : "memory" );
+   return *(volatile apr_uint32_t*)mem;
+}
+#define APR_OVERRIDE_ATOMIC_READ32
+#endif
+
+#if !defined(APR_OVERRIDE_ATOMIC_SET32)
+APR_DECLARE(void) apr_atomic_set32(apr_uint32_t *mem, apr_uint32_t val)
+{
+   *(volatile apr_uint32_t*)mem = val;
+   asm volatile( "membar #StoreStore | #StoreLoad" : : : "memory" );
+}
+#define APR_OVERRIDE_ATOMIC_SET32
+#endif
+
+#if !defined(APR_OVERRIDE_ATOMIC_CAS32)
+APR_DECLARE(apr_uint32_t) apr_atomic_cas32(apr_uint32_t *mem,
+                                           apr_uint32_t with,
+                                           apr_uint32_t cmp)
+{
+   apr_uint32_t prev;
+
+   asm volatile( "cas [%1],%2,%0"
+                 : "=r" (prev)
+                 : "r" (mem), "r" (cmp), "0" (with)
+                 : "memory" );
+
+   return prev;
+}
+#define APR_OVERRIDE_ATOMIC_CAS32
+#endif
+
+#endif /* defined(__sparc__) && defined(__GNUC__)
+          && !defined(FORBID_INLINE_ASSEMBLER) */
+
+/*****************************************/
+
+#if defined(__POWERPC__ ) && defined(__GNUC__) \
+   && !defined(FORBID_INLINE_ASSEMBLER)
+
+#if !defined(APR_OVERRIDE_ATOMIC_READ32)
+APR_DECLARE(apr_uint32_t) apr_atomic_read32(apr_uint32_t *mem)
+{
+   asm volatile ("sync" ::: "memory" );
+   return *(volatile apr_uint32_t*)mem;
+}
+#define APR_OVERRIDE_ATOMIC_READ32
+#endif
+
+#if !defined(APR_OVERRIDE_ATOMIC_SET32)
+APR_DECLARE(void) apr_atomic_set32(apr_uint32_t *mem, apr_uint32_t val)
+{
+   *(volatile apr_uint32_t*)mem = val;
+   asm volatile ("sync" ::: "memory" );
+}
+#define APR_OVERRIDE_ATOMIC_SET32
+#endif
+
+#if !defined(APR_OVERRIDE_ATOMIC_CAS32)
+APR_DECLARE(apr_uint32_t) apr_atomic_cas32(apr_uint32_t *mem,
                                            apr_uint32_t swap,
                                            apr_uint32_t cmp)
 {
@@ -140,8 +376,10 @@
     return prev;
 }
 #define APR_OVERRIDE_ATOMIC_CAS32
+#endif
 
-APR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem,
+#if !defined(APR_OVERRIDE_ATOMIC_ADD32)
+APR_DECLARE(apr_uint32_t) apr_atomic_add32(apr_uint32_t *mem,
                                            apr_uint32_t delta)
 {
     apr_uint32_t prev, temp;
@@ -162,14 +400,122 @@
     return prev;
 }
 #define APR_OVERRIDE_ATOMIC_ADD32
+#endif
 
-#endif /* __PPC__ && __GNUC__ */
+#endif /* __POWERPC__ */
 
+/*****************************************/
+
+// DARWIN >= 4
+#if defined(DARWIN) && !defined(USE_GENERIC_ATOMICS)
+
+#include <inttypes.h>
+#include <libkern/OSAtomic.h>
+
+#if !defined(APR_OVERRIDE_ATOMIC_READ32)
+APR_DECLARE(apr_uint32_t) apr_atomic_read32(apr_uint32_t *mem)
+{
+   OSMemoryBarrier();
+   return *(volatile apr_uint32_t*)mem;
+}
+#define APR_OVERRIDE_ATOMIC_READ32
+#endif
+
+#if !defined(APR_OVERRIDE_ATOMIC_SET32)
+APR_DECLARE(void) apr_atomic_set32(apr_uint32_t *mem, apr_uint32_t val)
+{
+   *(volatile apr_uint32_t*)mem = val;
+   OSMemoryBarrier();
+}
+#define APR_OVERRIDE_ATOMIC_SET32
+#endif
+
+#if !defined(APR_OVERRIDE_ATOMIC_ADD32)
+APR_DECLARE(apr_uint32_t) apr_atomic_add32(apr_uint32_t *mem, apr_uint32_t val)
+{
+   return OSAtomicAdd32(val, (int32_t *)mem) - val;
+}
+#define APR_OVERRIDE_ATOMIC_ADD32
+#endif
+
+#if !defined(APR_OVERRIDE_ATOMIC_SUB32)
+APR_DECLARE(void) apr_atomic_sub32(apr_uint32_t *mem, apr_uint32_t val)
+{
+   OSAtomicAdd32(-val, (int32_t *)mem);
+}
+#define APR_OVERRIDE_ATOMIC_SUB32
+#endif
+
+#if !defined(APR_OVERRIDE_ATOMIC_INC32)
+APR_DECLARE(apr_uint32_t) apr_atomic_inc32(apr_uint32_t *mem)
+{
+   return apr_atomic_add32(mem, 1);
+}
+#define APR_OVERRIDE_ATOMIC_INC32
+#endif
+
+#if !defined(APR_OVERRIDE_ATOMIC_DEC32)
+APR_DECLARE(int) apr_atomic_dec32(apr_uint32_t *mem)
+{
+   return OSAtomicAdd32(0xffffffff, (int32_t *)mem);
+}
+#define APR_OVERRIDE_ATOMIC_DEC32
+#endif
+
+/* Apple's OSAtomicCompareAndSwap is a pain because it doesn't
+   return the old value, which is however needed for the return
+   value of apr_atomic_cas32 if the compare fails...
+   The following implementation is ugly as hell, but should
+   never be used as long as the PowerPC and i386/x86_64 versions
+   are kept above.
+*/
+
+#if !defined(APR_OVERRIDE_ATOMIC_CAS32)
+APR_DECLARE(apr_uint32_t) apr_atomic_cas32(apr_uint32_t *mem,
+                                           apr_uint32_t with,
+                                           apr_uint32_t cmp)
+{
+   apr_uint32_t tmp;
+
+   do {
+      if (OSAtomicCompareAndSwap32(cmp, with, (int32_t *)mem))
+         return cmp;
+      else if ((tmp = apr_atomic_read32(mem)) == with)
+         return cmp;  /* pretend */
+
+   } while ( tmp == cmp );
+
+   return tmp;
+}
+#define APR_OVERRIDE_ATOMIC_CAS32
+#endif
+
+#if !defined(APR_OVERRIDE_ATOMIC_XCHG32)
+APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(apr_uint32_t *mem,
+                                            apr_uint32_t val)
+{
+   apr_uint32_t tmp;
+
+   do {
+      tmp = apr_atomic_read32(mem);
+   } while (!OSAtomicCompareAndSwap32(tmp, val, (int32_t *)mem));
+
+   return tmp;
+}
+#define APR_OVERRIDE_ATOMIC_XCHG32
+#endif
+
+#endif /* DARWIN && DARWIN >= 4 */
+
+/*****************************************/
+
 #if (defined(SOLARIS2) && SOLARIS2 >= 10) \
     && !defined(USE_GENERIC_ATOMICS)
 
+#include <atomic.h>
+
 #if !defined(APR_OVERRIDE_ATOMIC_CAS32)
-APR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t *mem,
+APR_DECLARE(apr_uint32_t) apr_atomic_cas32(apr_uint32_t *mem,
                                            apr_uint32_t with,
                                            apr_uint32_t cmp)
 {
@@ -178,36 +524,60 @@
 #define APR_OVERRIDE_ATOMIC_CAS32
 #endif /* APR_OVERRIDE_ATOMIC_CAS32 */
 
+#if !defined(APR_OVERRIDE_ATOMIC_ADD32)
+APR_DECLARE(apr_uint32_t) apr_atomic_add32(apr_uint32_t *mem,
+                                           apr_uint32_t val)
+{
+   return atomic_add_32_nv(mem, val) - val;
+}
+#define APR_OVERRIDE_ATOMIC_ADD32
+#endif
+
+#if !defined(APR_OVERRIDE_ATOMIC_SUB32)
+APR_DECLARE(void) apr_atomic_sub32(apr_uint32_t *mem,
+                                   apr_uint32_t val)
+{
+   atomic_add_32(mem, -val);
+}
+#define APR_OVERRIDE_ATOMIC_SUB32
+#endif
+
 #if !defined(APR_OVERRIDE_ATOMIC_DEC32)
-APR_DECLARE(int) apr_atomic_dec32(volatile apr_uint32_t *mem)
+APR_DECLARE(int) apr_atomic_dec32(apr_uint32_t *mem)
 {
-    apr_uint32_t prev = *mem;
-    atomic_dec_32(mem);
-    return prev != 1;
+   return atomic_dec_32_nv(mem);
 }
 #define APR_OVERRIDE_ATOMIC_DEC32
 #endif /* APR_OVERRIDE_ATOMIC_DEC32 */
 
 #if !defined(APR_OVERRIDE_ATOMIC_INC32)
-APR_DECLARE(apr_uint32_t) apr_atomic_inc32(volatile apr_uint32_t *mem)
+APR_DECLARE(apr_uint32_t) apr_atomic_inc32(apr_uint32_t *mem)
 {
-    apr_uint32_t prev = *mem;
-    atomic_inc_32(mem);
-    return prev;
+    return atomic_inc_32_nv(mem) - 1;
 }
 #define APR_OVERRIDE_ATOMIC_INC32
 #endif /* APR_OVERRIDE_ATOMIC_INC32 */
 
+#if !defined(APR_OVERRIDE_ATOMIC_READ32)
+APR_DECLARE(apr_uint32_t) apr_atomic_read32(apr_uint32_t *mem)
+{
+   membar_enter();
+   return *(volatile apr_uint32_t *)mem;
+}
+#define APR_OVERRIDE_ATOMIC_READ32
+#endif
+
 #if !defined(APR_OVERRIDE_ATOMIC_SET32)
-APR_DECLARE(void) apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val)
+APR_DECLARE(void) apr_atomic_set32(apr_uint32_t *mem, apr_uint32_t val)
 {
-    *mem = val;
+   *(volatile apr_uint32_t *)mem = val;
+   membar_exit();
 }
 #define APR_OVERRIDE_ATOMIC_SET32
 #endif /* APR_OVERRIDE_ATOMIC_SET32 */
 
 #if !defined(APR_OVERRIDE_ATOMIC_XCHG32)
-APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(volatile apr_uint32_t *mem,
+APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(apr_uint32_t *mem,
                                             apr_uint32_t val) 
 {
     return atomic_swap_32(mem, val);
@@ -215,234 +585,281 @@
 #define APR_OVERRIDE_ATOMIC_XCHG32
 #endif /* APR_OVERRIDE_ATOMIC_XCHG32 */
 
+#if !define(APR_OVERRIDE_ATOMIC_CASPTR)
+APR_DECLARE(void*) apr_atomic_casptr(void **mem,
+                                     void *with,
+                                     void *cmp)
+{
+   return atomic_cas_ptr(mem, cmp, with);
+}
+#define APR_OVERRIDE_ATOMIC_CASPTR
+#endif
+
 #endif /* SOLARIS2 && SOLARIS2 >= 10 */
 
-#if !defined(APR_OVERRIDE_ATOMIC_INIT)
+/*****************************************/
 
-#if APR_HAS_THREADS
-#define NUM_ATOMIC_HASH 7
-/* shift by 2 to get rid of alignment issues */
-#define ATOMIC_HASH(x) (unsigned int)(((unsigned long)(x)>>2)%(unsigned int)NUM_ATOMIC_HASH)
+#if defined(APR_OVERRIDE_ATOMIC_INIT)
+#error Unallowed definition of apr_atomic_init.
+#endif
+
+#if defined(APR_OVERRIDE_ATOMIC_CAS32) && !defined(APR_OVERRIDE_ATOMIC_READ32)
+#error Inconsistent set of functions defined.
+#endif
+
+#if !defined(APR_OVERRIDE_ATOMIC_CAS32) && defined(APR_OVERRIDE_ATOMIC_READ32)
+#error Inconsistent set of functions defined.
+#endif
+
+/*****************************************/
+
+#if !defined(APR_OVERRIDE_ATOMIC_CASPTR) || !defined(APR_OVERRIDE_ATOMIC_CAS32) || !defined(APR_OVERRIDE_ATOMIC_READ32)
+
+static const unsigned num_atomic_hash = 7;
+/* shift by 2 or 3 to get rid of alignment issues */
+#define ATOMIC_HASH(x) (unsigned int)(((unsigned long)(x)>>((sizeof(void *)<8)?2:3))%(unsigned
int)num_atomic_hash)
 static apr_thread_mutex_t **hash_mutex;
-#endif /* APR_HAS_THREADS */
+#define APR_CHECK(x) do { if ((x) != APR_SUCCESS) abort(); } while (0)
 
 apr_status_t apr_atomic_init(apr_pool_t *p)
 {
-#if APR_HAS_THREADS
     int i;
     apr_status_t rv;
-    hash_mutex = apr_palloc(p, sizeof(apr_thread_mutex_t*) * NUM_ATOMIC_HASH);
+    hash_mutex = apr_palloc(p, sizeof(apr_thread_mutex_t*) * num_atomic_hash);
 
-    for (i = 0; i < NUM_ATOMIC_HASH; i++) {
+    for (i = 0; i < num_atomic_hash; i++) {
         rv = apr_thread_mutex_create(&(hash_mutex[i]),
                                      APR_THREAD_MUTEX_DEFAULT, p);
         if (rv != APR_SUCCESS) {
            return rv;
         }
     }
-#endif /* APR_HAS_THREADS */
     return APR_SUCCESS;
 }
-#endif /* !defined(APR_OVERRIDE_ATOMIC_INIT) */
+#define APR_OVERRIDE_ATOMIC_INIT
+#endif /* !defined(APR_OVERRIDE_ATOMIC_CASPTR) || !defined(APR_OVERRIDE_ATOMIC_CAS32) ||
!defined(APR_OVERRIDE_ATOMIC_READ32) /*
 
-/* abort() if 'x' does not evaluate to APR_SUCCESS. */
-#define CHECK(x) do { if ((x) != APR_SUCCESS) abort(); } while (0)
+/*****************************************/
 
+#if !defined(APR_OVERRIDE_ATOMIC_INC32)
+apr_uint32_t apr_atomic_inc32(apr_uint32_t *mem) 
+{
+    return apr_atomic_add32(mem, 1);
+}
+#define APR_OVERRIDE_ATOMIC_INC32
+#endif /* !defined(APR_OVERRIDE_ATOMIC_INC32) */
+
+/*****************************************/
+
+#if defined(APR_OVERRIDE_ATOMIC_CAS32) && defined(APR_OVERRIDE_ATOMIC_READ32)
+
 #if !defined(APR_OVERRIDE_ATOMIC_ADD32)
-#if defined(APR_OVERRIDE_ATOMIC_CAS32)
-apr_uint32_t apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val)
+apr_uint32_t apr_atomic_add32(apr_uint32_t *mem, apr_uint32_t val)
 {
     apr_uint32_t old_value, new_value;
     
     do {
-        old_value = *mem;
+       old_value = apr_atomic_read32(mem);
         new_value = old_value + val;
     } while (apr_atomic_cas32(mem, new_value, old_value) != old_value);
     return old_value;
 }
-#else
-apr_uint32_t apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val)
-{
-    apr_uint32_t old_value;
-
-#if APR_HAS_THREADS
-    apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
-       
-    CHECK(apr_thread_mutex_lock(lock));
-    old_value = *mem;
-    *mem += val;
-    CHECK(apr_thread_mutex_unlock(lock));
-#else
-    old_value = *mem;
-    *mem += val;
-#endif /* APR_HAS_THREADS */
-    return old_value;
-}
-#endif /* defined(APR_OVERRIDE_ATOMIC_CAS32) */
+#define APR_OVERRIDE_ATOMIC_ADD32
 #endif /* !defined(APR_OVERRIDE_ATOMIC_ADD32) */
 
 #if !defined(APR_OVERRIDE_ATOMIC_SUB32)
-#if defined(APR_OVERRIDE_ATOMIC_CAS32)
-void apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val)
+void apr_atomic_sub32(apr_uint32_t *mem, apr_uint32_t val)
 {
     apr_uint32_t old_value, new_value;
     
     do {
-        old_value = *mem;
+       old_value = apr_atomic_read32(mem);
         new_value = old_value - val;
     } while (apr_atomic_cas32(mem, new_value, old_value) != old_value);
 }
-#else
-void apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val) 
+#define APR_OVERRIDE_ATOMIC_SUB32
+#endif /* !defined(APR_OVERRIDE_ATOMIC_SUB32) */
+
+#if !defined(APR_OVERRIDE_ATOMIC_DEC32)
+int apr_atomic_dec32(apr_uint32_t *mem)
 {
-#if APR_HAS_THREADS
-    apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
-       
-    CHECK(apr_thread_mutex_lock(lock));
-    *mem -= val;
-    CHECK(apr_thread_mutex_unlock(lock));
-#else
-    *mem -= val;
-#endif /* APR_HAS_THREADS */
+    apr_uint32_t old_value, new_value;
+    
+    do {
+       old_value = apr_atomic_read32(mem);
+        new_value = old_value - 1;
+    } while (apr_atomic_cas32(mem, new_value, old_value) != old_value);
+    return old_value != 1;
 }
-#endif /* defined(APR_OVERRIDE_ATOMIC_CAS32) */
-#endif /* !defined(APR_OVERRIDE_ATOMIC_SUB32) */
+#define APR_OVERRIDE_ATOMIC_DEC32
+#endif /* !defined(APR_OVERRIDE_ATOMIC_DEC32) */
 
+#if !defined(APR_OVERRIDE_ATOMIC_XCHG32)
+apr_uint32_t apr_atomic_xchg32(apr_uint32_t *mem, apr_uint32_t val)
+{
+    apr_uint32_t prev;
+    do {
+       prev = apr_atomic_read32(mem);
+    } while (apr_atomic_cas32(mem, val, prev) != prev);
+    return prev;
+}
+#define APR_OVERRIDE_ATOMIC_XCHG32
+#endif /* !defined(APR_OVERRIDE_ATOMIC_XCHG32) */
+
 #if !defined(APR_OVERRIDE_ATOMIC_SET32)
-void apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val) 
+void apr_atomic_set32(apr_uint32_t *mem, apr_uint32_t val) 
 {
-#if APR_HAS_THREADS
-    apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
-
-    CHECK(apr_thread_mutex_lock(lock));
-    *mem = val;
-    CHECK(apr_thread_mutex_unlock(lock));
-#else
-    *mem = val;
-#endif /* APR_HAS_THREADS */
+   apr_uint32_t prev;
+   do {
+      prev = apr_atomic_read32(mem);
+   } while (apr_atomic_cas32(mem, val, prev) != prev);
 }
+#define APR_OVERRIDE_ATOMIC_SET32
 #endif /* !defined(APR_OVERRIDE_ATOMIC_SET32) */
 
-#if !defined(APR_OVERRIDE_ATOMIC_INC32)
-apr_uint32_t apr_atomic_inc32(volatile apr_uint32_t *mem) 
+#else /* defined(APR_OVERRIDE_ATOMIC_CAS32) && defined(APR_OVERRIDE_ATOMIC_READ32)
*/
+
+/*****************************************/
+
+#if defined(APR_OVERRIDE_ATOMIC_ADD32)
+#error Found function that should not exist.
+#endif
+apr_uint32_t apr_atomic_add32(apr_uint32_t *mem, apr_uint32_t val)
 {
-    return apr_atomic_add32(mem, 1);
+    apr_uint32_t old_value;
+
+    apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
+       
+    APR_CHECK(apr_thread_mutex_lock(lock));
+    old_value = *mem;
+    *mem += val;
+    APR_CHECK(apr_thread_mutex_unlock(lock));
+
+    return old_value;
 }
-#endif /* !defined(APR_OVERRIDE_ATOMIC_INC32) */
+#define APR_OVERRIDE_ATOMIC_ADD32
 
-#if !defined(APR_OVERRIDE_ATOMIC_DEC32)
-#if defined(APR_OVERRIDE_ATOMIC_CAS32)
-int apr_atomic_dec32(volatile apr_uint32_t *mem)
+#if defined(APR_OVERRIDE_ATOMIC_SUB32)
+#error Found function that should not exist.
+#endif
+void apr_atomic_sub32(apr_uint32_t *mem, apr_uint32_t val) 
 {
-    apr_uint32_t old_value, new_value;
-    
-    do {
-        old_value = *mem;
-        new_value = old_value - 1;
-    } while (apr_atomic_cas32(mem, new_value, old_value) != old_value);
-    return old_value != 1;
+    apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
+       
+    APR_CHECK(apr_thread_mutex_lock(lock));
+    *mem -= val;
+    APR_CHECK(apr_thread_mutex_unlock(lock));
 }
-#else
-int apr_atomic_dec32(volatile apr_uint32_t *mem) 
+#define APR_OVERRIDE_ATOMIC_SUB32
+
+#if defined(APR_OVERRIDE_ATOMIC_DEC32)
+#error Found function that should not exist.
+#endif
+int apr_atomic_dec32(apr_uint32_t *mem) 
 {
-#if APR_HAS_THREADS
     apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
     apr_uint32_t new;
 
-    CHECK(apr_thread_mutex_lock(lock));
+    APR_CHECK(apr_thread_mutex_lock(lock));
     (*mem)--;
     new = *mem;
-    CHECK(apr_thread_mutex_unlock(lock));
+    APR_CHECK(apr_thread_mutex_unlock(lock));
     return new;
-#else
-    (*mem)--;
-    return *mem; 
-#endif /* APR_HAS_THREADS */
 }
-#endif /* defined(APR_OVERRIDE_ATOMIC_CAS32) */
-#endif /* !defined(APR_OVERRIDE_ATOMIC_DEC32) */
+#define APR_OVERRIDE_ATOMIC_DEC32
 
-#if !defined(APR_OVERRIDE_ATOMIC_CAS32)
-apr_uint32_t apr_atomic_cas32(volatile apr_uint32_t *mem, apr_uint32_t with,
+#if defined(APR_OVERRIDE_ATOMIC_CAS32)
+#error Found function that should not exist.
+#endif
+apr_uint32_t apr_atomic_cas32(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)];
 
-    CHECK(apr_thread_mutex_lock(lock));
+    APR_CHECK(apr_thread_mutex_lock(lock));
     prev = *mem;
     if (prev == cmp) {
         *mem = with;
     }
-    CHECK(apr_thread_mutex_unlock(lock));
-#else
-    prev = *mem;
-    if (prev == cmp) {
-        *mem = with;
-    }
-#endif /* APR_HAS_THREADS */
+    APR_CHECK(apr_thread_mutex_unlock(lock));
     return prev;
 }
-#endif /* !defined(APR_OVERRIDE_ATOMIC_CAS32) */
+#define APR_OVERRIDE_ATOMIC_CAS32
 
-#if !defined(APR_OVERRIDE_ATOMIC_XCHG32)
-#if defined(APR_OVERRIDE_ATOMIC_CAS32)
-apr_uint32_t apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val)
+#if defined(APR_OVERRIDE_ATOMIC_XCHG32)
+#error Found function that should not exist.
+#endif
+apr_uint32_t apr_atomic_xchg32(apr_uint32_t *mem, apr_uint32_t val)
 {
     apr_uint32_t prev;
-    do {
-        prev = *mem;
-    } while (apr_atomic_cas32(mem, val, prev) != prev);
+    apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
+
+    APR_CHECK(apr_thread_mutex_lock(lock));
+    prev = *mem;
+    *mem = val;
+    APR_CHECK(apr_thread_mutex_unlock(lock));
     return prev;
 }
-#else
-apr_uint32_t apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val)
+#define APR_OVERRIDE_ATOMIC_XCHG32
+
+#if defined(APR_OVERRIDE_ATOMIC_SET32)
+#error Found function that should not exist.
+#endif
+void apr_atomic_set32(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)];
 
-    CHECK(apr_thread_mutex_lock(lock));
-    prev = *mem;
+    APR_CHECK(apr_thread_mutex_lock(lock));
     *mem = val;
-    CHECK(apr_thread_mutex_unlock(lock));
-#else
-    prev = *mem;
-    *mem = val;
-#endif /* APR_HAS_THREADS */
-    return prev;
+    APR_CHECK(apr_thread_mutex_unlock(lock));
 }
-#endif /* defined(APR_OVERRIDE_ATOMIC_CAS32) */
-#endif /* !defined(APR_OVERRIDE_ATOMIC_XCHG32) */
+#define APR_OVERRIDE_ATOMIC_SET32
 
+#if defined(APR_OVERRIDE_ATOMIC_READ32)
+#error Found function that should not exist.
+#endif
+APR_DECLARE(apr_uint32_t) apr_atomic_read32(apr_uint32_t *mem)
+{
+   apr_uint32_t nrv;
+   apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
+
+   APR_CHECK(apr_thread_mutex_lock(lock));
+   nrv = *mem;
+   APR_CHECK(apr_thread_mutex_unlock(lock));
+
+   return nrv;
+}
+
+#endif /* else of defined(APR_OVERRIDE_ATOMIC_CAS32) && defined(APR_OVERRIDE_ATOMIC_READ32)
*/
+
+/*****************************************/
+
 #if !defined(APR_OVERRIDE_ATOMIC_CASPTR)
-void *apr_atomic_casptr(volatile void **mem, void *with, const void *cmp)
+void *apr_atomic_casptr(void **mem, void *with, void *cmp)
 {
     void *prev;
-#if APR_HAS_THREADS
     apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
 
-    CHECK(apr_thread_mutex_lock(lock));
+    APR_CHECK(apr_thread_mutex_lock(lock));
     prev = *(void **)mem;
     if (prev == cmp) {
         *mem = with;
     }
-    CHECK(apr_thread_mutex_unlock(lock));
-#else
-    prev = *(void **)mem;
-    if (prev == cmp) {
-        *mem = with;
-    }
-#endif /* APR_HAS_THREADS */
+    APR_CHECK(apr_thread_mutex_unlock(lock));
     return prev;
 }
 #endif /* !defined(APR_OVERRIDE_ATOMIC_CASPTR) */
 
-#if !defined(APR_OVERRIDE_ATOMIC_READ32)
-APR_DECLARE(apr_uint32_t) apr_atomic_read32(volatile apr_uint32_t *mem)
+/*****************************************/
+
+#if !defined(APR_OVERRIDE_ATOMIC_INIT)
+APR_DECLARE(apr_status_t) apr_atomic_init(apr_pool_t *p)
 {
-    return *mem;
+   return APR_SUCCESS;
 }
+#define APR_OVERRIDE_ATOMIC_INIT
 #endif
 
+#endif /* APR_HAS_THREADS */
Index: include/apr_atomic.h
===================================================================
--- include/apr_atomic.h	(revision 466020)
+++ include/apr_atomic.h	(working copy)
@@ -53,14 +53,14 @@
  * atomically read an apr_uint32_t from memory
  * @param mem the pointer
  */
-APR_DECLARE(apr_uint32_t) apr_atomic_read32(volatile apr_uint32_t *mem);
+APR_DECLARE(apr_uint32_t) apr_atomic_read32(apr_uint32_t *mem);
 
 /**
  * atomically set an apr_uint32_t in memory
  * @param mem pointer to the object
  * @param val value that the object will assume
  */
-APR_DECLARE(void) apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val);
+APR_DECLARE(void) apr_atomic_set32(apr_uint32_t *mem, apr_uint32_t val);
 
 /**
  * atomically add 'val' to an apr_uint32_t
@@ -68,28 +68,28 @@
  * @param val amount to add
  * @return old value pointed to by mem
  */
-APR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val);
+APR_DECLARE(apr_uint32_t) apr_atomic_add32(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
  */
-APR_DECLARE(void) apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val);
+APR_DECLARE(void) apr_atomic_sub32(apr_uint32_t *mem, apr_uint32_t val);
 
 /**
  * atomically increment an apr_uint32_t by 1
  * @param mem pointer to the object
  * @return old value pointed to by mem
  */
-APR_DECLARE(apr_uint32_t) apr_atomic_inc32(volatile apr_uint32_t *mem);
+APR_DECLARE(apr_uint32_t) apr_atomic_inc32(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
  */
-APR_DECLARE(int) apr_atomic_dec32(volatile apr_uint32_t *mem);
+APR_DECLARE(int) apr_atomic_dec32(apr_uint32_t *mem);
 
 /**
  * compare an apr_uint32_t's value with 'cmp'.
@@ -99,7 +99,7 @@
  * @param cmp the value to compare it to
  * @return the old value of *mem
  */
-APR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t *mem, apr_uint32_t with,
+APR_DECLARE(apr_uint32_t) apr_atomic_cas32(apr_uint32_t *mem, apr_uint32_t with,
                               apr_uint32_t cmp);
 
 /**
@@ -108,7 +108,7 @@
  * @param val what to swap it with
  * @return the old value of *mem
  */
-APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val);
+APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(apr_uint32_t *mem, apr_uint32_t val);
 
 /**
  * compare the pointer's value with cmp.
@@ -118,7 +118,7 @@
  * @param cmp the value to compare it to
  * @return the old value of the pointer
  */
-APR_DECLARE(void*) apr_atomic_casptr(volatile void **mem, void *with, const void *cmp);
+APR_DECLARE(void*) apr_atomic_casptr(void **mem, void *with, void *cmp);
 
 /** @} */
 

Mime
View raw message