NCBI C++ ToolKit
ncbicntr.hpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 #ifndef NCBICNTR__HPP
2 #define NCBICNTR__HPP
3 
4 /* $Id: ncbicntr.hpp 91730 2020-12-03 14:56:32Z ucko $
5 * ===========================================================================
6 *
7 * PUBLIC DOMAIN NOTICE
8 * National Center for Biotechnology Information
9 *
10 * This software/database is a "United States Government Work" under the
11 * terms of the United States Copyright Act. It was written as part of
12 * the author's official duties as a United States Government employee and
13 * thus cannot be copyrighted. This software/database is freely available
14 * to the public for use. The National Library of Medicine and the U.S.
15 * Government have not placed any restriction on its use or reproduction.
16 *
17 * Although all reasonable efforts have been taken to ensure the accuracy
18 * and reliability of the software and data, the NLM and the U.S.
19 * Government do not and cannot warrant the performance or results that
20 * may be obtained by using this software or data. The NLM and the U.S.
21 * Government disclaim all warranties, express or implied, including
22 * warranties of performance, merchantability or fitness for any particular
23 * purpose.
24 *
25 * Please cite the author in any work or product based on this material.
26 *
27 * ===========================================================================
28 *
29 * Author: Aaron Ucko
30 *
31 *
32 */
33 
34 /// @file ncbictr.hpp
35 /// Efficient atomic counters (for CObject reference counts)
36 /// Note that the special value 0x3FFFFFFF is used to indicate
37 /// locked counters on some platforms.
38 
39 
40 #include <corelib/ncbistd.hpp>
41 
43 
44 /** @addtogroup Counters
45  *
46  * @{
47  */
48 
49 
51 
52 /////////////////////////////////////////////////////////////////////////////
53 ///
54 /// CAtomicCounter --
55 ///
56 /// Define a basic atomic counter.
57 ///
58 /// Provide basic counter operations for an atomic counter represented
59 /// internally by TNCBIAtomicValue.
60 /// @note
61 /// CAtomicCounter has no constructor and is initialized only when
62 /// created as static object. In all other cases Set(0) must be called
63 /// to initialize the counter. CAtomicCounter_WithAutoInit can be used
64 /// instead of CAtomicCounter if the initialization is required.
65 /// @note
66 /// TNCBIAtomicValue does not imply any assumptions about the size and
67 /// the signedness of the value. It is at least as big as int datatype
68 /// and can be signed on some platforms and unsigned on others.
69 
71 {
72 public:
73  typedef TNCBIAtomicValue TValue; ///< Alias TValue for TNCBIAtomicValue
74 
75 #ifdef NCBI_COUNTER_USE_STD_ATOMIC
76  CAtomicCounter() = default;
78  : m_Value(other.Get())
79  { }
80 #endif
81 
82  /// Get atomic counter value.
83  TValue Get(void) const THROWS_NONE;
84 
85  /// Set atomic counter value.
86  void Set(TValue new_value) THROWS_NONE;
87 
88  /// Atomically add value (=delta), and return new counter value.
90 
91  /// Define NCBI_COUNTER_ADD if one has not been defined.
92 #if defined(NCBI_COUNTER_USE_ASM)
93  static TValue x_Add(volatile TValue* value, int delta) THROWS_NONE;
94 # if !defined(NCBI_COUNTER_ADD)
95 # define NCBI_COUNTER_ADD(value, delta) NCBI_NS_NCBI::CAtomicCounter::x_Add((value), (delta))
96 # endif
97 #endif
98 
99 private:
100  typedef NCBI_ATOMIC_TYPE(TValue) TData;
101  volatile TData m_Value; ///< Internal counter value
102 
103  // CObject's constructor needs to read m_Value directly when checking
104  // for the magic number left by operator new.
105  friend class CObject;
106 };
107 
108 
109 /////////////////////////////////////////////////////////////////////////////
110 ///
111 /// CAtomicCounter_WithAutoInit --
112 ///
113 /// Define an atomic counter with guaranteed initialization.
114 ///
115 /// CAtomicCounter does not initialize its value if it's not
116 /// a static object. CAtomicCounter_WithAutoInit automatically
117 /// calls Set() in its constructor to set the initial value.
118 
120 {
121 public:
123  {
124  Set(initial_value);
125  }
126 };
127 
128 
129 /////////////////////////////////////////////////////////////////////////////
130 ///
131 /// CMutableAtomicCounter --
132 ///
133 /// Define a mutable atomic counter.
134 ///
135 /// Provide mutable counter operations for an atomic counter represented
136 /// internally by CAtomicCounter.
137 
139 {
140 public:
141  typedef CAtomicCounter::TValue TValue; ///< Alias TValue simplifies syntax
142 
143  /// Get atomic counter value.
144  TValue Get(void) const THROWS_NONE
145  { return m_Counter.Get(); }
146 
147  /// Set atomic counter value.
148  void Set(TValue new_value) const THROWS_NONE
149  { m_Counter.Set(new_value); }
150 
151  /// Atomically add value (=delta), and return new counter value.
153  { return m_Counter.Add(delta); }
154 
155 private:
156  mutable CAtomicCounter m_Counter; ///< Mutable atomic counter value
157 };
158 
159 
160 /* @} */
161 
162 
163 //////////////////////////////////////////////////////////////////////
164 //
165 // Inline methods
166 
167 inline
169 {
170 #ifdef NCBI_COUNTER_RESERVED_VALUE
171  TValue value = m_Value;
173  while (value == NCBI_COUNTER_RESERVED_VALUE) {
175  value = m_Value;
176  }
177  return value;
178 #else
179  return m_Value;
180 #endif
181 }
182 
183 
184 inline
186 {
187  m_Value = new_value;
188 }
189 
190 
191 // With WorkShop, sanely inlining assembly requires the use of ".il" files.
192 // In order to keep the toolkit's external interface sane, we therefore
193 // force this method out-of-line and into ncbicntr_workshop.o.
194 #if defined(NCBI_COUNTER_USE_ASM) && (!defined(NCBI_COMPILER_WORKSHOP) || defined(NCBI_COUNTER_IMPLEMENTATION))
195 # ifndef NCBI_COMPILER_WORKSHOP
196 inline
197 # endif
199 CAtomicCounter::x_Add(volatile CAtomicCounter::TValue* value_p, int delta)
201 {
202  TValue result;
203  TValue* nv_value_p = const_cast<TValue*>(value_p);
204 # ifdef __sparcv9
206  for (;;) {
207  TValue old_value = *value_p;
208  result = old_value + delta;
209  // Atomic compare-and-swap: if *value_p == old_value, swap it
210  // with result; otherwise, just put the current value in result.
211 # ifdef NCBI_COMPILER_WORKSHOP
212  result = NCBICORE_asm_cas(result, nv_value_p, old_value);
213 # else
214  asm volatile("cas [%3], %2, %1" : "=m" (*nv_value_p), "+r" (result)
215  : "r" (old_value), "r" (nv_value_p), "m" (*nv_value_p));
216 # endif
217  if (result == old_value) { // We win
218  break;
219  }
221  }
222  result += delta;
223 # elif defined(__sparc)
224  result = NCBI_COUNTER_RESERVED_VALUE;
226  for (;;) {
227 # ifdef NCBI_COMPILER_WORKSHOP
228  result = NCBICORE_asm_swap(result, nv_value_p);
229 # else
230  asm volatile("swap [%2], %1" : "=m" (*nv_value_p), "+r" (result)
231  : "r" (nv_value_p), "m" (*nv_value_p));
232 # endif
233  if (result != NCBI_COUNTER_RESERVED_VALUE) {
234  break;
235  }
237  }
238  result += delta;
239  *value_p = result;
240 # elif defined(__i386) || defined(__x86_64)
241  // Yay CISC. ;-) (WorkShop already handled.)
242 # ifdef NCBI_COUNTER_64_BIT
243  asm volatile("lock; xaddq %1, %0" : "=m" (*nv_value_p), "=r" (result)
244  : "1" (Int8(delta)), "m" (*nv_value_p));
245 # else
246  asm volatile("lock; xaddl %1, %0" : "=m" (*nv_value_p), "=r" (result)
247  : "1" (delta), "m" (*nv_value_p));
248 # endif
249  result += delta;
250 # elif defined(__aarch64__)
251 # ifdef __ARM_FEATURE_ATOMICS
252  asm volatile("ldaddal %2, %0, %1" : "=&r" (result), "+Q" (*nv_value_p)
253  : "r" (Int8(delta)));
254  result += delta;
255 # else
257  register int undone asm("w9") = 1;
258  while (undone) {
259  asm volatile("ldxr %1, %2\n\tadd %1, %1, %3\n\tstlxr w9, %1, %2"
260  : "=&r" (undone), "=&r" (result), "+Q" (*nv_value_p)
261  : "r" (Int8(delta)));
262  if (undone) {
264  }
265  }
266 # endif
267 # else
268 # error "Unsupported processor type for assembly implementation!"
269 # endif
270  return result;
271 }
272 #endif
273 
274 #if !defined(NCBI_COUNTER_NEED_MUTEX) && (!defined(NCBI_COUNTER_USE_EXTERN_ASM) || defined(NCBI_COUNTER_IMPLEMENTATION))
275 # ifndef NCBI_COUNTER_USE_EXTERN_ASM
276 inline
277 # endif
279 {
280  TData* nv_value_p = const_cast<TData*>(&m_Value);
281  return NCBI_COUNTER_ADD(nv_value_p, delta);
282 }
283 #endif
284 
286 
287 #endif /* NCBICNTR__HPP */
CAtomicCounter_WithAutoInit –.
Definition: ncbicntr.hpp:120
CAtomicCounter –.
Definition: ncbicntr.hpp:71
CMutableAtomicCounter –.
Definition: ncbicntr.hpp:139
CObject –.
Definition: ncbiobj.hpp:180
Include a standard set of the NCBI C++ Toolkit most basic headers.
TValue Add(int delta) const THROWS_NONE
Atomically add value (=delta), and return new counter value.
Definition: ncbicntr.hpp:152
void Set(TValue new_value) const THROWS_NONE
Set atomic counter value.
Definition: ncbicntr.hpp:148
CAtomicCounter_WithAutoInit(TValue initial_value=0)
Definition: ncbicntr.hpp:122
TNCBIAtomicValue TValue
Alias TValue for TNCBIAtomicValue.
Definition: ncbicntr.hpp:73
typedef NCBI_ATOMIC_TYPE(TValue) TData
Define NCBI_COUNTER_ADD if one has not been defined.
TValue Get(void) const THROWS_NONE
Get atomic counter value.
Definition: ncbicntr.hpp:144
void Set(TValue new_value) THROWS_NONE
Set atomic counter value.
Definition: ncbicntr.hpp:185
TValue Add(int delta) THROWS_NONE
Atomically add value (=delta), and return new counter value.
Definition: ncbicntr.hpp:278
CAtomicCounter m_Counter
Mutable atomic counter value.
Definition: ncbicntr.hpp:156
volatile TData m_Value
Internal counter value.
Definition: ncbicntr.hpp:101
CAtomicCounter::TValue TValue
Alias TValue simplifies syntax.
Definition: ncbicntr.hpp:141
TValue Get(void) const THROWS_NONE
Get atomic counter value.
Definition: ncbicntr.hpp:168
#define THROWS_NONE
Do not use 'throw' dynamic exception specification for C++11 compilers.
Definition: ncbiexpt.hpp:74
int64_t Int8
8-byte (64-bit) signed integer
Definition: ncbitype.h:104
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
#define NCBI_SCHED_SPIN_INIT()
#define NCBI_SCHED_SPIN_YIELD()
size_t TNCBIAtomicValue
Define platform specific atomic-operations macros/values.
#define NCBI_COUNTER_ADD(p, d)
#define NCBI_XNCBI_EXPORT
Definition: ncbi_export.h:1283
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1227
(Highly!) platform-specific configuration for low-level atomic operations (reference-count manipulati...
Int4 delta(size_t dimension_, const Int4 *score_)
else result
Definition: token2.c:20
Modified on Sat Apr 27 11:17:05 2024 by modify_doxy.py rev. 669887