blocxx
|
00001 /******************************************************************************* 00002 * Copyright (C) 2005, Vintela, Inc. All rights reserved. 00003 * Copyright (C) 2006, Novell, Inc. All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * * Redistributions of source code must retain the above copyright notice, 00009 * this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Neither the name of 00014 * Vintela, Inc., 00015 * nor Novell, Inc., 00016 * nor the names of its contributors or employees may be used to 00017 * endorse or promote products derived from this software without 00018 * specific prior written permission. 00019 * 00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00021 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00022 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00023 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00024 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00025 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00026 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00029 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00030 * POSSIBILITY OF SUCH DAMAGE. 00031 *******************************************************************************/ 00032 00033 00039 #ifndef BLOCXX_ATOMIC_OPS_HPP_ 00040 #define BLOCXX_ATOMIC_OPS_HPP_ 00041 #include "blocxx/BLOCXX_config.h" 00042 00043 #if defined(BLOCXX_AIX) 00044 extern "C" 00045 { 00046 #include <sys/atomic_op.h> 00047 } 00048 #elif defined(__HP_aCC) && defined(BLOCXX_ARCH_IA64) 00049 #include <machine/sys/inline.h> 00050 #endif 00051 00052 00053 // TODO: PA-RISC and itanium. IA64 is supported for aCC, but not for gcc. 00054 // See http://h21007.www2.hp.com/dspp/files/unprotected/Itanium/spinlocks.pdf 00055 // http://www.hpl.hp.com/research/linux/atomic_ops/ 00056 00057 // The classes and functions defined in this file are not meant for general 00058 // use, they are internal implementation details. They may change at any time. 00059 00060 // x86 and x86-64 asm is identical 00061 #if (defined(BLOCXX_ARCH_X86) || defined(__i386__) || defined(BLOCXX_ARCH_X86_64) || defined(__x86_64__)) && defined(__GNUC__) 00062 00063 namespace BLOCXX_NAMESPACE 00064 { 00065 00066 // use fast inline assembly versions 00067 struct Atomic_t 00068 { 00069 Atomic_t() : val(0) {} 00070 Atomic_t(int i) : val(i) {} 00071 volatile int val; 00072 }; 00073 inline void AtomicInc(Atomic_t &v) 00074 { 00075 __asm__ __volatile__( 00076 "lock ; " "incl %0" 00077 :"=m" (v.val) 00078 :"m" (v.val)); 00079 } 00080 inline bool AtomicDecAndTest(Atomic_t &v) 00081 { 00082 unsigned char c; 00083 __asm__ __volatile__( 00084 "lock ; " "decl %0; sete %1" 00085 :"=m" (v.val), "=qm" (c) 00086 :"m" (v.val) : "memory"); 00087 return c != 0; 00088 } 00089 inline int AtomicGet(Atomic_t const &v) 00090 { 00091 return v.val; 00092 } 00093 inline void AtomicDec(Atomic_t &v) 00094 { 00095 __asm__ __volatile__( 00096 "lock ; " "decl %0" 00097 :"=m" (v.val) 00098 :"m" (v.val)); 00099 } 00100 00101 } // end namespace BLOCXX_NAMESPACE 00102 #elif defined(__HP_aCC) && defined(BLOCXX_ARCH_IA64) 00103 namespace BLOCXX_NAMESPACE 00104 { 00105 struct Atomic_t 00106 { 00107 Atomic_t() : val(0) {} 00108 Atomic_t(int i) : val(i) {} 00109 volatile int val; 00110 }; 00111 inline void AtomicInc(Atomic_t &v) 00112 { 00113 _Asm_fetchadd(_FASZ_W, _SEM_ACQ, &v.val, 1, _LDHINT_NONE); 00114 } 00115 inline bool AtomicDecAndTest(Atomic_t &v) 00116 { 00117 int c = int(_Asm_fetchadd(_FASZ_W, _SEM_ACQ, &v.val, int(-1), _LDHINT_NONE)); 00118 --c; 00119 return c == 0; 00120 } 00121 inline int AtomicGet(Atomic_t const &v) 00122 { 00123 return int(v.val); 00124 } 00125 inline void AtomicDec(Atomic_t &v) 00126 { 00127 _Asm_fetchadd(_FASZ_W, _SEM_ACQ, &v.val, -1, _LDHINT_NONE); 00128 } 00129 } 00130 00131 #elif defined(BLOCXX_AIX) 00132 namespace BLOCXX_NAMESPACE 00133 { 00134 // This comment was stolen from the libstdc++ implementation of atomicity.h 00135 // (and modified). 00136 // We cannot use the inline assembly for powerpc, since definitions for 00137 // these operations since they depend on operations that are not available on 00138 // the original POWER architecture. AIX still runs on the POWER architecture, 00139 // so it would be incorrect to assume the existence of these instructions. 00140 // 00141 // The definition of Atomic_t.val must match the type pointed to by atomic_p in 00142 // <sys/atomic_op.h>. 00143 struct Atomic_t 00144 { 00145 Atomic_t() : val(0) {} 00146 Atomic_t(int i) : val(i) {} 00147 volatile int val; 00148 }; 00149 00150 inline void AtomicInc(Atomic_t &v) 00151 { 00152 ::fetch_and_add(const_cast<atomic_p>(&v.val), 1); 00153 } 00154 inline bool AtomicDecAndTest(Atomic_t &v) 00155 { 00156 // fetch_and_add returns the original value before the add operation. Thus, 00157 // we must subtract one from the returned value before comparing. 00158 int c = ::fetch_and_add(const_cast<atomic_p>(&v.val), -1); 00159 --c; 00160 return c == 0; 00161 } 00162 inline int AtomicGet(Atomic_t const &v) 00163 { 00164 int c = ::fetch_and_add(const_cast<atomic_p>(&v.val), 0); 00165 return c; 00166 } 00167 inline void AtomicDec(Atomic_t &v) 00168 { 00169 ::fetch_and_add(const_cast<atomic_p>(&v.val), -1); 00170 } 00171 00172 } // end namespace BLOCXX_NAMESPACE 00173 00174 #elif (defined(BLOCXX_ARCH_PPC) || defined(__ppc__)) && defined(__GNUC__) 00175 00176 namespace BLOCXX_NAMESPACE 00177 { 00178 00179 // use fast inline assembly versions 00180 struct Atomic_t 00181 { 00182 Atomic_t() : val(0) {} 00183 Atomic_t(int i) : val(i) {} 00184 volatile int val; 00185 }; 00186 00187 inline void AtomicInc(Atomic_t &v) 00188 { 00189 int t; 00190 __asm__ __volatile__( 00191 "1: lwarx %0,0,%2\n" 00192 " addic %0,%0,1\n" 00193 " stwcx. %0,0,%2\n" 00194 " bne- 1b" 00195 : "=&r" (t), "=m" (v.val) 00196 : "r" (&v.val), "m" (v.val) 00197 : "cc"); 00198 } 00199 inline bool AtomicDecAndTest(Atomic_t &v) 00200 { 00201 int c; 00202 __asm__ __volatile__( 00203 "1: lwarx %0,0,%1\n" 00204 " addic %0,%0,-1\n" 00205 " stwcx. %0,0,%1\n" 00206 " bne- 1b\n" 00207 " isync" 00208 : "=&r" (c) 00209 : "r" (&v.val) 00210 : "cc", "memory"); 00211 return c == 0; 00212 } 00213 inline int AtomicGet(Atomic_t const &v) 00214 { 00215 return v.val; 00216 } 00217 inline void AtomicDec(Atomic_t &v) 00218 { 00219 int c; 00220 __asm__ __volatile__( 00221 "1: lwarx %0,0,%2\n" 00222 " addic %0,%0,-1\n" 00223 " stwcx. %0,0,%2\n" 00224 " bne- 1b" 00225 : "=&r" (c), "=m" (v.val) 00226 : "r" (&v.val), "m" (v.val) 00227 : "cc"); 00228 } 00229 00230 } // end namespace BLOCXX_NAMESPACE 00231 00232 #elif defined(BLOCXX_WIN32) 00233 00234 #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 00235 #include <wtypes.h> 00236 00237 namespace BLOCXX_NAMESPACE 00238 { 00239 00240 // use fast inline assembly versions 00241 struct BLOCXX_COMMON_API Atomic_t 00242 { 00243 Atomic_t() : val(0) {} 00244 Atomic_t(int i) : val(i) {} 00245 volatile long val; 00246 }; 00247 inline void AtomicInc(Atomic_t &v) 00248 { 00249 InterlockedIncrement(&v.val); 00250 } 00251 inline bool AtomicDecAndTest(Atomic_t &v) 00252 { 00253 return InterlockedDecrement(&v.val) == 0; 00254 } 00255 inline int AtomicGet(Atomic_t const &v) 00256 { 00257 return v.val; 00258 } 00259 inline void AtomicDec(Atomic_t &v) 00260 { 00261 InterlockedDecrement(&v.val); 00262 } 00263 00264 } // end namespace BLOCXX_NAMESPACE 00265 00266 #elif defined(BLOCXX_HAVE_PTHREAD_SPIN_LOCK) 00267 #include <pthread.h> 00268 00269 #define BLOCXX_USE_PTHREAD_SPIN_LOCK_ATOMIC_OPS // used in BLOCXX_AtomicOps.cpp 00270 00271 namespace BLOCXX_NAMESPACE 00272 { 00276 struct Atomic_t 00277 { 00282 Atomic_t(); 00283 00289 Atomic_t(int i); 00290 00292 int val; 00293 00294 pthread_spinlock_t spinlock; 00295 }; 00296 00301 void AtomicInc(Atomic_t &v); 00302 00308 bool AtomicDecAndTest(Atomic_t &v); 00314 int AtomicGet(Atomic_t const &v); 00315 00320 void AtomicDec(Atomic_t &v); 00321 00322 } // end namespace BLOCXX_NAMESPACE 00323 00324 #else 00325 // use slow mutex protected versions 00326 #define BLOCXX_USE_BLOCXX_DEFAULT_ATOMIC_OPS // used in BLOCXX_AtomicOps.cpp 00327 00328 namespace BLOCXX_NAMESPACE 00329 { 00330 00331 struct Atomic_t 00332 { 00333 Atomic_t() : val(0) {} 00334 Atomic_t(int i) : val(i) {} 00335 volatile int val; 00336 }; 00337 void AtomicInc(Atomic_t &v); 00338 bool AtomicDecAndTest(Atomic_t &v); 00339 int AtomicGet(Atomic_t const &v); 00340 void AtomicDec(Atomic_t &v); 00341 00342 } // end namespace BLOCXX_NAMESPACE 00343 00344 #endif 00345 #endif