Main Page | Modules | Data Structures | File List | Data Fields | Globals | Related Pages

apr_atomic.h

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

Generated on Wed Dec 8 10:14:03 2004 for Apache Portable Runtime by doxygen 1.3.6