apr_atomic.h

Go to the documentation of this file.
00001 /* Licensed to the Apache Software Foundation (ASF) under one or more
00002  * contributor license agreements.  See the NOTICE file distributed with
00003  * this work for additional information regarding copyright ownership.
00004  * The ASF licenses this file to You under the Apache License, Version 2.0
00005  * (the "License"); you may not use this file except in compliance with
00006  * the License.  You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #ifndef APR_ATOMIC_H
00018 #define APR_ATOMIC_H
00019 
00025 #include "apr.h"
00026 #include "apr_pools.h"
00027 
00028 /* Platform includes for atomics */
00029 #if defined(NETWARE) || defined(__MVS__) /* OS/390 */
00030 #include <stdlib.h>
00031 #elif defined(__FreeBSD__)
00032 #include <machine/atomic.h>
00033 #endif
00034 
00035 #ifdef __cplusplus
00036 extern "C" {
00037 #endif
00038 
00045 /* easiest way to get these documented for the moment */
00046 #if defined(DOXYGEN)
00047 
00051 typedef apr_atomic_t;
00052 
00059 apr_status_t apr_atomic_init(apr_pool_t *p);
00066 apr_uint32_t apr_atomic_read(volatile apr_atomic_t *mem);
00072 void apr_atomic_set(volatile apr_atomic_t *mem, apr_uint32_t val);
00078 void apr_atomic_add(volatile apr_atomic_t *mem, apr_uint32_t val);
00079 
00084 void apr_atomic_inc(volatile apr_atomic_t *mem);
00085 
00091 int apr_atomic_dec(volatile apr_atomic_t *mem);
00092 
00103 apr_uint32_t apr_atomic_cas(volatile apr_uint32_t *mem, long with, long cmp);
00104 
00113 void *apr_atomic_casptr(volatile void **mem, void *with, const void *cmp);
00114 #else /* !DOXYGEN */
00115 
00116 /* The following definitions provide optimized, OS-specific
00117  * implementations of the APR atomic functions on various
00118  * platforms.  Any atomic operation that isn't redefined as
00119  * a macro here will be declared as a function later, and
00120  * apr_atomic.c will provide a mutex-based default implementation.
00121  */
00122 
00123 #if defined(WIN32)
00124 
00125 #define apr_atomic_t LONG
00126 
00127 #define apr_atomic_add(mem, val)     InterlockedExchangeAdd(mem,val)
00128 #define apr_atomic_dec(mem)          InterlockedDecrement(mem)
00129 #define apr_atomic_inc(mem)          InterlockedIncrement(mem)
00130 #define apr_atomic_set(mem, val)     InterlockedExchange(mem, val)
00131 #define apr_atomic_read(mem)         (*mem)
00132 #define apr_atomic_cas(mem,with,cmp) InterlockedCompareExchange(mem,with,cmp)
00133 #define apr_atomic_init(pool)        APR_SUCCESS
00134 #define apr_atomic_casptr(mem,with,cmp) InterlockedCompareExchangePointer(mem,with,cmp)
00135 
00136 #elif defined(NETWARE)
00137 
00138 #define apr_atomic_t unsigned long
00139 
00140 #define apr_atomic_add(mem, val)     atomic_add(mem,val)
00141 #define apr_atomic_inc(mem)          atomic_inc(mem)
00142 #define apr_atomic_set(mem, val)     (*mem = val)
00143 #define apr_atomic_read(mem)         (*mem)
00144 #define apr_atomic_init(pool)        APR_SUCCESS
00145 #define apr_atomic_cas(mem,with,cmp) atomic_cmpxchg((unsigned long *)(mem),(unsigned long)(cmp),(unsigned long)(with))
00146     
00147 int apr_atomic_dec(apr_atomic_t *mem);
00148 void *apr_atomic_casptr(void **mem, void *with, const void *cmp);
00149 #define APR_OVERRIDE_ATOMIC_DEC 1
00150 #define APR_OVERRIDE_ATOMIC_CASPTR 1
00151 
00152 inline int apr_atomic_dec(apr_atomic_t *mem) 
00153 {
00154     return (atomic_xchgadd(mem, 0xFFFFFFFF) - 1);
00155 }
00156 
00157 inline void *apr_atomic_casptr(void **mem, void *with, const void *cmp)
00158 {
00159     return (void*)atomic_cmpxchg((unsigned long *)mem,(unsigned long)cmp,(unsigned long)with);
00160 }
00161 
00162 #elif defined(__FreeBSD__)
00163 
00164 #define apr_atomic_t apr_uint32_t
00165 #define apr_atomic_add(mem, val)     (atomic_add_int(mem,val),mem)
00166 #define apr_atomic_dec(mem)          (atomic_subtract_int(mem,1),mem)
00167 #define apr_atomic_inc(mem)          (atomic_add_int(mem,1),mem)
00168 #define apr_atomic_set(mem, val)     (atomic_set_int(mem, val),mem)
00169 #define apr_atomic_read(mem)         (*mem)
00170 
00171 #elif (defined(__linux__) || defined(__EMX__)) && defined(__i386__) && !APR_FORCE_ATOMIC_GENERIC
00172 
00173 #define apr_atomic_t apr_uint32_t
00174 #define apr_atomic_cas(mem,with,cmp) \
00175 ({ apr_atomic_t prev; \
00176     asm volatile ("lock; cmpxchgl %1, %2"              \
00177          : "=a" (prev)               \
00178          : "r" (with), "m" (*(mem)), "0"(cmp) \
00179          : "memory"); \
00180     prev;})
00181 
00182 #define apr_atomic_add(mem, val)                                \
00183 ({ register apr_atomic_t last;                                  \
00184    do {                                                         \
00185        last = *(mem);                                           \
00186    } while (apr_atomic_cas((mem), last + (val), last) != last); \
00187   })
00188 
00189 #define apr_atomic_dec(mem)                                     \
00190 ({ register apr_atomic_t last;                                  \
00191    do {                                                         \
00192        last = *(mem);                                           \
00193    } while (apr_atomic_cas((mem), last - 1, last) != last);     \
00194   (--last != 0); })
00195 
00196 #define apr_atomic_inc(mem)                                     \
00197 ({ register apr_atomic_t last;                                  \
00198    do {                                                         \
00199        last = *(mem);                                           \
00200    } while (apr_atomic_cas((mem), last + 1, last) != last);     \
00201   })
00202 
00203 #define apr_atomic_set(mem, val)     (*(mem) = val)
00204 #define apr_atomic_read(mem)        (*(mem))
00205 #define apr_atomic_init(pool)        APR_SUCCESS
00206 
00207 #elif defined(__MVS__) /* OS/390 */
00208 
00209 #define apr_atomic_t cs_t
00210 
00211 apr_int32_t apr_atomic_add(volatile apr_atomic_t *mem, apr_int32_t val);
00212 apr_uint32_t apr_atomic_cas(volatile apr_atomic_t *mem, apr_uint32_t swap, 
00213                             apr_uint32_t cmp);
00214 #define APR_OVERRIDE_ATOMIC_ADD 1
00215 #define APR_OVERRIDE_ATOMIC_CAS 1
00216 
00217 #define apr_atomic_inc(mem)          apr_atomic_add(mem, 1)
00218 #define apr_atomic_dec(mem)          apr_atomic_add(mem, -1)
00219 #define apr_atomic_init(pool)        APR_SUCCESS
00220 
00221 /* warning: the following two operations, _read and _set, are atomic
00222  * if the memory variables are aligned (the usual case).  
00223  * 
00224  * If you try really hard and manage to mis-align them, they are not 
00225  * guaranteed to be atomic on S/390.  But then your program will blow up 
00226  * with SIGBUS on a sparc, or with a S0C6 abend if you use the mis-aligned 
00227  * variables with other apr_atomic_* operations on OS/390.
00228  */
00229 
00230 #define apr_atomic_read(p)           (*p)
00231 #define apr_atomic_set(mem, val)     (*mem = val)
00232 
00233 #endif /* end big if-elseif switch for platform-specifics */
00234 
00235 
00236 /* Default implementation of the atomic API
00237  * The definitions above may override some or all of the
00238  * atomic functions with optimized, platform-specific versions.
00239  * Any operation that hasn't been overridden as a macro above
00240  * is declared as a function here, unless APR_OVERRIDE_ATOMIC_[OPERATION]
00241  * is defined.  (The purpose of the APR_OVERRIDE_ATOMIC_* is
00242  * to allow a platform to declare an apr_atomic_*() function
00243  * with a different signature than the default.)
00244  */
00245 
00246 #if !defined(apr_atomic_t)
00247 #define apr_atomic_t apr_uint32_t
00248 #endif
00249 
00250 #if !defined(apr_atomic_init) && !defined(APR_OVERRIDE_ATOMIC_INIT)
00251 apr_status_t apr_atomic_init(apr_pool_t *p);
00252 #endif
00253 
00254 #if !defined(apr_atomic_read) && !defined(APR_OVERRIDE_ATOMIC_READ)
00255 #define apr_atomic_read(p)  *p
00256 #endif
00257 
00258 #if !defined(apr_atomic_set) && !defined(APR_OVERRIDE_ATOMIC_SET)
00259 void apr_atomic_set(volatile apr_atomic_t *mem, apr_uint32_t val);
00260 #define APR_ATOMIC_NEED_DEFAULT_INIT 1
00261 #endif
00262 
00263 #if !defined(apr_atomic_add) && !defined(APR_OVERRIDE_ATOMIC_ADD)
00264 void apr_atomic_add(volatile apr_atomic_t *mem, apr_uint32_t val);
00265 #define APR_ATOMIC_NEED_DEFAULT_INIT 1
00266 #endif
00267 
00268 #if !defined(apr_atomic_inc) && !defined(APR_OVERRIDE_ATOMIC_INC)
00269 void apr_atomic_inc(volatile apr_atomic_t *mem);
00270 #define APR_ATOMIC_NEED_DEFAULT_INIT 1
00271 #endif
00272 
00273 #if !defined(apr_atomic_dec) && !defined(APR_OVERRIDE_ATOMIC_DEC)
00274 int apr_atomic_dec(volatile apr_atomic_t *mem);
00275 #define APR_ATOMIC_NEED_DEFAULT_INIT 1
00276 #endif
00277 
00278 #if !defined(apr_atomic_cas) && !defined(APR_OVERRIDE_ATOMIC_CAS)
00279 apr_uint32_t apr_atomic_cas(volatile apr_uint32_t *mem,long with,long cmp);
00280 #define APR_ATOMIC_NEED_DEFAULT_INIT 1
00281 #endif
00282 
00283 #if !defined(apr_atomic_casptr) && !defined(APR_OVERRIDE_ATOMIC_CASPTR)
00284 #if APR_SIZEOF_VOIDP == 4
00285 #define apr_atomic_casptr(mem, with, cmp) (void *)apr_atomic_cas((apr_uint32_t *)(mem), (long)(with), (long)cmp)
00286 #else
00287 void *apr_atomic_casptr(volatile void **mem, void *with, const void *cmp);
00288 #define APR_ATOMIC_NEED_DEFAULT_INIT 1
00289 #endif
00290 #endif
00291 
00292 #ifndef APR_ATOMIC_NEED_DEFAULT_INIT
00293 #define APR_ATOMIC_NEED_DEFAULT_INIT 0
00294 #endif
00295 
00296 /* If we're using the default versions of any of the atomic functions,
00297  * we'll need the atomic init to set up mutexes.  If a platform-specific
00298  * override above has replaced the atomic_init with a macro, it's an error.
00299  */
00300 #if APR_ATOMIC_NEED_DEFAULT_INIT
00301 #if defined(apr_atomic_init) || defined(APR_OVERRIDE_ATOMIC_INIT)
00302 #error Platform has redefined apr_atomic_init, but other default default atomics require a default apr_atomic_init
00303 #endif
00304 #endif /* APR_ATOMIC_NEED_DEFAULT_INIT */
00305 
00306 #endif /* !DOXYGEN */
00307 
00310 #ifdef __cplusplus
00311 }
00312 #endif
00313 
00314 #endif  /* !APR_ATOMIC_H */

Generated on Mon Nov 26 11:47:26 2007 for Apache Portable Runtime by  doxygen 1.5.2