AtomicOps.hpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 * Copyright (C) 2004 Vintela, Inc. All rights reserved.
00003 * Copyright (C) 2005 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 *
00011 *  - Redistributions in binary form must reproduce the above copyright notice,
00012 *    this list of conditions and the following disclaimer in the documentation
00013 *    and/or other materials provided with the distribution.
00014 *
00015 *  - Neither the name of Vintela, Inc., Novell, Inc., nor the names of its
00016 *    contributors may be used to endorse or promote products derived from this
00017 *    software without specific prior written permission.
00018 *
00019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
00020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00021 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00022 * ARE DISCLAIMED. IN NO EVENT SHALL Vintela, Inc., Novell, Inc., OR THE 
00023 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
00024 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
00025 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
00026 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
00027 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
00028 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
00029 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00030 *******************************************************************************/
00031 
00032 
00037 #ifndef BLOCXX_ATOMIC_OPS_HPP_
00038 #define BLOCXX_ATOMIC_OPS_HPP_
00039 #include "blocxx/BLOCXX_config.h"
00040 
00041 #if defined(BLOCXX_AIX)
00042 extern "C"
00043 {
00044 #include <sys/atomic_op.h>
00045 }
00046 #endif
00047 
00048 // The classes and functions defined in this file are not meant for general
00049 // use, they are internal implementation details.  They may change at any time.
00050 
00051 // x86 and x86-64 asm is identical
00052 #if (defined(BLOCXX_ARCH_X86) || defined(__i386__) || defined(BLOCXX_ARCH_X86_64) || defined(__x86_64__)) && defined(__GNUC__)
00053 
00054 namespace BLOCXX_NAMESPACE
00055 {
00056 
00057 // use fast inline assembly versions
00058 struct Atomic_t
00059 { 
00060    Atomic_t() : val(0) {}
00061    Atomic_t(int i) : val(i) {}
00062    volatile int val; 
00063 };
00064 inline void AtomicInc(Atomic_t &v)
00065 {
00066    __asm__ __volatile__(
00067       "lock ; " "incl %0"
00068       :"=m" (v.val)
00069       :"m" (v.val));
00070 }
00071 inline bool AtomicDecAndTest(Atomic_t &v)
00072 {
00073    unsigned char c;
00074    __asm__ __volatile__(
00075       "lock ; " "decl %0; sete %1"
00076       :"=m" (v.val), "=qm" (c)
00077       :"m" (v.val) : "memory");
00078    return c != 0;
00079 }
00080 inline int AtomicGet(Atomic_t const &v)
00081 {
00082    return v.val;
00083 }
00084 inline void AtomicDec(Atomic_t &v)
00085 {
00086    __asm__ __volatile__(
00087       "lock ; " "decl %0"
00088       :"=m" (v.val)
00089       :"m" (v.val));
00090 }
00091 
00092 } // end namespace BLOCXX_NAMESPACE
00093 
00094 #elif defined(BLOCXX_AIX)
00095 namespace BLOCXX_NAMESPACE
00096 {
00097 // This comment was stolen from the libstdc++ implementation of atomicity.h
00098 // (and modified). 
00099 // We cannot use the inline assembly for powerpc, since definitions for
00100 // these operations since they depend on operations that are not available on
00101 // the original POWER architecture.  AIX still runs on the POWER architecture,
00102 // so it would be incorrect to assume the existence of these instructions. 
00103 //
00104 // The definition of Atomic_t.val must match the type pointed to by atomic_p in
00105 // <sys/atomic_op.h>. 
00106 struct Atomic_t
00107 { 
00108    Atomic_t() : val(0) {}
00109    Atomic_t(int i) : val(i) {}
00110    volatile int val; 
00111 };
00112 
00113 inline void AtomicInc(Atomic_t &v)
00114 {
00115    ::fetch_and_add(const_cast<atomic_p>(&v.val), 1);
00116 }
00117 inline bool AtomicDecAndTest(Atomic_t &v)
00118 {
00119    // fetch_and_add returns the original value before the add operation.  Thus,
00120    // we must subtract one from the returned value before comparing.
00121    int c = ::fetch_and_add(const_cast<atomic_p>(&v.val), -1);
00122    --c;
00123    return c == 0;
00124 }
00125 inline int AtomicGet(Atomic_t const &v)
00126 {
00127    int c = ::fetch_and_add(const_cast<atomic_p>(&v.val), 0);
00128    return c;
00129 }
00130 inline void AtomicDec(Atomic_t &v)
00131 {
00132    ::fetch_and_add(const_cast<atomic_p>(&v.val), -1);
00133 }
00134 
00135 } // end namespace BLOCXX_NAMESPACE
00136 
00137 #elif (defined(BLOCXX_ARCH_PPC) || defined(__ppc__)) && defined(__GNUC__)
00138 
00139 namespace BLOCXX_NAMESPACE
00140 {
00141 
00142 // use fast inline assembly versions
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    int t;
00153    __asm__ __volatile__(
00154       "1:   lwarx   %0,0,%2\n"
00155       "  addic   %0,%0,1\n"
00156       "  stwcx.  %0,0,%2\n"
00157       "  bne-    1b"
00158       : "=&r" (t), "=m" (v.val)
00159       : "r" (&v.val), "m" (v.val)
00160       : "cc");
00161 }
00162 inline bool AtomicDecAndTest(Atomic_t &v)
00163 {
00164    int c;
00165    __asm__ __volatile__(
00166       "1:   lwarx   %0,0,%1\n"
00167       "  addic   %0,%0,-1\n"
00168       "  stwcx.  %0,0,%1\n"
00169       "  bne-    1b\n"
00170       "  isync"
00171       : "=&r" (c)
00172       : "r" (&v.val)
00173       : "cc", "memory");
00174    return c == 0;
00175 }
00176 inline int AtomicGet(Atomic_t const &v)
00177 {
00178    return v.val;
00179 }
00180 inline void AtomicDec(Atomic_t &v)
00181 {
00182    int c;
00183    __asm__ __volatile__(
00184       "1:   lwarx   %0,0,%2\n"
00185       "  addic   %0,%0,-1\n"
00186       "  stwcx.  %0,0,%2\n"
00187       "  bne-    1b"
00188       : "=&r" (c), "=m" (v.val)
00189       : "r" (&v.val), "m" (v.val)
00190       : "cc");
00191 }
00192 
00193 } // end namespace BLOCXX_NAMESPACE
00194 
00195 #elif defined(BLOCXX_WIN32)
00196 
00197 namespace BLOCXX_NAMESPACE
00198 {
00199 
00200 // use fast inline assembly versions
00201 struct BLOCXX_COMMON_API Atomic_t
00202 { 
00203    Atomic_t() : val(0) {}
00204    Atomic_t(int i) : val(i) {}
00205    volatile LONG val; 
00206 };
00207 inline void AtomicInc(Atomic_t &v)
00208 {
00209    InterlockedIncrement(&v.val); 
00210 }
00211 inline bool AtomicDecAndTest(Atomic_t &v)
00212 {
00213    return InterlockedDecrement(&v.val) == 0;
00214 }
00215 inline int AtomicGet(Atomic_t const &v)
00216 {
00217    return v.val;
00218 }
00219 inline void AtomicDec(Atomic_t &v)
00220 {
00221    InterlockedDecrement(&v.val);
00222 }
00223 
00224 } // end namespace BLOCXX_NAMESPACE
00225 
00226 #elif defined(BLOCXX_HAVE_PTHREAD_SPIN_LOCK)
00227 #include <pthread.h>
00228 
00229 #define BLOCXX_USE_PTHREAD_SPIN_LOCK_ATOMIC_OPS // used in BLOCXX_AtomicOps.cpp
00230 
00231 namespace BLOCXX_NAMESPACE
00232 {
00236 struct Atomic_t
00237 {
00242    Atomic_t();
00243 
00249    Atomic_t(int i);
00250 
00252    int val;
00253 
00254    pthread_spinlock_t spinlock;
00255 };
00256 
00261 void AtomicInc(Atomic_t &v);
00262 
00268 bool AtomicDecAndTest(Atomic_t &v);
00274 int AtomicGet(Atomic_t const &v);
00275 
00280 void AtomicDec(Atomic_t &v);
00281 
00282 } // end namespace BLOCXX_NAMESPACE
00283 
00284 #else
00285 // use slow mutex protected versions
00286 #define BLOCXX_USE_BLOCXX_DEFAULT_ATOMIC_OPS // used in BLOCXX_AtomicOps.cpp
00287 
00288 namespace BLOCXX_NAMESPACE
00289 {
00290 
00291 struct Atomic_t
00292 { 
00293    Atomic_t() : val(0) {}
00294    Atomic_t(int i) : val(i) {}
00295    volatile int val; 
00296 };
00297 void AtomicInc(Atomic_t &v);
00298 bool AtomicDecAndTest(Atomic_t &v);
00299 int AtomicGet(Atomic_t const &v);
00300 void AtomicDec(Atomic_t &v);
00301 
00302 } // end namespace BLOCXX_NAMESPACE
00303 
00304 #endif
00305 #endif

Generated on Fri Jun 16 15:39:08 2006 for blocxx by  doxygen 1.4.6