include/corelib/ncbicntr.hpp

Go to the documentation of this file.
00001 #ifndef NCBICNTR__HPP
00002 #define NCBICNTR__HPP
00003 
00004 /*  $Id: ncbicntr.hpp 152540 2009-02-17 20:37:42Z grichenk $
00005 * ===========================================================================
00006 *
00007 *                            PUBLIC DOMAIN NOTICE
00008 *               National Center for Biotechnology Information
00009 *
00010 *  This software/database is a "United States Government Work" under the
00011 *  terms of the United States Copyright Act.  It was written as part of
00012 *  the author's official duties as a United States Government employee and
00013 *  thus cannot be copyrighted.  This software/database is freely available
00014 *  to the public for use. The National Library of Medicine and the U.S.
00015 *  Government have not placed any restriction on its use or reproduction.
00016 *
00017 *  Although all reasonable efforts have been taken to ensure the accuracy
00018 *  and reliability of the software and data, the NLM and the U.S.
00019 *  Government do not and cannot warrant the performance or results that
00020 *  may be obtained by using this software or data. The NLM and the U.S.
00021 *  Government disclaim all warranties, express or implied, including
00022 *  warranties of performance, merchantability or fitness for any particular
00023 *  purpose.
00024 *
00025 *  Please cite the author in any work or product based on this material.
00026 *
00027 * ===========================================================================
00028 *
00029 * Author:  Aaron Ucko
00030 *
00031 *
00032 */
00033 
00034 /// @file ncbictr.hpp
00035 /// Efficient atomic counters (for CObject reference counts)
00036 /// Note that the special value 0x3FFFFFFF is used to indicate
00037 /// locked counters on some platforms.
00038 
00039 
00040 #include <corelib/ncbistd.hpp>
00041 
00042 #include <corelib/impl/ncbi_atomic_defs.h>
00043 
00044 /** @addtogroup Counters
00045  *
00046  * @{
00047  */
00048 
00049 
00050 BEGIN_NCBI_SCOPE
00051 
00052 /////////////////////////////////////////////////////////////////////////////
00053 ///
00054 /// CAtomicCounter --
00055 ///
00056 /// Define a basic atomic counter.
00057 ///
00058 /// Provide basic counter operations for an atomic counter represented
00059 /// internally by TNCBIAtomicValue.
00060 /// @note
00061 ///   CAtomicCounter has no constructor and is initialized only when
00062 ///   created as static object. In all other cases Set(0) must be called
00063 ///   to initialize the counter. CAtomicCounter_WithAutoInit can be used
00064 ///   instead of CAtomicCounter if the initialization is required.
00065 /// @note
00066 ///   TNCBIAtomicValue does not imply any assumptions about the size and
00067 ///   the signedness of the value. It is at least as big as int datatype
00068 ///   and can be signed on some platforms and unsigned on others.
00069 
00070 class CAtomicCounter
00071 {
00072 public:
00073     typedef TNCBIAtomicValue TValue;  ///< Alias TValue for TNCBIAtomicValue
00074 
00075     /// Get atomic counter value.
00076     TValue Get(void) const THROWS_NONE;
00077 
00078     /// Set atomic counter value.
00079     void   Set(TValue new_value) THROWS_NONE;
00080 
00081     /// Atomically add value (=delta), and return new counter value.
00082     TValue Add(int delta) THROWS_NONE;
00083     
00084     /// Define NCBI_COUNTER_ADD if one has not been defined.
00085 #if defined(NCBI_COUNTER_USE_ASM)
00086     static TValue x_Add(volatile TValue* value, int delta) THROWS_NONE;
00087 #  if !defined(NCBI_COUNTER_ADD)
00088 #     define NCBI_COUNTER_ADD(value, delta) NCBI_NS_NCBI::CAtomicCounter::x_Add((value), (delta))
00089 #  endif
00090 #endif
00091 
00092 private:
00093     volatile TValue m_Value;  ///< Internal counter value
00094 
00095     // CObject's constructor needs to read m_Value directly when checking
00096     // for the magic number left by operator new.
00097     friend class CObject;
00098 };
00099 
00100 
00101 /////////////////////////////////////////////////////////////////////////////
00102 ///
00103 /// CAtomicCounter_WithAutoInit --
00104 ///
00105 /// Define an atomic counter with guaranteed initialization.
00106 ///
00107 /// CAtomicCounter does not initialize its value if it's not
00108 /// a static object. CAtomicCounter_WithAutoInit automatically
00109 /// calls Set() in its constructor to set the initial value.
00110 
00111 class CAtomicCounter_WithAutoInit : public CAtomicCounter
00112 {
00113 public:
00114     CAtomicCounter_WithAutoInit(TValue initial_value = 0)
00115     {
00116         Set(initial_value);
00117     }
00118 };
00119 
00120 
00121 /////////////////////////////////////////////////////////////////////////////
00122 ///
00123 /// CMutableAtomicCounter --
00124 ///
00125 /// Define a mutable atomic counter.
00126 ///
00127 /// Provide mutable counter operations for an atomic counter represented
00128 /// internally by CAtomicCounter. 
00129 
00130 class  CMutableAtomicCounter
00131 {
00132 public:
00133     typedef CAtomicCounter::TValue TValue; ///< Alias TValue simplifies syntax
00134 
00135     /// Get atomic counter value.
00136     TValue Get(void) const THROWS_NONE
00137         { return m_Counter.Get(); }
00138 
00139     /// Set atomic counter value.
00140     void   Set(TValue new_value) const THROWS_NONE
00141         { m_Counter.Set(new_value); }
00142 
00143     /// Atomically add value (=delta), and return new counter value.
00144     TValue Add(int delta) const THROWS_NONE
00145         { return m_Counter.Add(delta); }
00146 
00147 private:
00148     mutable CAtomicCounter m_Counter;      ///< Mutable atomic counter value
00149 };
00150 
00151 
00152 /* @} */
00153 
00154 
00155 //////////////////////////////////////////////////////////////////////
00156 // 
00157 // Inline methods
00158 
00159 inline
00160 CAtomicCounter::TValue CAtomicCounter::Get(void) const THROWS_NONE
00161 {
00162 #ifdef NCBI_COUNTER_RESERVED_VALUE
00163     TValue value = m_Value;
00164     NCBI_SCHED_SPIN_INIT();
00165     while (value == NCBI_COUNTER_RESERVED_VALUE) {
00166         NCBI_SCHED_SPIN_YIELD();
00167         value = m_Value;
00168     }
00169     return value;
00170 #else
00171     return m_Value;
00172 #endif
00173 }
00174 
00175 
00176 inline
00177 void CAtomicCounter::Set(CAtomicCounter::TValue new_value) THROWS_NONE
00178 {
00179     m_Value = new_value;
00180 }
00181 
00182 
00183 // With WorkShop, sanely inlining assembly requires the use of ".il" files.
00184 // In order to keep the toolkit's external interface sane, we therefore
00185 // force this method out-of-line and into ncbicntr_workshop.o.
00186 #if defined(NCBI_COUNTER_USE_ASM) && (!defined(NCBI_COMPILER_WORKSHOP) || defined(NCBI_COUNTER_IMPLEMENTATION))
00187 #  ifndef NCBI_COMPILER_WORKSHOP
00188 inline
00189 #  endif
00190 CAtomicCounter::TValue
00191 CAtomicCounter::x_Add(volatile CAtomicCounter::TValue* value_p, int delta)
00192 THROWS_NONE
00193 {
00194     TValue result;
00195     TValue* nv_value_p = const_cast<TValue*>(value_p);
00196 #  ifdef __sparcv9
00197     NCBI_SCHED_SPIN_INIT();
00198     for (;;) {
00199         TValue old_value = *value_p;
00200         result = old_value + delta;
00201         // Atomic compare-and-swap: if *value_p == old_value, swap it
00202         // with result; otherwise, just put the current value in result.
00203 #    ifdef NCBI_COMPILER_WORKSHOP
00204         result = NCBICORE_asm_cas(result, nv_value_p, old_value);
00205 #    else
00206         asm volatile("cas [%3], %2, %1" : "=m" (*nv_value_p), "+r" (result)
00207                      : "r" (old_value), "r" (nv_value_p), "m" (*nv_value_p));
00208 #    endif
00209         if (result == old_value) { // We win
00210             break;
00211         }
00212         NCBI_SCHED_SPIN_YIELD();
00213     }
00214     result += delta;
00215 #  elif defined(__sparc)
00216     result = NCBI_COUNTER_RESERVED_VALUE;
00217     NCBI_SCHED_SPIN_INIT();
00218     for (;;) {
00219 #    ifdef NCBI_COMPILER_WORKSHOP
00220         result = NCBICORE_asm_swap(result, nv_value_p);
00221 #    else
00222         asm volatile("swap [%2], %1" : "=m" (*nv_value_p), "+r" (result)
00223                      : "r" (nv_value_p), "m" (*nv_value_p));
00224 #    endif
00225         if (result != NCBI_COUNTER_RESERVED_VALUE) {
00226             break;
00227         }
00228         NCBI_SCHED_SPIN_YIELD();
00229     }
00230     result += delta;
00231     *value_p = result;
00232 #  elif defined(__i386) || defined(__x86_64)
00233     // Yay CISC. ;-)  (WorkShop already handled.)
00234     asm volatile("lock; xaddl %1, %0" : "=m" (*nv_value_p), "=r" (result)
00235                  : "1" (delta), "m" (*nv_value_p));
00236     result += delta;
00237 #  else
00238 #    error "Unsupported processor type for assembly implementation!"
00239 #  endif
00240     return result;
00241 }
00242 #endif
00243 
00244 #if !defined(NCBI_COUNTER_NEED_MUTEX)  &&  (!defined(NCBI_COUNTER_USE_EXTERN_ASM)  ||  defined(NCBI_COUNTER_IMPLEMENTATION))
00245 #  ifndef NCBI_COUNTER_USE_EXTERN_ASM
00246 inline
00247 #  endif
00248 CAtomicCounter::TValue CAtomicCounter::Add(int delta) THROWS_NONE
00249 {
00250     TValue* nv_value_p = const_cast<TValue*>(&m_Value);
00251     return NCBI_COUNTER_ADD(nv_value_p, delta);
00252 }
00253 #endif
00254 
00255 END_NCBI_SCOPE
00256 
00257 #endif  /* NCBICNTR__HPP */
00258 
00259 

Generated on Wed Dec 9 03:01:53 2009 for NCBI C++ ToolKit by  doxygen 1.4.6
Modified on Wed Dec 09 08:17:29 2009 by modify_doxy.py rev. 173732