> Also, please use diff -u :-)

Attached is the output of diff -u against version 1.2.7; again only
atomic/unix/apr_atomic.c was affected.

Added: Sparc atomic primitives for v9 architectures, requires -mcpu=v9
  to compile!

Fixed: Changed Intel atomic primitives to use input/output parameters
  wherever possible and/or necessary.

Added: A comment "// TODO: read memory barrier" wherever one is missing;
  the memory barrier is not necessary on x86, but on most other archs.

Fixed: As I noted in a previous post, the PowerPC implementation of 
  apr_atomic_add32() and apr_atomic_cas32() can produce a livelock on
  some PowerPC 970 chips like the 970MP in my PowerMac, I have therefore
  put the respective code in a "#if 0".

If memory barriers are used correctly, then the "volatile" can be 
removed from the declaration of all "volatile apr_uint32_t * mem"
function arguments; only select few accesses need to cast the pointer
to volatile when performing the access; this change will (a) likely
produce better code for when the access need not be explicitly
volatile [again], like when a mutex is used, and (b) make it more
likely to trigger existing bugs (volatile alone does not fix them).

Regards, Colin
--- apr_atomic.c.old    2006-09-15 10:05:43.000000000 +0200
+++ apr_atomic.c        2006-09-15 10:55:53.000000000 +0200
@@ -37,9 +37,9 @@
 {
     apr_uint32_t prev;
 
-    asm volatile ("lock; cmpxchgl %1, %2"             
-                  : "=a" (prev)               
-                  : "r" (with), "m" (*(mem)), "0"(cmp) 
+    asm volatile ("lock; cmpxchgl %2,%1"
+                  : "=a" (prev), "+m" (*(mem))
+                  : "r" (with), "0"(cmp)
                   : "memory", "cc");
     return prev;
 }
@@ -49,8 +49,8 @@
                                               apr_uint32_t val)
 {
     asm volatile ("lock; xaddl %0,%1"
-                  : "=r"(val), "=m"(*mem) /* outputs */
-                  : "0"(val), "m"(*mem)   /* inputs */
+                  : "+r"(val), "+m"(*mem) /* outputs */
+                  : 
                   : "memory", "cc");
     return val;
 }
@@ -64,9 +64,9 @@
 
 APR_DECLARE(void) apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t 
val)
 {
-    asm volatile ("lock; subl %1, %0"
-                  :
-                  : "m" (*(mem)), "r" (val)
+    asm volatile ("lock; subl %1,%0"
+                  : "+m" (*(mem))
+                  : "r" (val)
                   : "memory", "cc");
 }
 #define APR_OVERRIDE_ATOMIC_SUB32
@@ -77,8 +77,8 @@
 
     asm volatile ("lock; decl %1;\n\t"
                   "setnz %%al"
-                  : "=a" (prev)
-                  : "m" (*(mem))
+                  : "=a" (prev), "+m" (*(mem))
+                  :
                   : "memory", "cc");
     return prev;
 }
@@ -101,8 +101,8 @@
     apr_uint32_t prev = val;
 
     asm volatile ("lock; xchgl %0, %1"
-                  : "+r" (prev), "+m" (*(mem))
-                  : 
+                  : "=r" (prev)
+                  : "m" (*(mem)), "0"(prev)
                   : "memory");
     return prev;
 }
@@ -112,8 +112,10 @@
 
 #endif /* (__linux__ || __EMX__ || __FreeBSD__) && __i386__ */
 
-#if (defined(__PPC__) || defined(__ppc__)) && defined(__GNUC__) \
-    && !defined(USE_GENERIC_ATOMICS)
+// #if (defined(__PPC__) || defined(__ppc__)) && defined(__GNUC__)       \
+//    && !defined(USE_GENERIC_ATOMICS)
+
+#if 0
 
 APR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t *mem,
                                            apr_uint32_t swap,
@@ -162,6 +164,88 @@
 
 #endif /* __PPC__ && __GNUC__ */
 
