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

Go to the SVN repository for this file.

1 #ifndef NETCACHE__SRV_SYNC__HPP
2 #define NETCACHE__SRV_SYNC__HPP
3 /* $Id: srv_sync.hpp 69906 2015-11-19 19:33:55Z gouriano $
4  * ===========================================================================
5  *
6  * PUBLIC DOMAIN NOTICE
7  * National Center for Biotechnology Information
8  *
9  * This software/database is a "United States Government Work" under the
10  * terms of the United States Copyright Act. It was written as part of
11  * the author's official duties as a United States Government employee and
12  * thus cannot be copyrighted. This software/database is freely available
13  * to the public for use. The National Library of Medicine and the U.S.
14  * Government have not placed any restriction on its use or reproduction.
15  *
16  * Although all reasonable efforts have been taken to ensure the accuracy
17  * and reliability of the software and data, the NLM and the U.S.
18  * Government do not and cannot warrant the performance or results that
19  * may be obtained by using this software or data. The NLM and the U.S.
20  * Government disclaim all warranties, express or implied, including
21  * warranties of performance, merchantability or fitness for any particular
22  * purpose.
23  *
24  * Please cite the author in any work or product based on this material.
25  *
26  * ===========================================================================
27  *
28  * Authors: Pavel Ivanov
29  *
30  * File Description:
31  * Header defines several primitives to use for inter-thread synchronization.
32  */
33 
34 
35 #include <corelib/guard.hpp>
36 
37 
39 
40 
41 class CSrvTime;
42 
43 
44 #ifdef NCBI_COMPILER_GCC
45 
46 /// Purpose of this macro is to force compiler to access variable exactly at
47 /// the place it's written (no moving around and changing places with other
48 /// variables reads or writes) and to avoid optimizations when several usages
49 /// of local variable are replaced with direct access to global variable which
50 /// should be read/written only once.
51 #define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
52 
53 template <class T>
54 inline T
55 AtomicValCAS(T volatile& var, T old_value, T new_value)
56 {
57  return __sync_val_compare_and_swap(&var, old_value, new_value);
58 }
59 
60 template <class T>
61 inline bool
62 AtomicCAS(T volatile& var, T old_value, T new_value)
63 {
64  return __sync_bool_compare_and_swap(&var, old_value, new_value);
65 }
66 
67 template <class T>
68 inline T
69 AtomicAdd(T volatile& var, T add_value)
70 {
71  return __sync_add_and_fetch(&var, add_value);
72 }
73 
74 template <class T>
75 inline T
76 AtomicSub(T volatile& var, T sub_value)
77 {
78  return __sync_sub_and_fetch(&var, sub_value);
79 }
80 
81 #else
82 
83 #define ACCESS_ONCE(x) x
84 
85 template <class T>
86 inline T
87 AtomicValCAS(T volatile& var, T old_value, T new_value)
88 {
89  return old_value;
90 }
91 
92 template <class T>
93 inline bool
94 AtomicCAS(T volatile& var, T old_value, T new_value)
95 {
96  return false;
97 }
98 
99 template <class T>
100 inline T
101 AtomicAdd(T volatile& var, T add_value)
102 {
103  return var;
104 }
105 
106 template <class T>
107 inline T
108 AtomicSub(T volatile& var, T sub_value)
109 {
110  return var;
111 }
112 
113 #endif
114 
115 
116 template <class T1, class T2, class T3>
117 inline bool
118 AtomicCAS(T1 volatile& var, T2 old_value, T3 new_value)
119 {
120  return AtomicCAS(var, (T1)old_value, (T1)new_value);
121 }
122 
123 template <class T1, class T2>
124 inline T1
125 AtomicAdd(T1 volatile& var, T2 add_value)
126 {
127  return AtomicAdd(var, (T1)add_value);
128 }
129 
130 template <class T1, class T2>
131 inline T1
132 AtomicSub(T1 volatile& var, T2 sub_value)
133 {
134  return AtomicSub(var, (T1)sub_value);
135 }
136 
137 
138 
139 /// Wrapper around Linux's futex.
140 class CFutex
141 {
142 public:
143  CFutex(void);
144 
145  /// Read value of the futex.
146  int GetValue(void);
147  /// Atomically change value of the futex. If current futex value was
148  /// changed in another thread and doesn't match old_value then method
149  /// returns FALSE and value is not changed. Otherwise value is changed to
150  /// new_value and method returns TRUE.
151  bool ChangeValue(int old_value, int new_value);
152  /// Atomically add some amount to futex's value. Result of addition is
153  /// returned.
154  int AddValue(int cnt_to_add);
155 
156  /// Set futex's value non-atomically, i.e. caller should ensure that
157  /// several threads don't race with each other with setting different
158  /// values.
159  void SetValueNonAtomic(int new_value);
160 
161  /// Type of result returned from WaitValueChange()
162  enum EWaitResult {
163  /// Thread was woken up by call to WakeUpWaiters() from another thread.
165  /// Futex's value was changed in another thread before waiting was
166  /// started.
168  /// Method returned because total waiting time exceeded given timeout.
169  eTimedOut
170  };
171 
172  /// Wait for futex's value to change (with and without timeout).
173  /// Thread won't wake up automatically when value has changed -- thread
174  /// changing it should call WakeUpWaiters().
175  EWaitResult WaitValueChange(int old_value);
176  EWaitResult WaitValueChange(int old_value, const CSrvTime& timeout);
177  /// Wake up some threads waiting on this futex. cnt_to_wake is the maximum
178  /// number of threads to wake.
179  int WakeUpWaiters(int cnt_to_wake);
180 
181 private:
182  CFutex(const CFutex&);
184 
185  /// Value of the futex.
186  volatile int m_Value;
187 };
188 
189 
190 /// Mutex created to have minimum possible size (its size is 4 bytes) and
191 /// to sleep using kernel capabilities (without busy-loops).
193 {
194 public:
195  CMiniMutex(void);
196  ~CMiniMutex(void);
197 
198  /// Lock the mutex. Mutex doesn't support recursive locking. So if current
199  /// thread has already locked this mutex second call will result in
200  /// deadlock.
201  void Lock(void);
202  /// Quickly try to lock mutex (without any retries). Returns TRUE if lock
203  /// was successful and Unlock() should be called, FALSE otherwise.
204  bool TryLock(void);
205  /// Unlock the mutex. Mutex doesn't check whether this thread actually
206  /// locked it. If you call Unlock() without calling Lock() behavior is
207  /// undefined.
208  void Unlock(void);
209 
210 private:
211  /// Prohibit copying of the object
214 
215  /// Futex which is used as base for mutex implementation.
217 };
218 
220 #if NCBI_DEVELOPMENT_VER > 20141106
221 inline
222 void CGuard_Base::ReportException(std::exception&) {
223 }
224 #endif
225 
226 
227 
228 //////////////////////////////////////////////////////////////////////////
229 // Inline methods
230 //////////////////////////////////////////////////////////////////////////
231 
232 inline
234  : m_Value(0)
235 {}
236 
237 inline int
239 {
240  return m_Value;
241 }
242 
243 inline bool
244 CFutex::ChangeValue(int old_value, int new_value)
245 {
246  return AtomicCAS(m_Value, old_value, new_value);
247 }
248 
249 inline int
250 CFutex::AddValue(int cnt_to_add)
251 {
252  return AtomicAdd(m_Value, cnt_to_add);
253 }
254 
255 inline void
257 {
258  m_Value = new_value;
259 }
260 
261 
262 inline
264 {
266 }
267 
268 inline
270 {
271  _ASSERT(m_Futex.GetValue() == 0);
272 }
273 
274 inline bool
276 {
277  return m_Futex.GetValue() == 0 && m_Futex.ChangeValue(0, 1);
278 }
279 
281 
282 #endif /* NETCACHE__SRV_SYNC__HPP */
Wrapper around Linux's futex.
Definition: srv_sync.hpp:141
CFutex(const CFutex &)
CFutex & operator=(const CFutex &)
EWaitResult WaitValueChange(int old_value)
Wait for futex's value to change (with and without timeout).
Definition: srv_sync.cpp:44
volatile int m_Value
Value of the futex.
Definition: srv_sync.hpp:186
CFutex(void)
Definition: srv_sync.hpp:233
int GetValue(void)
Read value of the futex.
Definition: srv_sync.hpp:238
void SetValueNonAtomic(int new_value)
Set futex's value non-atomically, i.e.
Definition: srv_sync.hpp:256
EWaitResult
Type of result returned from WaitValueChange()
Definition: srv_sync.hpp:162
@ eWaitWokenUp
Thread was woken up by call to WakeUpWaiters() from another thread.
Definition: srv_sync.hpp:164
@ eValueChanged
Futex's value was changed in another thread before waiting was started.
Definition: srv_sync.hpp:167
@ eTimedOut
Method returned because total waiting time exceeded given timeout.
Definition: srv_sync.hpp:169
bool ChangeValue(int old_value, int new_value)
Atomically change value of the futex.
Definition: srv_sync.hpp:244
int WakeUpWaiters(int cnt_to_wake)
Wake up some threads waiting on this futex.
Definition: srv_sync.cpp:98
int AddValue(int cnt_to_add)
Atomically add some amount to futex's value.
Definition: srv_sync.hpp:250
static void ReportException(std::exception &ex)
Definition: guard.cpp:42
Mutex created to have minimum possible size (its size is 4 bytes) and to sleep using kernel capabilit...
Definition: srv_sync.hpp:193
CMiniMutex(const CMiniMutex &)
Prohibit copying of the object.
void Unlock(void)
Unlock the mutex.
Definition: srv_sync.cpp:119
void Lock(void)
Lock the mutex.
Definition: srv_sync.cpp:108
CMiniMutex & operator=(const CMiniMutex &)
CFutex m_Futex
Futex which is used as base for mutex implementation.
Definition: srv_sync.hpp:216
bool TryLock(void)
Quickly try to lock mutex (without any retries).
Definition: srv_sync.hpp:275
CMiniMutex(void)
Definition: srv_sync.hpp:263
~CMiniMutex(void)
Definition: srv_sync.hpp:269
Class incorporating convenient methods to work with struct timespec.
Definition: srv_time.hpp:61
#define T(s)
Definition: common.h:230
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
T AtomicAdd(T volatile &var, T add_value)
Definition: srv_sync.hpp:69
T AtomicSub(T volatile &var, T sub_value)
Definition: srv_sync.hpp:76
CGuard< CMiniMutex > CMiniMutexGuard
Definition: srv_sync.hpp:219
T AtomicValCAS(T volatile &var, T old_value, T new_value)
Definition: srv_sync.hpp:55
bool AtomicCAS(T volatile &var, T old_value, T new_value)
Definition: srv_sync.hpp:62
#define _ASSERT
Modified on Sat Jul 13 13:40:40 2024 by modify_doxy.py rev. 669887