1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more 2251875Speter * contributor license agreements. See the NOTICE file distributed with 3251875Speter * this work for additional information regarding copyright ownership. 4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0 5251875Speter * (the "License"); you may not use this file except in compliance with 6251875Speter * the License. You may obtain a copy of the License at 7251875Speter * 8251875Speter * http://www.apache.org/licenses/LICENSE-2.0 9251875Speter * 10251875Speter * Unless required by applicable law or agreed to in writing, software 11251875Speter * distributed under the License is distributed on an "AS IS" BASIS, 12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13251875Speter * See the License for the specific language governing permissions and 14251875Speter * limitations under the License. 15251875Speter */ 16251875Speter 17251875Speter#include "apr_arch_atomic.h" 18251875Speter 19251875Speter#ifdef USE_ATOMICS_GENERIC 20251875Speter 21251875Speter#include <stdlib.h> 22251875Speter 23251875Speter#if APR_HAS_THREADS 24251875Speter# define DECLARE_MUTEX_LOCKED(name, mem) \ 25251875Speter apr_thread_mutex_t *name = mutex_hash(mem) 26251875Speter# define MUTEX_UNLOCK(name) \ 27251875Speter do { \ 28251875Speter if (apr_thread_mutex_unlock(name) != APR_SUCCESS) \ 29251875Speter abort(); \ 30251875Speter } while (0) 31251875Speter#else 32251875Speter# define DECLARE_MUTEX_LOCKED(name, mem) 33251875Speter# define MUTEX_UNLOCK(name) 34251875Speter# warning Be warned: using stubs for all atomic operations 35251875Speter#endif 36251875Speter 37251875Speter#if APR_HAS_THREADS 38251875Speter 39251875Speterstatic apr_thread_mutex_t **hash_mutex; 40251875Speter 41251875Speter#define NUM_ATOMIC_HASH 7 42251875Speter/* shift by 2 to get rid of alignment issues */ 43251875Speter#define ATOMIC_HASH(x) (unsigned int)(((unsigned long)(x)>>2)%(unsigned int)NUM_ATOMIC_HASH) 44251875Speter 45251875Speterstatic apr_status_t atomic_cleanup(void *data) 46251875Speter{ 47251875Speter if (hash_mutex == data) 48251875Speter hash_mutex = NULL; 49251875Speter 50251875Speter return APR_SUCCESS; 51251875Speter} 52251875Speter 53251875SpeterAPR_DECLARE(apr_status_t) apr_atomic_init(apr_pool_t *p) 54251875Speter{ 55251875Speter int i; 56251875Speter apr_status_t rv; 57251875Speter 58251875Speter if (hash_mutex != NULL) 59251875Speter return APR_SUCCESS; 60251875Speter 61251875Speter hash_mutex = apr_palloc(p, sizeof(apr_thread_mutex_t*) * NUM_ATOMIC_HASH); 62251875Speter apr_pool_cleanup_register(p, hash_mutex, atomic_cleanup, 63251875Speter apr_pool_cleanup_null); 64251875Speter 65251875Speter for (i = 0; i < NUM_ATOMIC_HASH; i++) { 66251875Speter rv = apr_thread_mutex_create(&(hash_mutex[i]), 67251875Speter APR_THREAD_MUTEX_DEFAULT, p); 68251875Speter if (rv != APR_SUCCESS) { 69251875Speter return rv; 70251875Speter } 71251875Speter } 72251875Speter 73251875Speter return APR_SUCCESS; 74251875Speter} 75251875Speter 76251875Speterstatic APR_INLINE apr_thread_mutex_t *mutex_hash(volatile apr_uint32_t *mem) 77251875Speter{ 78251875Speter apr_thread_mutex_t *mutex = hash_mutex[ATOMIC_HASH(mem)]; 79251875Speter 80251875Speter if (apr_thread_mutex_lock(mutex) != APR_SUCCESS) { 81251875Speter abort(); 82251875Speter } 83251875Speter 84251875Speter return mutex; 85251875Speter} 86251875Speter 87251875Speter#else 88251875Speter 89251875SpeterAPR_DECLARE(apr_status_t) apr_atomic_init(apr_pool_t *p) 90251875Speter{ 91251875Speter return APR_SUCCESS; 92251875Speter} 93251875Speter 94251875Speter#endif /* APR_HAS_THREADS */ 95251875Speter 96251875SpeterAPR_DECLARE(apr_uint32_t) apr_atomic_read32(volatile apr_uint32_t *mem) 97251875Speter{ 98251875Speter return *mem; 99251875Speter} 100251875Speter 101251875SpeterAPR_DECLARE(void) apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val) 102251875Speter{ 103251875Speter DECLARE_MUTEX_LOCKED(mutex, mem); 104251875Speter 105251875Speter *mem = val; 106251875Speter 107251875Speter MUTEX_UNLOCK(mutex); 108251875Speter} 109251875Speter 110251875SpeterAPR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val) 111251875Speter{ 112251875Speter apr_uint32_t old_value; 113251875Speter DECLARE_MUTEX_LOCKED(mutex, mem); 114251875Speter 115251875Speter old_value = *mem; 116251875Speter *mem += val; 117251875Speter 118251875Speter MUTEX_UNLOCK(mutex); 119251875Speter 120251875Speter return old_value; 121251875Speter} 122251875Speter 123251875SpeterAPR_DECLARE(void) apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val) 124251875Speter{ 125251875Speter DECLARE_MUTEX_LOCKED(mutex, mem); 126251875Speter *mem -= val; 127251875Speter MUTEX_UNLOCK(mutex); 128251875Speter} 129251875Speter 130251875SpeterAPR_DECLARE(apr_uint32_t) apr_atomic_inc32(volatile apr_uint32_t *mem) 131251875Speter{ 132251875Speter return apr_atomic_add32(mem, 1); 133251875Speter} 134251875Speter 135251875SpeterAPR_DECLARE(int) apr_atomic_dec32(volatile apr_uint32_t *mem) 136251875Speter{ 137251875Speter apr_uint32_t new; 138251875Speter DECLARE_MUTEX_LOCKED(mutex, mem); 139251875Speter 140251875Speter (*mem)--; 141251875Speter new = *mem; 142251875Speter 143251875Speter MUTEX_UNLOCK(mutex); 144251875Speter 145251875Speter return new; 146251875Speter} 147251875Speter 148251875SpeterAPR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t *mem, apr_uint32_t with, 149251875Speter apr_uint32_t cmp) 150251875Speter{ 151251875Speter apr_uint32_t prev; 152251875Speter DECLARE_MUTEX_LOCKED(mutex, mem); 153251875Speter 154251875Speter prev = *mem; 155251875Speter if (prev == cmp) { 156251875Speter *mem = with; 157251875Speter } 158251875Speter 159251875Speter MUTEX_UNLOCK(mutex); 160251875Speter 161251875Speter return prev; 162251875Speter} 163251875Speter 164251875SpeterAPR_DECLARE(apr_uint32_t) apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val) 165251875Speter{ 166251875Speter apr_uint32_t prev; 167251875Speter DECLARE_MUTEX_LOCKED(mutex, mem); 168251875Speter 169251875Speter prev = *mem; 170251875Speter *mem = val; 171251875Speter 172251875Speter MUTEX_UNLOCK(mutex); 173251875Speter 174251875Speter return prev; 175251875Speter} 176251875Speter 177251875SpeterAPR_DECLARE(void*) apr_atomic_casptr(volatile void **mem, void *with, const void *cmp) 178251875Speter{ 179251875Speter void *prev; 180251875Speter DECLARE_MUTEX_LOCKED(mutex, *mem); 181251875Speter 182251875Speter prev = *(void **)mem; 183251875Speter if (prev == cmp) { 184251875Speter *mem = with; 185251875Speter } 186251875Speter 187251875Speter MUTEX_UNLOCK(mutex); 188251875Speter 189251875Speter return prev; 190251875Speter} 191251875Speter 192251875SpeterAPR_DECLARE(void*) apr_atomic_xchgptr(volatile void **mem, void *with) 193251875Speter{ 194251875Speter void *prev; 195251875Speter DECLARE_MUTEX_LOCKED(mutex, *mem); 196251875Speter 197251875Speter prev = *(void **)mem; 198251875Speter *mem = with; 199251875Speter 200251875Speter MUTEX_UNLOCK(mutex); 201251875Speter 202251875Speter return prev; 203251875Speter} 204251875Speter 205251875Speter#endif /* USE_ATOMICS_GENERIC */ 206