This patch is my attempt to simplify the platform-specific
conditional logic in apr_atomic.h.
I need a few volunteers to test it on Win32, FreeBSD, Netware,
and OS/390 before I commit.
With this patch, the overriding of the default atomic ops is
mow more granular: you can add #defines for whatever atomic
ops are available natively on your target platform, and the
ifdefs at the end of apr_atomic.h will pull in default
declarations for the ops that are missing.
I've also added a default implementation for platforms without
threads in apr_atomic.c.
--Brian
Index: include/apr_atomic.h
===================================================================
RCS file: /home/cvs/apr/include/apr_atomic.h,v
retrieving revision 1.32
diff -u -r1.32 apr_atomic.h
--- include/apr_atomic.h 5 Jul 2002 20:51:39 -0000 1.32
+++ include/apr_atomic.h 13 Jul 2002 03:29:36 -0000
@@ -136,13 +136,14 @@
apr_uint32_t apr_atomic_cas(volatile apr_uint32_t *mem,long with,long cmp);
#else /* !DOXYGEN */
-#if APR_FORCE_ATOMIC_GENERIC
-#if APR_HAS_THREADS
-#define APR_ATOMIC_NEED_DEFAULT 1
-#define APR_ATOMIC_NEED_CAS_DEFAULT 1
-#endif /* APR_HAS_THREADS */
+/* The following definitions provide optimized, OS-specific
+ * implementations of the APR atomic functions on various
+ * platforms. Any atomic operation that isn't redefined as
+ * a macro here will be declared as a function later, and
+ * apr_atomic.c will provide a mutex-based default implementation.
+ */
-#elif defined(WIN32)
+#if defined(WIN32)
typedef LONG apr_atomic_t;
@@ -161,6 +162,7 @@
#define apr_atomic_add(mem, val) atomic_add(mem,val)
APR_DECLARE(int) apr_atomic_dec(apr_atomic_t *mem);
+#define apr_override_atomic_dec 1
#define apr_atomic_inc(mem) atomic_inc(mem)
#define apr_atomic_set(mem, val) (*mem = val)
#define apr_atomic_read(mem) (*mem)
@@ -178,9 +180,8 @@
#define apr_atomic_set(mem, val) atomic_set_int(mem, val)
#define apr_atomic_read(mem) (*mem)
-#define APR_ATOMIC_NEED_CAS_DEFAULT 1
+#elif defined(__linux__) && defined(__i386__) && !APR_FORCE_ATOMIC_GENERIC
-#elif defined(__linux__) && defined(__i386__)
#define apr_atomic_t apr_uint32_t
#define apr_atomic_cas(mem,with,cmp) \
({ apr_atomic_t prev; \
@@ -190,12 +191,8 @@
: "memory"); \
prev;})
-#define APR_ATOMIC_NEED_DEFAULT 1
-#if defined(APR_ATOMIC_NEED_CAS_DEFAULT)
-#undef APR_ATOMIC_NEED_CAS_DEFAULT
-#endif
+#elif defined(__sparc__) || defined(sparc) && !APR_FORCE_ATOMIC_GENERIC
-#elif defined(__sparc__) || defined(sparc)
#define apr_atomic_t apr_uint32_t
#define apr_atomic_read(p) *p
@@ -217,6 +214,8 @@
apr_int32_t apr_atomic_add(volatile apr_atomic_t *mem, apr_int32_t val);
apr_uint32_t apr_atomic_cas(volatile apr_atomic_t *mem, apr_uint32_t swap,
apr_uint32_t cmp);
+#define apr_override_atomic_add 1
+#define apr_override_atomic_cas 1
#define apr_atomic_inc(mem) apr_atomic_add(mem, 1)
#define apr_atomic_dec(mem) apr_atomic_add(mem, -1)
@@ -234,30 +233,67 @@
#define apr_atomic_read(p) (*p)
#define apr_atomic_set(mem, val) (*mem = val)
-#else
-#if APR_HAS_THREADS
-#define APR_ATOMIC_NEED_DEFAULT 1
-#define APR_ATOMIC_NEED_CAS_DEFAULT 1
-#endif /* APR_HAS_THREADS */
+#endif /* end big if-elseif switch for platform-specifics */
+
-#endif /* !defined(WIN32) */
+/* Default implementation of the atomic API
+ * The definitions above may override some or all of the
+ * atomic functions with optimized, platform-specific versions.
+ * Any operation that hasn't been overridden as a macro above
+ * is declared as a function here, unless apr_override_atomic_[operation]
+ * is defined.
+ */
+
+#define APR_ATOMIC_NEED_DEFAULT_INIT 0
-#if defined(APR_ATOMIC_NEED_DEFAULT)
+#if !defined(apr_atomic_t)
#define apr_atomic_t apr_uint32_t
-#define apr_atomic_read(p) *p
+#endif
+
+#if !defined(apr_atomic_init) && !defined(apr_override_atomic_init)
apr_status_t apr_atomic_init(apr_pool_t *p);
+#endif
+
+#if !defined(apr_atomic_read) && !defined(apr_override_atomic_read)
+#define apr_atomic_read(p) *p
+#endif
+
+#if !defined(apr_atomic_set) && !defined(apr_override_atomic_set)
void apr_atomic_set(volatile apr_atomic_t *mem, apr_uint32_t val);
+#define APR_ATOMIC_NEED_DEFAULT_INIT 1
+#endif
+
+#if !defined(apr_atomic_add) && !defined(apr_override_atomic_add)
void apr_atomic_add(volatile apr_atomic_t *mem, apr_uint32_t val);
+#define APR_ATOMIC_NEED_DEFAULT_INIT 1
+#endif
+
+#if !defined(apr_atomic_inc) && !defined(apr_override_atomic_inc)
void apr_atomic_inc(volatile apr_atomic_t *mem);
+#define APR_ATOMIC_NEED_DEFAULT_INIT 1
+#endif
+
+#if !defined(apr_atomic_dec) && !defined(apr_override_atomic_dec)
int apr_atomic_dec(volatile apr_atomic_t *mem);
+#define APR_ATOMIC_NEED_DEFAULT_INIT 1
#endif
-#if defined(APR_ATOMIC_NEED_CAS_DEFAULT)
-apr_status_t apr_atomic_init(apr_pool_t *p);
+#if !defined(apr_atomic_cas) && !defined(apr_override_atomic_cas)
apr_uint32_t apr_atomic_cas(volatile apr_uint32_t *mem,long with,long cmp);
+#define APR_ATOMIC_NEED_DEFAULT_INIT 1
+#endif
+
+/* If we're using the default versions of any of the atomic functions,
+ * we'll need the atomic init to set up mutexes. If a platform-specific
+ * override above has replaced the atomic_init with a macro, it's an error.
+ */
+#if APR_ATOMIC_NEED_DEFAULT_INIT
+#if defined(apr_atomic_init) || defined(apr_override_atomic_init)
+#error Platform has redefined apr_atomic_init, but other default default
atomics require a default apr_atomic_init
#endif
+#endif /* APR_ATOMIC_NEED_DEFAULT_INIT */
-#endif /* DOXYGEN */
+#endif /* !DOXYGEN */
#ifdef __cplusplus
}
#endif
Index: atomic/unix/apr_atomic.c
===================================================================
RCS file: /home/cvs/apr/atomic/unix/apr_atomic.c,v
retrieving revision 1.16
diff -u -r1.16 apr_atomic.c
--- atomic/unix/apr_atomic.c 5 Jul 2002 21:10:10 -0000 1.16
+++ atomic/unix/apr_atomic.c 13 Jul 2002 03:29:36 -0000
@@ -56,17 +56,18 @@
#include "apr_atomic.h"
#include "apr_thread_mutex.h"
-#if APR_HAS_THREADS
-
-#if defined(APR_ATOMIC_NEED_DEFAULT) || defined(APR_ATOMIC_NEED_CAS_DEFAULT)
+#if !defined(apr_atomic_init) && !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)
static apr_thread_mutex_t **hash_mutex;
+#endif /* APR_HAS_THREADS */
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);
@@ -78,13 +79,15 @@
return rv;
}
}
+#endif /* APR_HAS_THREADS */
return APR_SUCCESS;
}
-#endif /* APR_ATOMIC_NEED_DEFAULT || APR_ATOMIC_NEED_CAS_DEFAULT */
+#endif /*!defined(apr_atomic_init) && !defined(apr_override_atomic_init) */
-#if defined(APR_ATOMIC_NEED_DEFAULT)
+#if !defined(apr_atomic_add) && !defined(apr_override_atomic_add)
void apr_atomic_add(volatile apr_atomic_t *mem, apr_uint32_t val)
{
+#if APR_HAS_THREADS
apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
apr_uint32_t prev;
@@ -93,10 +96,16 @@
*mem += val;
apr_thread_mutex_unlock(lock);
}
+#else
+ *mem += val;
+#endif /* APR_HAS_THREADS */
}
+#endif /*!defined(apr_atomic_add) && !defined(apr_override_atomic_add) */
+#if !defined(apr_atomic_set) && !defined(apr_override_atomic_set)
void apr_atomic_set(volatile apr_atomic_t *mem, apr_uint32_t val)
{
+#if APR_HAS_THREADS
apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
apr_uint32_t prev;
@@ -105,10 +114,16 @@
*mem = val;
apr_thread_mutex_unlock(lock);
}
+#else
+ *mem = val;
+#endif /* APR_HAS_THREADS */
}
+#endif /*!defined(apr_atomic_set) && !defined(apr_override_atomic_set) */
+#if !defined(apr_atomic_inc) && !defined(apr_override_atomic_inc)
void apr_atomic_inc(volatile apr_uint32_t *mem)
{
+#if APR_HAS_THREADS
apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
apr_uint32_t prev;
@@ -117,10 +132,16 @@
(*mem)++;
apr_thread_mutex_unlock(lock);
}
+#else
+ (*mem)++;
+#endif /* APR_HAS_THREADS */
}
+#endif /*!defined(apr_atomic_inc) && !defined(apr_override_atomic_inc) */
+#if !defined(apr_atomic_dec) && !defined(apr_override_atomic_dec)
int apr_atomic_dec(volatile apr_atomic_t *mem)
{
+#if APR_HAS_THREADS
apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
apr_uint32_t new;
@@ -130,14 +151,17 @@
apr_thread_mutex_unlock(lock);
return new;
}
+#else
+ (*mem)--;
+#endif /* APR_HAS_THREADS */
return *mem;
}
+#endif /*!defined(apr_atomic_dec) && !defined(apr_override_atomic_dec) */
-#endif /* APR_ATOMIC_NEED_DEFAULT */
-#if defined(APR_ATOMIC_NEED_CAS_DEFAULT)
-
+#if !defined(apr_atomic_cas) && !defined(apr_override_atomic_case)
apr_uint32_t apr_atomic_cas(volatile apr_uint32_t *mem, long with, long cmp)
{
+#if APR_HAS_THREADS
apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
long prev;
@@ -150,16 +174,12 @@
return prev;
}
return *(long*)mem;
-}
-#endif /* APR_ATOMIC_NEED_CAS_DEFAULT */
-
-#else /* !APR_HAS_THREADS */
-
-#if !defined(apr_atomic_init)
-apr_status_t apr_atomic_init(apr_pool_t *p)
-{
- return APR_SUCCESS;
-}
-#endif /* !defined(apr_atomic_init) */
-
+#else
+ prev = *(long*)mem;
+ if ( prev == cmp) {
+ *(long*)mem = with;
+ }
+ return prev;
#endif /* APR_HAS_THREADS */
+}
+#endif /*!defined(apr_atomic_dec) && !defined(apr_override_atomic_dec) */