+#if (defined(__SPARC__) || defined(__sparc__)) && defined(__GNUC__ ) \
+   && !defined(USE_GENERIC_ATOMICS)
+
+APR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t * mem,
+                                           apr_uint32_t with,
+                                           apr_uint32_t cmp)
+{
+   __asm__ __volatile__ ( "cas [%1],%2,%0"
+                          : "+r" ( with )
+                          : "r" ( mem ), "r" ( cmp )
+                          : "memory" );
+   return with;
+}
+#define APR_OVERRIDE_ATOMIC_CAS32
+
+APR_DECLARE(apr_uint32_t) apr_atomic_read32(volatile apr_uint32_t * mem)
+{
+   __asm__ __volatile__ ( "membar #StoreLoad | #LoadLoad" : : : "memory" );
+   return *(volatile apr_uint32_t *)mem;
+}
+#define APR_OVERRIDE_ATOMIC_READ32
+
+APR_DECLARE(void) apr_atomic_set32(volatile 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
+
+APR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t * mem,
+                                           apr_uint32_t val)
+{
+   apr_uint32_t nrv;
+
+   do {
+      nrv = apr_atomic_read32(mem);
+   } while (apr_atomic_cas32(mem,nrv+val,nrv)!=nrv);
+
+   return nrv;
+}
+#define APR_OVERRIDE_ATOMIC_ADD32
+
+APR_DECLARE(void) apr_atomic_sub32(volatile apr_uint32_t * mem, apr_uint32_t 
val)
+{
+   apr_atomic_add32(mem,-val);
+}
+#define APR_OVERRIDE_ATOMIC_SUB32
+
+APR_DECLARE(apr_uint32_t) apr_atomic_inc32(volatile apr_uint32_t * mem)
+{
+   return apr_atomic_add32(mem,1);
+}
+#define APR_OVERRIDE_ATOMIC_INC32
+
+APR_DECLARE(int) apr_atomic_dec32(volatile apr_uint32_t * mem)
+{
+   apr_uint32_t nrv;
+
+   do {
+      nrv = apr_atomic_read32(mem);
+   } while (apr_atomic_cas32(mem,nrv-1,nrv)!=nrv);
+
+   return nrv != 1;
+}
+#define APR_OVERRIDE_ATOMIC_DEC32
+
+APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(volatile apr_uint32_t * mem,
+                                            apr_uint32_t val)
+{
+   apr_uint32_t nrv;
+
+   do {
+      nrv = apr_atomic_read32(mem);
+   } while (apr_atomic_cas32(mem,val,nrv)!=nrv);
+
+   return nrv;
+}
+#define APR_OVERRIDE_ATOMIC_XCHG32
+
+#endif /* __SPARC__ && __GNUC__ */
+
 #if !defined(APR_OVERRIDE_ATOMIC_INIT)
 
 #if APR_HAS_THREADS
@@ -200,6 +284,7 @@
     apr_uint32_t old_value, new_value;
     
     do {
+        // TODO: read memory barrier
         old_value = *mem;
         new_value = old_value + val;
     } while (apr_atomic_cas32(mem, new_value, old_value) != old_value);
@@ -233,6 +318,7 @@
     apr_uint32_t old_value, new_value;
     
     do {
+        // TODO: read memory barrier
         old_value = *mem;
         new_value = old_value - val;
     } while (apr_atomic_cas32(mem, new_value, old_value) != old_value);
@@ -282,6 +368,7 @@
     apr_uint32_t old_value, new_value;
     
     do {
+        // TODO: read memory barrier
         old_value = *mem;
         new_value = old_value - 1;
     } while (apr_atomic_cas32(mem, new_value, old_value) != old_value);
@@ -337,6 +424,7 @@
 {
     apr_uint32_t prev;
     do {
+        // TODO: read memory barrier
         prev = *mem;
     } while (apr_atomic_cas32(mem, val, prev) != prev);
     return prev;
@@ -387,6 +475,7 @@
 #if !defined(APR_OVERRIDE_ATOMIC_READ32)
 APR_DECLARE(apr_uint32_t) apr_atomic_read32(volatile apr_uint32_t *mem)
 {
+    // TODO: read memory barrier
     return *mem;
 }
 #endif

Reply via email to