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