summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbrianp <brianp@13f79535-47bb-0310-9956-ffa450edef68>2002-08-31 22:56:18 +0000
committerbrianp <brianp@13f79535-47bb-0310-9956-ffa450edef68>2002-08-31 22:56:18 +0000
commitb3e7bfec4df6d8ccb2b657b5bbdf8f167e60a53d (patch)
tree88af6c656eab418b5732dd3037c661dd15f4515e
parentdbff1f163f68c21dff1e62ce71606ece45731c96 (diff)
downloadlibapr-b3e7bfec4df6d8ccb2b657b5bbdf8f167e60a53d.tar.gz
Cleaner mechanism for using platform-specific atomics on platforms
that override some of the default atomic functions but not others git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@63842 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--atomic/unix/apr_atomic.c60
-rw-r--r--include/apr_atomic.h86
2 files changed, 102 insertions, 44 deletions
diff --git a/atomic/unix/apr_atomic.c b/atomic/unix/apr_atomic.c
index a17e1adaa..e28d0f94c 100644
--- a/atomic/unix/apr_atomic.c
+++ b/atomic/unix/apr_atomic.c
@@ -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 @@ apr_status_t apr_atomic_init(apr_pool_t *p)
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 @@ void apr_atomic_add(volatile apr_atomic_t *mem, apr_uint32_t val)
*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 @@ void apr_atomic_set(volatile apr_atomic_t *mem, apr_uint32_t val)
*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 @@ void apr_atomic_inc(volatile apr_uint32_t *mem)
(*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 @@ int apr_atomic_dec(volatile apr_atomic_t *mem)
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 @@ apr_uint32_t apr_atomic_cas(volatile apr_uint32_t *mem, long with, long cmp)
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) */
diff --git a/include/apr_atomic.h b/include/apr_atomic.h
index 9277658cf..e9189aa56 100644
--- a/include/apr_atomic.h
+++ b/include/apr_atomic.h
@@ -136,13 +136,14 @@ int apr_atomic_dec(volatile apr_atomic_t *mem);
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 @@ typedef LONG apr_atomic_t;
#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 @@ APR_DECLARE(int) apr_atomic_dec(apr_atomic_t *mem);
#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 @@ APR_DECLARE(int) apr_atomic_dec(apr_atomic_t *mem);
: "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_uint32_t apr_atomic_cas_sparc(volatile apr_uint32_t *mem, long with, long cm
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,69 @@ apr_uint32_t apr_atomic_cas(volatile apr_atomic_t *mem, apr_uint32_t swap,
#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. (The purpose of the APR_OVERRIDE_ATOMIC_* is
+ * to allow a platform to declare an apr_atomic_*() function
+ * with a different signature than the default.)
+ */
+
+#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