> 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