CFx SDK Documentation  2022 SP0
OdMutex.h
Go to the documentation of this file.
1 // Copyright (C) 2002-2017, Open Design Alliance (the "Alliance").
3 // All rights reserved.
4 //
5 // This software and its documentation and related materials are owned by
6 // the Alliance. The software may only be incorporated into application
7 // programs owned by members of the Alliance, subject to a signed
8 // Membership Agreement and Supplemental Software License Agreement with the
9 // Alliance. The structure and organization of this software are the valuable
10 // trade secrets of the Alliance and its suppliers. The software is also
11 // protected by copyright law and international treaty provisions. Application
12 // programs incorporating this software must include the following statement
13 // with their copyright notices:
14 //
15 // This application incorporates Teigha(R) software pursuant to a license
16 // agreement with Open Design Alliance.
17 // Teigha(R) Copyright (C) 2002-2017 by Open Design Alliance.
18 // All rights reserved.
19 //
20 // By use of this software, its documentation or related materials, you
21 // acknowledge and accept the above terms.
23 
24 #ifndef _OD_MUTEX_H_
25 #define _OD_MUTEX_H_
26 
27 #include "RootExport.h"
28 #include "TD_PackPush.h"
29 #ifdef OD_POSIX_THREADS
30 #include <pthread.h>
31 #elif defined(ODA_WINDOWS)
32 #ifndef WIN32_LEAN_AND_MEAN
33 #define WIN32_LEAN_AND_MEAN
34 #endif
35 #ifndef NOMINMAX
36 #define NOMINMAX
37 #endif
38 #include <windows.h>
39 #endif
40 
50 {
51 #ifdef OD_POSIX_THREADS
52  pthread_mutex_t _mutex;
53 public:
55  {
56  pthread_mutexattr_t attr;
57  pthread_mutexattr_init(&attr);
58  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
59  pthread_mutex_init(&_mutex, &attr);
60  pthread_mutexattr_destroy(&attr);
61  }
63  {
64  pthread_mutex_destroy((pthread_mutex_t*)&_mutex);
65  }
69  void lock()
70  {
71  pthread_mutex_lock(&_mutex);
72  }
76  void unlock()
77  {
78  pthread_mutex_unlock(&_mutex);
79  }
80 #elif (defined(ODA_WINDOWS)) && !defined(_WIN32_WCE) && !defined(_WINRT)
81  CRITICAL_SECTION _mutex;
82 public:
83  OdMutex()
84  {
85  InitializeCriticalSection(&_mutex);
86  }
87  ~OdMutex()
88  {
89  DeleteCriticalSection(&_mutex);
90  }
94  void lock()
95  {
96  EnterCriticalSection(&_mutex);
97  }
101  void unlock()
102  {
103  LeaveCriticalSection(&_mutex);
104  }
105 #else
106 public:
107  OdMutex() {}
108  ~OdMutex() {}
112  void lock() {}
116  void unlock() {}
117 #endif
118 };
119 
133 {
134 public:
137  OdMutexAutoLock(OdMutex& mutex) : m_Mutex(mutex)
138  {
139  m_Mutex.lock();
140  }
142  {
143  m_Mutex.unlock();
144  }
145 private:
146  OdMutex& m_Mutex;
147 };
148 
149 #ifndef TD_SINGLE_THREAD
150 #define TD_AUTOLOCK(Mutex) OdMutexAutoLock autoLock(Mutex);
151 #else
152 #define TD_AUTOLOCK(Mutex)
153 #endif
154 
155 
156 #ifndef TD_SINGLE_THREAD
157 #if defined(_MSC_VER) && _M_IX86 >= 400 && !defined(_WIN32_WCE)
158 // Intel486 platform with Microsoft compiler
159 #pragma warning(push)
160 #pragma warning(disable:4035)
161 #pragma warning(disable:4793)
162 inline int OdInterlockedExchange(volatile int* dest, int val)
163 {
164  __asm
165  {
166  mov edx, dest
167  mov eax, val
168  lock xchg [edx], eax
169  }
170 }
171 inline int OdInterlockedExchangeAdd(volatile int* dest, int incr)
172 {
173  __asm
174  {
175  mov edx, dest
176  mov eax, incr
177  lock xadd [edx], eax
178  }
179 }
180 inline int OdInterlockedIncrement(volatile int* dest)
181 {
182  __asm
183  {
184  mov edx, dest
185  mov eax, 1
186  lock xadd [edx], eax
187  inc eax
188  }
189 }
190 inline int OdInterlockedDecrement(volatile int* dest)
191 {
192  __asm
193  {
194  mov edx, dest
195  mov eax, -1
196  lock xadd [edx], eax
197  dec eax
198  }
199 }
200 #pragma warning(pop)
201 #elif (defined(_WIN32) || defined(_WIN64)) && !defined(_WIN32_WCE) && !defined(_WINRT) && !defined(ODA_WINDOWS_GCC)
202 // Windows platform with generic compiler - use interlocked functions from Win32 API
203 #define OdInterlockedExchange(dest, val) InterlockedExchange((LONG*)(dest), val)
204 #define OdInterlockedExchangeAdd(dest, incr) InterlockedExchangeAdd((LONG*)(dest), incr)
205 #define OdInterlockedIncrement(dest) InterlockedIncrement((LONG*)(dest))
206 #define OdInterlockedDecrement(dest) InterlockedDecrement((LONG*)(dest))
207 #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
208 // Intel platform with GCC compiler
209 inline int OdInterlockedExchange(volatile int* dest, int val)
210 {
211  int ret;
212  __asm__ __volatile__ (
213  "lock; xchgl %0, (%1)"
214  : "=r" (ret)
215  : "r" (dest), "0" (val)
216  : "memory");
217  return ret;
218 }
219 inline int OdInterlockedExchangeAdd(volatile int* dest, int incr)
220 {
221  int ret;
222  __asm__ __volatile__ (
223  "lock; xaddl %0, (%1)"
224  : "=r" (ret)
225  : "r" (dest), "0" (incr)
226  : "memory");
227  return ret;
228 }
229 inline int OdInterlockedIncrement(volatile int* dest)
230 {
231  return OdInterlockedExchangeAdd(dest, 1) + 1;
232 }
233 inline int OdInterlockedDecrement(volatile int* dest)
234 {
235  return OdInterlockedExchangeAdd(dest, -1) - 1;
236 }
237 #elif defined(__GNUC__) && defined(__POWERPC__)
238 // Macintosh PowerPC platform with GCC compiler
239 inline int OdInterlockedExchange(volatile int* dest, int val)
240 {
241  // Assembler code is taken from Wine 0.9.4 sources
242  // See http://cvs.winehq.org/cvsweb/wine/libs/port/interlocked.c?rev=1.7&content-type=text/x-cvsweb-markup
243  int ret = 0;
244  __asm__ __volatile__ (
245  "0: lwarx %0, 0, %1\n"
246  " stwcx. %2, 0, %1\n"
247  " bne- 0b\n"
248  " isync\n"
249  : "=&r"(ret)
250  : "r"(dest), "r"(val)
251  : "cr0", "memory", "r0");
252  return ret;
253 }
254 inline int OdInterlockedExchangeAdd(volatile int* dest, int incr)
255 {
256  // Assembler code is taken from Wine 0.9.4 sources
257  // See http://cvs.winehq.org/cvsweb/wine/libs/port/interlocked.c?rev=1.7&content-type=text/x-cvsweb-markup
258  int ret = 0;
259  int zero = 0;
260  __asm__ __volatile__ (
261  "0: lwarx %0, %3, %1\n"
262  " add %0, %2, %0\n"
263  " stwcx. %0, %3, %1\n"
264  " bne- 0b\n"
265  " isync\n"
266  : "=&r" (ret)
267  : "r"(dest), "r"(incr), "r"(zero)
268  : "cr0", "memory", "r0");
269  return ret - incr;
270 }
271 inline int OdInterlockedIncrement(volatile int* dest)
272 {
273  return OdInterlockedExchangeAdd(dest, 1) + 1;
274 }
275 inline int OdInterlockedDecrement(volatile int* dest)
276 {
277  return OdInterlockedExchangeAdd(dest, -1) - 1;
278 }
279 #elif defined(__APPLE__)
280 // iOS or Mac platform
281 #include <libkern/OSAtomic.h>
282 inline int OdInterlockedExchange(volatile int* dest, int val)
283 {
284  int oldValue = *dest;
285  while (!OSAtomicCompareAndSwapIntBarrier(oldValue, val, dest))
286  oldValue = *dest;
287  return oldValue;
288 }
289 inline int OdInterlockedExchangeAdd(volatile int* dest, int incr)
290 {
291  return OSAtomicAdd32Barrier(incr, dest) - incr;
292 }
293 inline int OdInterlockedIncrement(volatile int* dest)
294 {
295  return OSAtomicIncrement32Barrier(dest);
296 }
297 inline int OdInterlockedDecrement(volatile int* dest)
298 {
299  return OSAtomicDecrement32Barrier(dest);
300 }
301 //FELIX_CHANGE_BEGIN
302 /*
303 #elif defined(ANDROID) && !defined(ANDROID_GOOGLE)
304 //TODO Android r10c NDK doesn't provide such functionality
305 // Android platform with GCC or MinGW compiler
306 #include <sys/atomics.h>
307 inline int OdInterlockedExchange(volatile int* dest, int val)
308 {
309  return __atomic_swap(val, dest);
310 }
311 inline int OdInterlockedExchangeAdd(volatile int* dest, int incr)
312 {
313  // There is no atomic instruction to add. This implementation isn't completely safe.
314  return __atomic_swap(*dest + incr, dest);
315 }
316 inline int OdInterlockedIncrement(volatile int* dest)
317 {
318  return __atomic_inc(dest) + 1;
319 }
320 inline int OdInterlockedDecrement(volatile int* dest)
321 {
322  return __atomic_dec(dest) - 1;
323 }
324 */
325 #elif defined(ANDROID)
326 inline int OdInterlockedExchange(volatile int* dest, int val)
327 {
328  return __sync_lock_test_and_set(dest, val);
329 }
330 inline int OdInterlockedExchangeAdd(volatile int* dest, int incr)
331 {
332  // There is no atomic instruction to add. This implementation isn't completely safe.
333  return __sync_fetch_and_add(dest, incr);
334 }
335 inline int OdInterlockedIncrement(volatile int* dest)
336 {
337  return __sync_fetch_and_add(dest, 1) + 1;
338 }
339 inline int OdInterlockedDecrement(volatile int* dest)
340 {
341  return __sync_fetch_and_sub(dest, 1) - 1;
342 }
343 //FELIX_CHANGE_END
344 /*
345 #elif defined(__sun)
346 // sparc on Sun Studio compiler, solaris
347 #include <atomic.h>
348 inline int OdInterlockedExchange(volatile int* dest, int val)
349 {
350  return (int)atomic_swap_uint((volatile uint_t*)dest, (uint_t)val);
351 }
352 inline int OdInterlockedExchangeAdd(volatile int* dest, int incr)
353 {
354  return (int)atomic_add_int_nv((volatile uint_t*)dest, incr) - incr;
355 }
356 inline int OdInterlockedIncrement(volatile int* dest)
357 {
358  return (int)atomic_inc_uint_nv((volatile uint_t*)dest);
359 }
360 inline int OdInterlockedDecrement(volatile int* dest)
361 {
362  return (int)atomic_dec_uint_nv((volatile uint_t*)dest);
363 }
364 #elif defined (__hpux)
365 // HPUX (require libatomic: https://h20392.www2.hp.com/portal/swdepot/displayProductInfo.do?productNumber=Atomic)
366 #include <atomic.h>
367 inline int OdInterlockedExchange(volatile int* dest, int val)
368 {
369  return (int)atomic_swap_32((volatile uint32_t*)dest, (uint32_t)val);
370 }
371 inline int OdInterlockedExchangeAdd(volatile int* dest, int incr)
372 {
373  // There is no atomic instruction to add. This implementation isn't completely safe.
374  return (int)atomic_swap_32((volatile uint32_t*)dest, (uint32_t)(*desc + incr));
375 }
376 inline int OdInterlockedIncrement(volatile int* dest)
377 {
378  return (int)atomic_inc_32((volatile uint32_t*)dest) + 1;
379 }
380 inline int OdInterlockedDecrement(volatile int* dest)
381 {
382  return (int)atomic_dec_32((volatile uint32_t*)dest) - 1;
383 }*/
384 #else
385 // here should go other platforms
386 // synchronization is disabled if no atomic functions are defined
387 #define TD_SINGLE_THREAD
388 #endif //architecture
389 #endif //TD_SINGLE_THREAD
390 
397 #ifndef TD_SINGLE_THREAD
398 #ifdef _MANAGED
399 #pragma managed(push, off)
400 #endif
403  struct OdRefCounter
404 {
405  typedef int RefCounterType;
406  volatile RefCounterType _ref_count;
407  OdRefCounter& operator = (RefCounterType n) { _ref_count = 0; OdInterlockedExchange(&_ref_count, n); return *this; }
408  operator RefCounterType () const { return OdInterlockedExchangeAdd(const_cast<RefCounterType*>(&_ref_count), 0); }
409  RefCounterType operator ++ () { return OdInterlockedIncrement(&_ref_count); }
410  RefCounterType operator -- () { return OdInterlockedDecrement(&_ref_count); }
411  // 1 as default is not correct for all classes
412  // (see for example OdArrayBuffer, CAllocator)
413  OdRefCounter() : _ref_count(-1) {} // undefined
414  OdRefCounter(int n) : _ref_count(n) {}
415 };
416 
419  struct OdVolatile
420 {
421  typedef int VolatileType;
422  volatile VolatileType _val;
423  OdVolatile& operator = (VolatileType n) { _val = 0; OdInterlockedExchange(&_val, n); return *this; }
424  operator VolatileType () const { return OdInterlockedExchangeAdd(const_cast<VolatileType*>(&_val), 0); }
425  VolatileType operator|=(VolatileType n) { return OdInterlockedExchange(&_val, _val|n); }
426  VolatileType operator&=(VolatileType n) { return OdInterlockedExchange(&_val, _val&n); }
427  OdVolatile() : _val(0) {}
428  OdVolatile(int n): _val(n) {}
429 };
430 
431 #ifdef _MANAGED
432 #pragma managed(pop)
433 #endif
434 
435 #else
436 typedef int OdRefCounter;
437 typedef int OdVolatile;
438 #endif
439 
440 #include "TD_PackPop.h"
441 #endif
dec
Definition: DimVarDefs.h:953
int OdVolatile
Definition: OdMutex.h:437
int OdRefCounter
Definition: OdMutex.h:436
#define FIRSTDLL_EXPORT
Definition: RootExport.h:39
OdMutexAutoLock(OdMutex &mutex)
Definition: OdMutex.h:137
void lock()
Definition: OdMutex.h:69
void unlock()
Definition: OdMutex.h:76
~OdMutex()
Definition: OdMutex.h:62
OdMutex()
Definition: OdMutex.h:54