You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@apr.apache.org by Colin <sh...@think42.com> on 2006/10/19 22:51:32 UTC

various atomic operations

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.

Regards, Colin


1) The PowerPC assembler versions of apr_atomic_cas32 and
   apr_atomic_add32 can deadlock some machines.

http://www-306.ibm.com/chips/techlib/techlib.nsf/techdocs/79B6E24422AA101287256E93006C957E/$file/PowerPC_970FX_errata_DD3.X_V1.7.pdf

2) I have Sparc assembler versions of all atomic operations that work
   from Sparc v9 upward; for Solaris < 10; requires Makefile change.

3) Various places are missing memory barriers for non-x86
   architectures; volatile is not sufficient.

4) On Mac OS X (Darwin) there are atomic operations available to
   userspace as per /usr/include/libkern/OSAtomic.h .

5) The volatile declarations on all function prototypes in
   apr_atomic.c could be replaced by appropriate use of volatile
   accesses in the functions' bodies.

6) Might a value of 3 be better for the shift in the ATOMIC_HASH
   macro on 64 bit platforms?

7) For some (all?) architectures it should be ensured that the mutexes
   pointed to by hash_mutex are in different cache lines to prevent
   performance degradation.

8) I believe that some of the arguments to the x86 inline assembler
   parts can be simplified by use of "+", and generally cleaned up a
   little.

Re: various atomic operations

Posted by Colin <sh...@think42.com>.
On Mon, Oct 23, 2006 at 10:22:03AM +0100, Joe Orton wrote:
> On Fri, Oct 20, 2006 at 05:35:47PM +0200, Colin wrote:
> > On Thu, Oct 19, 2006 at 05:04:12PM -0700, Garrett Rooney wrote:
> > > On 10/19/06, Colin <sh...@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.
> 
> The emphasis should have been on patch*es* in the plural there!  When 
> you're making multiple sets of changes, it's better to send one patch 
> per functional change (or set of closely-related changes, possibly), so 
> they can be reviewed separately.
> 
> Without splitting out whitespace changes, non-functional changes, code 
> re-ordering etc this is very hard to review.  Also, the function 
> prototype changes need to be addressed separately because they can't be 
> used in any 1.x release.
> 
> Would it be possible for you to split this out and resend it?  e.g. one 
> patch for Solaris-specific fixes, one for the Darwin implemention, etc. 
> Also - the changes made should be described in the mail with which each 
> patch is sent, not in the source file itself.

My intention was to use the files I sent in the last mail as starting point
for further discussion; the hope is that looking at the original file and
the changed file with the comments allows for a first dialog, and perhaps
the decision on whether a change would be accepted.

(The list of changes has about 20 items, and I tested 5 versions on 3
machines, so I would need to create 20 patches and make 100 tests, but
if one of the first, more global changes gets rejected I end up with
having to re-do most of them ... that's why I would like to pre-filter.)

For example, if it is felt that the global moving around of functions,
e.g. creating dedicated NOTHREADS implementations, is not wanted, I 
would omit that part.

Other places that were in my opinion broken, like the wrong Solaris 10 
function calls, could be more or less nodded of immediately.

Perhaps we can start this way, and then I can start feeding small patches,
that are intended for inclusion, and only make one change... Even if you
just tell me where to start.

Regards, Colin



Re: various atomic operations

Posted by Colin <sh...@think42.com>.
On Thu, Oct 19, 2006 at 05:04:12PM -0700, Garrett Rooney wrote:
> On 10/19/06, Colin <sh...@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 <sh...@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);
 
 /** @} */
 

Re: various atomic operations

Posted by Garrett Rooney <ro...@electricjellyfish.net>.
On 10/19/06, Colin <sh...@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.

-garrett

Re: various atomic operations

Posted by Joe Orton <jo...@redhat.com>.
On Thu, Oct 19, 2006 at 10:51:32PM +0200, Colin wrote:
> 8) I believe that some of the arguments to the x86 inline assembler
>    parts can be simplified by use of "+", and generally cleaned up a
>    little.

The original implementation used + in output operands, but that doesn't 
work with gcc 2.7.2.1 so it got changed.

Regards,

joe