00001 #ifndef NCBICNTR__HPP
00002 #define NCBICNTR__HPP
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #include <corelib/ncbistd.hpp>
00041
00042 #include <corelib/impl/ncbi_atomic_defs.h>
00043
00044
00045
00046
00047
00048
00049
00050 BEGIN_NCBI_SCOPE
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070 class CAtomicCounter
00071 {
00072 public:
00073 typedef TNCBIAtomicValue TValue;
00074
00075
00076 TValue Get(void) const THROWS_NONE;
00077
00078
00079 void Set(TValue new_value) THROWS_NONE;
00080
00081
00082 TValue Add(int delta) THROWS_NONE;
00083
00084
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;
00094
00095
00096
00097 friend class CObject;
00098 };
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
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
00124
00125
00126
00127
00128
00129
00130 class CMutableAtomicCounter
00131 {
00132 public:
00133 typedef CAtomicCounter::TValue TValue;
00134
00135
00136 TValue Get(void) const THROWS_NONE
00137 { return m_Counter.Get(); }
00138
00139
00140 void Set(TValue new_value) const THROWS_NONE
00141 { m_Counter.Set(new_value); }
00142
00143
00144 TValue Add(int delta) const THROWS_NONE
00145 { return m_Counter.Add(delta); }
00146
00147 private:
00148 mutable CAtomicCounter m_Counter;
00149 };
00150
00151
00152
00153
00154
00155
00156
00157
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
00184
00185
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
00202
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) {
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
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
00258
00259