bottleneck testcase based on rubbos
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / srclib / apr / include / apr_atomic.h
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #ifndef APR_ATOMIC_H
18 #define APR_ATOMIC_H
19
20 /**
21  * @file apr_atomic.h
22  * @brief APR Atomic Operations
23  */
24
25 #include "apr.h"
26 #include "apr_pools.h"
27
28 /* Platform includes for atomics */
29 #if defined(NETWARE) || defined(__MVS__) /* OS/390 */
30 #include <stdlib.h>
31 #elif defined(__FreeBSD__)
32 #include <machine/atomic.h>
33 #endif
34
35 #ifdef __cplusplus
36 extern "C" {
37 #endif
38
39 /**
40  * @defgroup apr_atomic Atomic Operations
41  * @ingroup APR 
42  * @{
43  */
44
45 /* easiest way to get these documented for the moment */
46 #if defined(DOXYGEN)
47 /**
48  * structure for holding a atomic value.
49  * this number >only< has a 24 bit size on some platforms
50  */
51 typedef apr_atomic_t;
52
53 /**
54  * this function is required on some platforms to initialize the
55  * atomic operation's internal structures
56  * @param p pool
57  * @return APR_SUCCESS on successful completion
58  */
59 apr_status_t apr_atomic_init(apr_pool_t *p);
60 /**
61  * read the value stored in a atomic variable
62  * @param mem the pointer
63  * @warning on certain platforms this number is not stored
64  * directly in the pointer. in others it is 
65  */
66 apr_uint32_t apr_atomic_read(volatile apr_atomic_t *mem);
67 /**
68  * set the value for atomic.
69  * @param mem the pointer
70  * @param val the value
71  */
72 void apr_atomic_set(volatile apr_atomic_t *mem, apr_uint32_t val);
73 /**
74  * Add 'val' to the atomic variable
75  * @param mem pointer to the atomic value
76  * @param val the addition
77  */
78 void apr_atomic_add(volatile apr_atomic_t *mem, apr_uint32_t val);
79
80 /**
81  * increment the atomic variable by 1
82  * @param mem pointer to the atomic value
83  */
84 void apr_atomic_inc(volatile apr_atomic_t *mem);
85
86 /**
87  * decrement the atomic variable by 1
88  * @param mem pointer to the atomic value
89  * @return zero if the value is zero, otherwise non-zero
90  */
91 int apr_atomic_dec(volatile apr_atomic_t *mem);
92
93 /**
94  * compare the atomic's value with cmp.
95  * If they are the same swap the value with 'with'
96  * @param mem pointer to the atomic value
97  * @param with what to swap it with
98  * @param cmp the value to compare it to
99  * @return the old value of the atomic
100  * @warning do not mix apr_atomic's with the CAS function.
101  * on some platforms they may be implemented by different mechanisms
102  */
103 apr_uint32_t apr_atomic_cas(volatile apr_uint32_t *mem, long with, long cmp);
104
105 /**
106  * compare the pointer's value with cmp.
107  * If they are the same swap the value with 'with'
108  * @param mem pointer to the pointer
109  * @param with what to swap it with
110  * @param cmp the value to compare it to
111  * @return the old value of the pointer
112  */
113 void *apr_atomic_casptr(volatile void **mem, void *with, const void *cmp);
114 #else /* !DOXYGEN */
115
116 /* The following definitions provide optimized, OS-specific
117  * implementations of the APR atomic functions on various
118  * platforms.  Any atomic operation that isn't redefined as
119  * a macro here will be declared as a function later, and
120  * apr_atomic.c will provide a mutex-based default implementation.
121  */
122
123 #if defined(WIN32)
124
125 #define apr_atomic_t LONG
126
127 #define apr_atomic_add(mem, val)     InterlockedExchangeAdd(mem,val)
128 #define apr_atomic_dec(mem)          InterlockedDecrement(mem)
129 #define apr_atomic_inc(mem)          InterlockedIncrement(mem)
130 #define apr_atomic_set(mem, val)     InterlockedExchange(mem, val)
131 #define apr_atomic_read(mem)         (*mem)
132 #define apr_atomic_cas(mem,with,cmp) InterlockedCompareExchange(mem,with,cmp)
133 #define apr_atomic_init(pool)        APR_SUCCESS
134 #define apr_atomic_casptr(mem,with,cmp) InterlockedCompareExchangePointer(mem,with,cmp)
135
136 #elif defined(NETWARE)
137
138 #define apr_atomic_t unsigned long
139
140 #define apr_atomic_add(mem, val)     atomic_add(mem,val)
141 #define apr_atomic_inc(mem)          atomic_inc(mem)
142 #define apr_atomic_set(mem, val)     (*mem = val)
143 #define apr_atomic_read(mem)         (*mem)
144 #define apr_atomic_init(pool)        APR_SUCCESS
145 #define apr_atomic_cas(mem,with,cmp) atomic_cmpxchg((unsigned long *)(mem),(unsigned long)(cmp),(unsigned long)(with))
146     
147 int apr_atomic_dec(apr_atomic_t *mem);
148 void *apr_atomic_casptr(void **mem, void *with, const void *cmp);
149 #define APR_OVERRIDE_ATOMIC_DEC 1
150 #define APR_OVERRIDE_ATOMIC_CASPTR 1
151
152 inline int apr_atomic_dec(apr_atomic_t *mem) 
153 {
154     return (atomic_xchgadd(mem, 0xFFFFFFFF) - 1);
155 }
156
157 inline void *apr_atomic_casptr(void **mem, void *with, const void *cmp)
158 {
159     return (void*)atomic_cmpxchg((unsigned long *)mem,(unsigned long)cmp,(unsigned long)with);
160 }
161
162 #elif defined(__FreeBSD__)
163
164 #define apr_atomic_t apr_uint32_t
165 #define apr_atomic_add(mem, val)     (atomic_add_int(mem,val),mem)
166 #define apr_atomic_dec(mem)          (atomic_subtract_int(mem,1),mem)
167 #define apr_atomic_inc(mem)          (atomic_add_int(mem,1),mem)
168 #define apr_atomic_set(mem, val)     (atomic_set_int(mem, val),mem)
169 #define apr_atomic_read(mem)         (*mem)
170
171 #elif (defined(__linux__) || defined(__EMX__)) && defined(__i386__) && !APR_FORCE_ATOMIC_GENERIC
172
173 #define apr_atomic_t apr_uint32_t
174 #define apr_atomic_cas(mem,with,cmp) \
175 ({ apr_atomic_t prev; \
176     asm volatile ("lock; cmpxchgl %1, %2"              \
177          : "=a" (prev)               \
178          : "r" (with), "m" (*(mem)), "0"(cmp) \
179          : "memory"); \
180     prev;})
181
182 #define apr_atomic_add(mem, val)                                \
183 ({ register apr_atomic_t last;                                  \
184    do {                                                         \
185        last = *(mem);                                           \
186    } while (apr_atomic_cas((mem), last + (val), last) != last); \
187   })
188
189 #define apr_atomic_dec(mem)                                     \
190 ({ register apr_atomic_t last;                                  \
191    do {                                                         \
192        last = *(mem);                                           \
193    } while (apr_atomic_cas((mem), last - 1, last) != last);     \
194   (--last != 0); })
195
196 #define apr_atomic_inc(mem)                                     \
197 ({ register apr_atomic_t last;                                  \
198    do {                                                         \
199        last = *(mem);                                           \
200    } while (apr_atomic_cas((mem), last + 1, last) != last);     \
201   })
202
203 #define apr_atomic_set(mem, val)     (*(mem) = val)
204 #define apr_atomic_read(mem)        (*(mem))
205 #define apr_atomic_init(pool)        APR_SUCCESS
206
207 #elif defined(__MVS__) /* OS/390 */
208
209 #define apr_atomic_t cs_t
210
211 apr_int32_t apr_atomic_add(volatile apr_atomic_t *mem, apr_int32_t val);
212 apr_uint32_t apr_atomic_cas(volatile apr_atomic_t *mem, apr_uint32_t swap, 
213                             apr_uint32_t cmp);
214 #define APR_OVERRIDE_ATOMIC_ADD 1
215 #define APR_OVERRIDE_ATOMIC_CAS 1
216
217 #define apr_atomic_inc(mem)          apr_atomic_add(mem, 1)
218 #define apr_atomic_dec(mem)          apr_atomic_add(mem, -1)
219 #define apr_atomic_init(pool)        APR_SUCCESS
220
221 /* warning: the following two operations, _read and _set, are atomic
222  * if the memory variables are aligned (the usual case).  
223  * 
224  * If you try really hard and manage to mis-align them, they are not 
225  * guaranteed to be atomic on S/390.  But then your program will blow up 
226  * with SIGBUS on a sparc, or with a S0C6 abend if you use the mis-aligned 
227  * variables with other apr_atomic_* operations on OS/390.
228  */
229
230 #define apr_atomic_read(p)           (*p)
231 #define apr_atomic_set(mem, val)     (*mem = val)
232
233 #endif /* end big if-elseif switch for platform-specifics */
234
235
236 /* Default implementation of the atomic API
237  * The definitions above may override some or all of the
238  * atomic functions with optimized, platform-specific versions.
239  * Any operation that hasn't been overridden as a macro above
240  * is declared as a function here, unless APR_OVERRIDE_ATOMIC_[OPERATION]
241  * is defined.  (The purpose of the APR_OVERRIDE_ATOMIC_* is
242  * to allow a platform to declare an apr_atomic_*() function
243  * with a different signature than the default.)
244  */
245
246 #if !defined(apr_atomic_t)
247 #define apr_atomic_t apr_uint32_t
248 #endif
249
250 #if !defined(apr_atomic_init) && !defined(APR_OVERRIDE_ATOMIC_INIT)
251 apr_status_t apr_atomic_init(apr_pool_t *p);
252 #endif
253
254 #if !defined(apr_atomic_read) && !defined(APR_OVERRIDE_ATOMIC_READ)
255 #define apr_atomic_read(p)  *p
256 #endif
257
258 #if !defined(apr_atomic_set) && !defined(APR_OVERRIDE_ATOMIC_SET)
259 void apr_atomic_set(volatile apr_atomic_t *mem, apr_uint32_t val);
260 #define APR_ATOMIC_NEED_DEFAULT_INIT 1
261 #endif
262
263 #if !defined(apr_atomic_add) && !defined(APR_OVERRIDE_ATOMIC_ADD)
264 void apr_atomic_add(volatile apr_atomic_t *mem, apr_uint32_t val);
265 #define APR_ATOMIC_NEED_DEFAULT_INIT 1
266 #endif
267
268 #if !defined(apr_atomic_inc) && !defined(APR_OVERRIDE_ATOMIC_INC)
269 void apr_atomic_inc(volatile apr_atomic_t *mem);
270 #define APR_ATOMIC_NEED_DEFAULT_INIT 1
271 #endif
272
273 #if !defined(apr_atomic_dec) && !defined(APR_OVERRIDE_ATOMIC_DEC)
274 int apr_atomic_dec(volatile apr_atomic_t *mem);
275 #define APR_ATOMIC_NEED_DEFAULT_INIT 1
276 #endif
277
278 #if !defined(apr_atomic_cas) && !defined(APR_OVERRIDE_ATOMIC_CAS)
279 apr_uint32_t apr_atomic_cas(volatile apr_uint32_t *mem,long with,long cmp);
280 #define APR_ATOMIC_NEED_DEFAULT_INIT 1
281 #endif
282
283 #if !defined(apr_atomic_casptr) && !defined(APR_OVERRIDE_ATOMIC_CASPTR)
284 #if APR_SIZEOF_VOIDP == 4
285 #define apr_atomic_casptr(mem, with, cmp) (void *)apr_atomic_cas((apr_uint32_t *)(mem), (long)(with), (long)cmp)
286 #else
287 void *apr_atomic_casptr(volatile void **mem, void *with, const void *cmp);
288 #define APR_ATOMIC_NEED_DEFAULT_INIT 1
289 #endif
290 #endif
291
292 #ifndef APR_ATOMIC_NEED_DEFAULT_INIT
293 #define APR_ATOMIC_NEED_DEFAULT_INIT 0
294 #endif
295
296 /* If we're using the default versions of any of the atomic functions,
297  * we'll need the atomic init to set up mutexes.  If a platform-specific
298  * override above has replaced the atomic_init with a macro, it's an error.
299  */
300 #if APR_ATOMIC_NEED_DEFAULT_INIT
301 #if defined(apr_atomic_init) || defined(APR_OVERRIDE_ATOMIC_INIT)
302 #error Platform has redefined apr_atomic_init, but other default default atomics require a default apr_atomic_init
303 #endif
304 #endif /* APR_ATOMIC_NEED_DEFAULT_INIT */
305
306 #endif /* !DOXYGEN */
307
308 /** @} */
309
310 #ifdef __cplusplus
311 }
312 #endif
313
314 #endif  /* !APR_ATOMIC_H */