Index: apr/atomic/unix/mutex.c =================================================================== --- /dev/null +++ apr/atomic/unix/mutex.c @@ -0,0 +1,192 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "apr_arch_atomic.h" + +#ifdef USE_ATOMICS_GENERIC + +#include + +#if APR_HAS_THREADS +# define DECLARE_MUTEX_LOCKED(name, mem) \ + apr_thread_mutex_t *name = mutex_hash(mem) +# define MUTEX_UNLOCK(name) \ + do { \ + if (apr_thread_mutex_unlock(name) != APR_SUCCESS) \ + abort(); \ + } while (0) +#else +# define DECLARE_MUTEX_LOCKED(name, mem) +# define MUTEX_UNLOCK(name) +# warning Be warned: using stubs for all atomic operations +#endif + +#if APR_HAS_THREADS + +static apr_thread_mutex_t **hash_mutex; + +#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_status_t atomic_cleanup(void *data) +{ + if (hash_mutex == data) + hash_mutex = NULL; + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_atomic_init(apr_pool_t *p) +{ + int i; + apr_status_t rv; + + if (hash_mutex != NULL) + return APR_SUCCESS; + + hash_mutex = apr_palloc(p, sizeof(apr_thread_mutex_t*) * NUM_ATOMIC_HASH); + apr_pool_cleanup_register(p, hash_mutex, atomic_cleanup, + apr_pool_cleanup_null); + + 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; + } + } + + return APR_SUCCESS; +} + +static APR_INLINE apr_thread_mutex_t *mutex_hash(volatile apr_uint32_t *mem) +{ + apr_thread_mutex_t *mutex = hash_mutex[ATOMIC_HASH(mem)]; + + if (apr_thread_mutex_lock(mutex) != APR_SUCCESS) { + abort(); + } + + return mutex; +} + +#else + +APR_DECLARE(apr_status_t) apr_atomic_init(apr_pool_t *p) +{ + return APR_SUCCESS; +} + +#endif /* APR_HAS_THREADS */ + +APR_DECLARE(apr_uint32_t) apr_atomic_read32(volatile apr_uint32_t *mem) +{ + return *mem; +} + +APR_DECLARE(void) apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + DECLARE_MUTEX_LOCKED(mutex, mem); + + *mem = val; + + MUTEX_UNLOCK(mutex); +} + +APR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + apr_uint32_t old_value; + DECLARE_MUTEX_LOCKED(mutex, mem); + + old_value = *mem; + *mem += val; + + MUTEX_UNLOCK(mutex); + + return old_value; +} + +APR_DECLARE(void) apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + DECLARE_MUTEX_LOCKED(mutex, mem); + *mem -= val; + MUTEX_UNLOCK(mutex); +} + +APR_DECLARE(apr_uint32_t) apr_atomic_inc32(volatile apr_uint32_t *mem) +{ + return apr_atomic_add32(mem, 1); +} + +APR_DECLARE(int) apr_atomic_dec32(volatile apr_uint32_t *mem) +{ + apr_uint32_t new; + DECLARE_MUTEX_LOCKED(mutex, mem); + + (*mem)--; + new = *mem; + + MUTEX_UNLOCK(mutex); + + return new; +} + +APR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t *mem, apr_uint32_t with, + apr_uint32_t cmp) +{ + apr_uint32_t prev; + DECLARE_MUTEX_LOCKED(mutex, mem); + + prev = *mem; + if (prev == cmp) { + *mem = with; + } + + MUTEX_UNLOCK(mutex); + + return prev; +} + +APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + apr_uint32_t prev; + DECLARE_MUTEX_LOCKED(mutex, mem); + + prev = *mem; + *mem = val; + + MUTEX_UNLOCK(mutex); + + return prev; +} + +APR_DECLARE(void*) apr_atomic_casptr(volatile void **mem, void *with, const void *cmp) +{ + void *prev; + DECLARE_MUTEX_LOCKED(mutex, *mem); + + prev = *(void **)mem; + if (prev == cmp) { + *mem = with; + } + + MUTEX_UNLOCK(mutex); + + return prev; +} + +#endif /* USE_ATOMICS_GENERIC */ Index: apr/atomic/unix/apr_atomic.c =================================================================== --- apr.orig/atomic/unix/apr_atomic.c +++ /dev/null @@ -1,464 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "apr.h" -#include "apr_atomic.h" -#include "apr_thread_mutex.h" - -#include "apr_private.h" - -#include -#if (defined(SOLARIS2) && SOLARIS2 >= 10) -#include -#endif - -#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 -#endif - -#if (defined(__i386__) || defined(__x86_64__)) \ - && 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) -{ - apr_uint32_t prev; - - asm volatile ("lock; cmpxchgl %1, %2" - : "=a" (prev) - : "r" (with), "m" (*(mem)), "0"(cmp) - : "memory", "cc"); - return prev; -} -#define APR_OVERRIDE_ATOMIC_CAS32 - -static apr_uint32_t inline intel_atomic_add32(volatile apr_uint32_t *mem, - apr_uint32_t val) -{ - asm volatile ("lock; xaddl %0,%1" - : "=r"(val), "=m"(*mem) /* outputs */ - : "0"(val), "m"(*mem) /* inputs */ - : "memory", "cc"); - return val; -} - -APR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem, - apr_uint32_t val) -{ - return intel_atomic_add32(mem, val); -} -#define APR_OVERRIDE_ATOMIC_ADD32 - -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) - : "memory", "cc"); -} -#define APR_OVERRIDE_ATOMIC_SUB32 - -APR_DECLARE(int) apr_atomic_dec32(volatile apr_uint32_t *mem) -{ - unsigned char prev; - - asm volatile ("lock; decl %1;\n\t" - "setnz %%al" - : "=a" (prev) - : "m" (*(mem)) - : "memory", "cc"); - return prev; -} -#define APR_OVERRIDE_ATOMIC_DEC32 - -APR_DECLARE(apr_uint32_t) apr_atomic_inc32(volatile apr_uint32_t *mem) -{ - return intel_atomic_add32(mem, 1); -} -#define APR_OVERRIDE_ATOMIC_INC32 - -APR_DECLARE(void) apr_atomic_set32(volatile 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) - : "memory"); - return prev; -} -#define APR_OVERRIDE_ATOMIC_XCHG32 - -/*#define apr_atomic_init(pool) APR_SUCCESS*/ - -#endif /* (__linux__ || __EMX__ || __FreeBSD__) && __i386__ */ - -#if (defined(__PPC__) || defined(__ppc__)) && defined(__GNUC__) \ - && !defined(USE_GENERIC_ATOMICS) - -APR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t *mem, - apr_uint32_t swap, - apr_uint32_t cmp) -{ - apr_uint32_t prev; - - asm volatile ("0:\n\t" /* retry local label */ - "lwarx %0,0,%1\n\t" /* load prev and reserve */ - "cmpw %0,%3\n\t" /* does it match cmp? */ - "bne- 1f\n\t" /* ...no, bail out */ - "stwcx. %2,0,%1\n\t" /* ...yes, conditionally - store swap */ - "bne- 0b\n\t" /* start over if we lost - the reservation */ - "1:" /* exit local label */ - - : "=&r"(prev) /* output */ - : "b" (mem), "r" (swap), "r"(cmp) /* inputs */ - : "memory", "cc"); /* clobbered */ - return prev; -} -#define APR_OVERRIDE_ATOMIC_CAS32 - -APR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem, - apr_uint32_t delta) -{ - apr_uint32_t prev, temp; - - asm volatile ("0:\n\t" /* retry local label */ - "lwarx %0,0,%2\n\t" /* load prev and reserve */ - "add %1,%0,%3\n\t" /* temp = prev + delta */ - "stwcx. %1,0,%2\n\t" /* conditionally store */ - "bne- 0b" /* start over if we lost - the reservation */ - - /*XXX find a cleaner way to define the temp - * it's not an output - */ - : "=&r" (prev), "=&r" (temp) /* output, temp */ - : "b" (mem), "r" (delta) /* inputs */ - : "memory", "cc"); /* clobbered */ - return prev; -} -#define APR_OVERRIDE_ATOMIC_ADD32 - -#endif /* __PPC__ && __GNUC__ */ - -#if (defined(SOLARIS2) && SOLARIS2 >= 10) \ - && !defined(USE_GENERIC_ATOMICS) - -#if !defined(APR_OVERRIDE_ATOMIC_CAS32) -APR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t *mem, - apr_uint32_t with, - apr_uint32_t cmp) -{ - return atomic_cas_32(mem, cmp, with); -} -#define APR_OVERRIDE_ATOMIC_CAS32 -#endif /* APR_OVERRIDE_ATOMIC_CAS32 */ - -#if !defined(APR_OVERRIDE_ATOMIC_DEC32) -APR_DECLARE(int) apr_atomic_dec32(volatile apr_uint32_t *mem) -{ - apr_uint32_t prev = *mem; - atomic_dec_32(mem); - return prev != 1; -} -#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_uint32_t prev = *mem; - atomic_inc_32(mem); - return prev; -} -#define APR_OVERRIDE_ATOMIC_INC32 -#endif /* APR_OVERRIDE_ATOMIC_INC32 */ - -#if !defined(APR_OVERRIDE_ATOMIC_SET32) -APR_DECLARE(void) apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val) -{ - *mem = val; -} -#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_uint32_t val) -{ - return atomic_swap_32(mem, val); -} -#define APR_OVERRIDE_ATOMIC_XCHG32 -#endif /* APR_OVERRIDE_ATOMIC_XCHG32 */ - -#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) -static apr_thread_mutex_t **hash_mutex; -#endif /* APR_HAS_THREADS */ - -#if APR_HAS_THREADS -static apr_status_t atomic_cleanup(void *data) -{ - if (hash_mutex == data) - hash_mutex = NULL; - - return APR_SUCCESS; -} -#endif - -apr_status_t apr_atomic_init(apr_pool_t *p) -{ -#if APR_HAS_THREADS - int i; - apr_status_t rv; - - if (hash_mutex != NULL) - return APR_SUCCESS; - - hash_mutex = apr_palloc(p, sizeof(apr_thread_mutex_t*) * NUM_ATOMIC_HASH); - apr_pool_cleanup_register(p, hash_mutex, atomic_cleanup, - apr_pool_cleanup_null); - - 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) */ - -/* 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_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 old_value, new_value; - - do { - old_value = *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) */ -#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) -{ - apr_uint32_t old_value, new_value; - - do { - old_value = *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) -{ -#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 */ -} -#endif /* defined(APR_OVERRIDE_ATOMIC_CAS32) */ -#endif /* !defined(APR_OVERRIDE_ATOMIC_SUB32) */ - -#if !defined(APR_OVERRIDE_ATOMIC_SET32) -void apr_atomic_set32(volatile 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 */ -} -#endif /* !defined(APR_OVERRIDE_ATOMIC_SET32) */ - -#if !defined(APR_OVERRIDE_ATOMIC_INC32) -apr_uint32_t apr_atomic_inc32(volatile apr_uint32_t *mem) -{ - return apr_atomic_add32(mem, 1); -} -#endif /* !defined(APR_OVERRIDE_ATOMIC_INC32) */ - -#if !defined(APR_OVERRIDE_ATOMIC_DEC32) -#if defined(APR_OVERRIDE_ATOMIC_CAS32) -int apr_atomic_dec32(volatile apr_uint32_t *mem) -{ - 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; -} -#else -int apr_atomic_dec32(volatile 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)); - (*mem)--; - new = *mem; - 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) */ - -#if !defined(APR_OVERRIDE_ATOMIC_CAS32) -apr_uint32_t apr_atomic_cas32(volatile 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)); - 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 */ - return prev; -} -#endif /* !defined(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) -{ - apr_uint32_t prev; - do { - prev = *mem; - } while (apr_atomic_cas32(mem, val, prev) != prev); - return prev; -} -#else -apr_uint32_t apr_atomic_xchg32(volatile 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; - *mem = val; - CHECK(apr_thread_mutex_unlock(lock)); -#else - prev = *mem; - *mem = val; -#endif /* APR_HAS_THREADS */ - return prev; -} -#endif /* defined(APR_OVERRIDE_ATOMIC_CAS32) */ -#endif /* !defined(APR_OVERRIDE_ATOMIC_XCHG32) */ - -#if !defined(APR_OVERRIDE_ATOMIC_CASPTR) -void *apr_atomic_casptr(volatile void **mem, void *with, const void *cmp) -{ - void *prev; -#if APR_HAS_THREADS - apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)]; - - 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 */ - 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) -{ - return *mem; -} -#endif - Index: apr/include/arch/unix/apr_arch_atomic.h =================================================================== --- /dev/null +++ apr/include/arch/unix/apr_arch_atomic.h @@ -0,0 +1,35 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ATOMIC_H +#define ATOMIC_H + +#include "apr.h" +#include "apr_private.h" +#include "apr_atomic.h" +#include "apr_thread_mutex.h" + +#if defined(USE_ATOMICS_GENERIC) +/* noop */ +#elif defined(__GNUC__) && defined(__STRICT_ANSI__) +/* force use of generic atomics if building e.g. with -std=c89, which + * doesn't allow inline asm */ +# define USE_ATOMICS_GENERIC +#else +# define USE_ATOMICS_GENERIC +#endif + +#endif /* ATOMIC_H */ Index: apr/configure.in =================================================================== --- apr.orig/configure.in +++ apr/configure.in @@ -495,7 +495,7 @@ esac ]) if test $force_generic_atomics = yes; then - AC_DEFINE([USE_GENERIC_ATOMICS], 1, + AC_DEFINE([USE_ATOMICS_GENERIC], 1, [Define if use of generic atomics is requested]) fi