PTLib  Version 2.18.8
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
atomic.h
Go to the documentation of this file.
1 /*
2  * critsec.h
3  *
4  * Critical section mutex class.
5  *
6  * Portable Windows Library
7  *
8  * Copyright (C) 2004 Post Increment
9  *
10  * The contents of this file are subject to the Mozilla Public License
11  * Version 1.0 (the "License"); you may not use this file except in
12  * compliance with the License. You may obtain a copy of the License at
13  * http://www.mozilla.org/MPL/
14  *
15  * Software distributed under the License is distributed on an "AS IS"
16  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17  * the License for the specific language governing rights and limitations
18  * under the License.
19  *
20  * The Original Code is Portable Windows Library.
21  *
22  * The Initial Developer of the Original Code is Post Increment
23  *
24  * Contributor(s): ______________________________________.
25  */
26 
27 #ifndef PTLIB_CRITICALSECTION_H
28 #define PTLIB_CRITICALSECTION_H
29 
30 #if P_STD_ATOMIC
31 
32 #include <atomic>
33 
34 using std::atomic;
35 #define PAtomicEnum std::atomic
36 
37 #else
38 
39 #ifdef P_ATOMICITY_HEADER
40  #include P_ATOMICITY_HEADER
41 #endif
42 
43 template <typename Type> struct atomic
44 {
45  __inline atomic() { this->ConstructMutex(); }
46  __inline atomic(Type value) : m_storage(value) { this->ConstructMutex(); }
47  __inline atomic(const atomic & other) : m_storage(other.m_storage) { this->ConstructMutex(); }
48  __inline ~atomic() { this->DestroyMutex(); }
49  __inline atomic & operator=(const atomic & other) { this->Lock(); other.Lock(); this->m_storage = other.m_storage; other.Unlock(); this->Unlock(); return *this; }
50  __inline operator Type() const { this->Lock(); Type value = this->m_storage; this->Unlock(); return value; }
51  __inline Type load() const { this->Lock(); Type value = this->m_storage; this->Unlock(); return value; } \
52  __inline void store(Type value) { this->Lock(); this->m_storage = value; this->Unlock(); } \
53  __inline Type exchange(Type value) { this->Lock(); Type previous = this->m_storage; this->m_storage = value; this->Unlock(); return previous; }
54  bool compare_exchange_strong(Type & comp, Type value)
55  {
56  this->Lock();
57  if (this->m_storage == comp) {
58  this->m_storage = value;
59  this->Unlock();
60  return true;
61  }
62  else {
63  comp = this->m_storage;
64  this->Unlock();
65  return false;
66  }
67  }
68 
69 private:
70  volatile Type m_storage;
71 
72  // This is declared before any PMutex classes, have to do it manually.
73 #if _WIN32
74  mutable CRITICAL_SECTION m_mutex;
75  __inline void ConstructMutex() { InitializeCriticalSection(&this->m_mutex); }
76  __inline void DestroyMutex() { DeleteCriticalSection(&this->m_mutex); }
77  __inline void Lock() const { EnterCriticalSection(&this->m_mutex); }
78  __inline void Unlock() const { LeaveCriticalSection(&this->m_mutex); }
79 #else
80  mutable pthread_mutex_t m_mutex;
81  __inline void ConstructMutex() { pthread_mutex_init(&this->m_mutex, NULL); }
82  __inline void DestroyMutex() { pthread_mutex_destroy(&this->m_mutex); }
83  __inline void Lock() const { pthread_mutex_lock(&this->m_mutex); }
84  __inline void Unlock() const { pthread_mutex_unlock(&this->m_mutex); }
85 #endif
86 };
87 
88 #define P_DEFINE_ATOMIC_FUNCTIONS(Type,Exch,FetchAdd,AddFetch,CompExch) \
89  __inline atomic() : m_storage() { } \
90  __inline atomic(Type value) : m_storage(value) { } \
91  __inline atomic(const atomic & other) : m_storage((Type)AddFetch(const_cast<Type *>(&other.m_storage), 0)) { } \
92  __inline atomic & operator=(const atomic & other) { store(other.load()); return *this; } \
93  __inline atomic & operator=(Type other) { store(other); return *this; } \
94  __inline operator Type() const { return (Type)AddFetch(const_cast<Type *>(&m_storage), 0); } \
95  __inline bool compare_exchange_strong(Type & comp, Type value) { return CompExch(&m_storage, comp, value); } \
96  __inline void store(Type value) { exchange(value); } \
97  __inline Type load() const { return (Type)AddFetch(const_cast<Type *>(&m_storage), 0); } \
98  __inline Type exchange(Type value) { return (Type)Exch(&m_storage, value); } \
99  __inline Type operator++() { return (Type)AddFetch(&m_storage, 1); } \
100  __inline Type operator++(int) { return (Type)FetchAdd(&m_storage, 1); } \
101  __inline Type operator+=(Type i) { return (Type)AddFetch(&m_storage, i); } \
102  __inline Type operator--() { return (Type)AddFetch(&m_storage, -1); } \
103  __inline Type operator--(int) { return (Type)FetchAdd(&m_storage, -1); } \
104  __inline Type operator-=(Type i) { return (Type)AddFetch(&m_storage, -i); } \
105 
106 #define P_DEFINE_ATOMIC_INT_CLASS(Type,Exch,FetchAdd,AddFetch,CompExch) \
107  template <> struct atomic<Type> { \
108  P_DEFINE_ATOMIC_FUNCTIONS(Type,Exch,FetchAdd,AddFetch,CompExch) \
109  private: volatile Type m_storage; \
110  }
111 
112 #define P_DEFINE_ATOMIC_PTR_CLASS(Exch,FetchAdd,AddFetch,CompExch) \
113  template <typename Type> struct atomic<Type *> { \
114  P_DEFINE_ATOMIC_FUNCTIONS(Type*,Exch,FetchAdd,AddFetch,CompExch) \
115  private: volatile Type * m_storage; \
116  }
117 
118 #if defined(_WIN32)
119 
120  #define P_Exchange8(storage, value) _InterlockedExchange8 ((CHAR *)(storage), value)
121  #define P_CompExch8(storage,comp,value) (_InterlockedCompareExchange8 ((CHAR *)(storage), value, comp) == (CHAR)comp)
122  #define P_FetchAdd8(storage, value) _InterlockedExchangeAdd8 ((char *)(storage), value)
123  #define P_AddFetch8(storage, value) (_InterlockedExchangeAdd8 ((char *)(storage), value)+value)
124  #define P_Exchange16(storage, value) _InterlockedExchange16 ((SHORT *)(storage), value)
125  #define P_CompExch16(storage,comp,value) (_InterlockedCompareExchange16 ((SHORT *)(storage), value, comp) == (SHORT)comp)
126  #define P_FetchAdd16(storage, value) _InterlockedExchangeAdd16 ((SHORT *)(storage), value)
127  #define P_AddFetch16(storage, value) (_InterlockedExchangeAdd16 ((SHORT *)(storage), value)+value)
128  #define P_Exchange32(storage, value) _InterlockedExchange ((LONG *)(storage), value)
129  #define P_CompExch32(storage,comp,value) (_InterlockedCompareExchange ((LONG *)(storage), value, comp) == (LONG)comp)
130  #define P_FetchAdd32(storage, value) _InterlockedExchangeAdd ((LONG *)(storage), value)
131  #define P_AddFetch32(storage, value) _InterlockedAdd ((LONG *)(storage), value)
132  #define P_Exchange64(storage, value) _InterlockedExchange64 ((LONG64*)(storage), value)
133  #define P_CompExch64(storage,comp,value) (_InterlockedCompareExchange64 ((LONG64*)(storage), value, comp) == (LONG64)comp)
134  #define P_FetchAdd64(storage, value) _InterlockedExchangeAdd64 ((LONG64*)(storage), value)
135  #define P_AddFetch64(storage, value) _InterlockedAdd64 ((LONG64*)(storage), value)
136  #define P_ExchangePtr(storage, value) _InterlockedExchangePointer ((PVOID *)(storage), value)
137  #ifdef _WIN64
138  #define P_CompExchPtr(storage,comp,value) (_InterlockedCompareExchange64((LONG *)(storage), value, comp) == comp)
139  #define P_FetchAddPtr(storage, value) _InterlockedExchangeAdd64 ((LONG64*)(storage), value)
140  #define P_AddFetchPtr(storage, value) _InterlockedAdd64 ((LONG64*)(storage), value)
141  #else
142  #define P_CompExchPtr(storage,comp,value) (_InterlockedCompareExchange ((LONG *)(storage), value, comp) == comp)
143  #define P_FetchAddPtr(storage, value) _InterlockedExchangeAdd ((LONG *)(storage), value)
144  #define P_AddFetchPtr(storage, value) _InterlockedAdd ((LONG *)(storage), value)
145  #endif
146 
147  #define P_DEFINE_ATOMIC_INT_CLASS_WIN32(Type, Size) \
148  P_DEFINE_ATOMIC_INT_CLASS(Type, P_Exchange##Size, P_FetchAdd##Size, P_AddFetch##Size, P_CompExch##Size)
149 
150  P_DEFINE_ATOMIC_INT_CLASS_WIN32( bool, 8 );
151  P_DEFINE_ATOMIC_INT_CLASS_WIN32( signed char, 8 );
152  P_DEFINE_ATOMIC_INT_CLASS_WIN32(unsigned char, 8 );
153  P_DEFINE_ATOMIC_INT_CLASS_WIN32( signed short, 16);
154  P_DEFINE_ATOMIC_INT_CLASS_WIN32(unsigned short, 16);
155  P_DEFINE_ATOMIC_INT_CLASS_WIN32( signed int, 32);
156  P_DEFINE_ATOMIC_INT_CLASS_WIN32(unsigned int, 32);
157  P_DEFINE_ATOMIC_INT_CLASS_WIN32( signed long, 32);
158  P_DEFINE_ATOMIC_INT_CLASS_WIN32(unsigned long, 32);
159  P_DEFINE_ATOMIC_INT_CLASS_WIN32( signed long long, 64);
160  P_DEFINE_ATOMIC_INT_CLASS_WIN32(unsigned long long, 64);
161 
162  P_DEFINE_ATOMIC_PTR_CLASS(P_ExchangePtr, P_FetchAddPtr, P_AddFetchPtr, P_CompExchPtr);
163 
164 #elif defined(P_ATOMICITY_BUILTIN)
165 
166  template <typename Type> static __inline bool p_compare_exchange_strong(volatile Type *ptr, Type & comp, Type newval)
167  {
168  Type oldval = __sync_val_compare_and_swap(ptr, comp, newval);
169  if (oldval == comp)
170  return true;
171  comp = oldval;
172  return false;
173  }
174 
175  #define P_DEFINE_ATOMIC_INT_CLASS_BUILTIN(Type) \
176  P_DEFINE_ATOMIC_INT_CLASS(Type, __sync_lock_test_and_set, __sync_fetch_and_add, __sync_add_and_fetch, p_compare_exchange_strong)
177 
178  template <> struct atomic<bool>
179  {
180  __inline atomic() : m_storage() { }
181  __inline atomic(bool value) : m_storage(value) { }
182  __inline atomic(const atomic & other) : m_storage(__sync_add_and_fetch(reinterpret_cast<char *>(const_cast<bool *>(&other.m_storage)), 0)) { }
183  __inline atomic & operator=(const atomic & other) { store(other.load()); return *this; }
184  __inline atomic & operator=(bool other) { store(other); return *this; }
185  __inline operator bool() const { return __sync_add_and_fetch(reinterpret_cast<char *>(const_cast<bool *>(&m_storage)), 0) != 0; }
186  __inline bool compare_exchange_strong(bool & comp, bool value) { return p_compare_exchange_strong(&m_storage, comp, value); }
187  __inline void store(bool value) { exchange(value); }
188  __inline bool load() const { return __sync_add_and_fetch(reinterpret_cast<char *>(const_cast<bool *>(&m_storage)), 0) != 0; }
189  __inline bool exchange(bool value) { return __sync_lock_test_and_set(&m_storage, value) != 0; }
190  private: volatile bool m_storage;
191  };
192 
193  P_DEFINE_ATOMIC_INT_CLASS_BUILTIN( signed char);
194  P_DEFINE_ATOMIC_INT_CLASS_BUILTIN(unsigned char);
195  P_DEFINE_ATOMIC_INT_CLASS_BUILTIN( signed short);
196  P_DEFINE_ATOMIC_INT_CLASS_BUILTIN(unsigned short);
197  P_DEFINE_ATOMIC_INT_CLASS_BUILTIN( signed int);
198  P_DEFINE_ATOMIC_INT_CLASS_BUILTIN(unsigned int);
199  P_DEFINE_ATOMIC_INT_CLASS_BUILTIN( signed long);
200  P_DEFINE_ATOMIC_INT_CLASS_BUILTIN(unsigned long);
201  #if HAVE_LONG_LONG_INT
202  P_DEFINE_ATOMIC_INT_CLASS_BUILTIN(signed long long);
203  #endif
204  #if HAVE_UNSIGNED_LONG_LONG_INT
205  P_DEFINE_ATOMIC_INT_CLASS_BUILTIN(unsigned long long);
206  #endif
207  P_DEFINE_ATOMIC_PTR_CLASS(__sync_lock_test_and_set, __sync_fetch_and_add, __sync_add_and_fetch, __sync_bool_compare_and_swap);
208 
209 #elif defined(SOLARIS) && !defined(__GNUC__)
210 
211  P_DEFINE_ATOMIC_INT_CLASS( bool, atomic_swap_8, atomic_add_8, atomic_add_8_nv);
212  P_DEFINE_ATOMIC_INT_CLASS( signed char, atomic_swap_8, atomic_add_8, atomic_add_8_nv);
213  P_DEFINE_ATOMIC_INT_CLASS(unsigned char, atomic_swap_8, atomic_add_8, atomic_add_8_nv);
214  P_DEFINE_ATOMIC_INT_CLASS( signed short, atomic_swap_16, atomic_add_16, atomic_add_16_nv);
215  P_DEFINE_ATOMIC_INT_CLASS(unsigned short, atomic_swap_16, atomic_add_16, atomic_add_16_nv);
216  P_DEFINE_ATOMIC_INT_CLASS( signed int, atomic_swap_32, atomic_add_32, atomic_add_32_nv);
217  P_DEFINE_ATOMIC_INT_CLASS(unsigned int, atomic_swap_32, atomic_add_32, atomic_add_32_nv);
218  P_DEFINE_ATOMIC_INT_CLASS( signed long, atomic_swap_32, atomic_add_32, atomic_add_32_nv);
219  P_DEFINE_ATOMIC_INT_CLASS(unsigned long, atomic_swap_32, atomic_add_32, atomic_add_32_nv);
220  #if HAVE_LONG_LONG_INT
221  P_DEFINE_ATOMIC_INT_CLASS(signed long long, atomic_swap_64, atomic_add_64, atomic_add_64_nv);
222  #endif
223  #if HAVE_UNSIGNED_LONG_LONG_INT
224  P_DEFINE_ATOMIC_INT_CLASS(unsigned long long, atomic_swap_64, atomic_add_64, atomic_add_64_nv);
225  #endif
226  #if defined(P_64BIT)
227  P_DEFINE_ATOMIC_PTR_CLASS(atomic_swap_64, atomic_add_64, atomic_add_64_nv);
228  #else
229  P_DEFINE_ATOMIC_PTR_CLASS(atomic_swap_32, atomic_add_32, atomic_add_32_nv);
230  #endif
231 
232 #elif defined(P_ATOMICITY_HEADER)
233 
234  P_DEFINE_ATOMIC_INT_CLASS(_Atomic_word, m_storage = value, P_ATOMICITY_NAMESPACE __exchange_and_add)
235 
236 #endif
237 
238  template <typename Enum> struct PAtomicEnum
239  {
240  __inline PAtomicEnum() { }
241  __inline PAtomicEnum(Enum value) : m_enum(value) { }
242  __inline PAtomicEnum(const PAtomicEnum & other) : m_enum(other.m_enum) { }
243  __inline Enum operator=(const PAtomicEnum & other) { Enum value = other; this->store(value); return value; }
244  __inline operator Enum() const { return this->load(); }
245  __inline Enum load() const { return (Enum)this->m_enum.load(); }
246  __inline void store(Enum value) { this->m_enum.store(value); }
247  __inline Enum exchange(Enum value) { return (Enum)this->m_enum.exchange(value); }
248  __inline bool compare_exchange_strong(Enum & comp, Enum value) { return this->m_enum.compare_exchange_strong((int &)comp, value); }
249  private:
250  atomic<int> m_enum;
251  };
252 
253 #endif // P_STD_ATOMIC
254 
255 // For backward compatibility
256 class PAtomicInteger : public atomic<long>
257 {
258  public:
259  typedef long IntegerType;
260  explicit PAtomicInteger(IntegerType value = 0) : atomic<IntegerType>(value) { }
261  __inline PAtomicInteger & operator=(IntegerType value) { atomic<IntegerType>::operator=(value); return *this; }
263  __inline bool IsZero() const { return static_cast<IntegerType>(*this) == 0; }
264 };
265 
266 // For backward compatibility
267 class PAtomicBoolean : public atomic<bool>
268 {
269  public:
270  typedef long IntegerType;
271  explicit PAtomicBoolean(bool value = false) : atomic<bool>(value) { }
272  __inline PAtomicBoolean & operator=(bool value) { atomic<bool>::operator=(value); return *this; }
273  bool TestAndSet(bool value) { return exchange(value); }
274 };
275 
276 
277 #endif // PTLIB_CRITICALSECTION_H
278 
279 
280 // End Of File ///////////////////////////////////////////////////////////////
__inline PAtomicEnum()
Definition: atomic.h:240
__inline PAtomicEnum(const PAtomicEnum &other)
Definition: atomic.h:242
long IntegerType
Definition: atomic.h:270
#define P_DEFINE_ATOMIC_INT_CLASS(Type, Exch, FetchAdd, AddFetch, CompExch)
Definition: atomic.h:106
__inline Enum operator=(const PAtomicEnum &other)
Definition: atomic.h:243
__inline PAtomicBoolean & operator=(bool value)
Definition: atomic.h:272
#define P_DEFINE_ATOMIC_PTR_CLASS(Exch, FetchAdd, AddFetch, CompExch)
Definition: atomic.h:112
void SetValue(IntegerType value)
Definition: atomic.h:262
__inline atomic(Type value)
Definition: atomic.h:46
__inline void store(Enum value)
Definition: atomic.h:246
Definition: atomic.h:267
__inline PAtomicInteger & operator=(IntegerType value)
Definition: atomic.h:261
Definition: atomic.h:256
__inline bool compare_exchange_strong(Enum &comp, Enum value)
Definition: atomic.h:248
__inline atomic & operator=(const atomic &other)
Definition: atomic.h:49
__inline bool IsZero() const
Definition: atomic.h:263
__inline void store(Type value)
Definition: atomic.h:52
long IntegerType
Definition: atomic.h:259
__inline PAtomicEnum(Enum value)
Definition: atomic.h:241
__inline Type exchange(Type value)
Definition: atomic.h:53
__inline atomic()
Definition: atomic.h:45
__inline Enum load() const
Definition: atomic.h:245
__inline Type load() const
Definition: atomic.h:51
PAtomicInteger(IntegerType value=0)
Definition: atomic.h:260
PAtomicBoolean(bool value=false)
Definition: atomic.h:271
__inline Enum exchange(Enum value)
Definition: atomic.h:247
__inline atomic(const atomic &other)
Definition: atomic.h:47
__inline ~atomic()
Definition: atomic.h:48
Definition: atomic.h:43
bool TestAndSet(bool value)
Definition: atomic.h:273
bool compare_exchange_strong(Type &comp, Type value)
Definition: atomic.h:54
Definition: atomic.h:238