CFx SDK Documentation 2024 SP0
Loading...
Searching...
No Matches
OdMutex.h
Go to the documentation of this file.
1
2// Copyright (C) 2002-2022, 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 Open Design Alliance software pursuant to a license
16// agreement with Open Design Alliance.
17// Open Design Alliance Copyright (C) 2002-2022 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 <cstring>
28#include "DebugStuff.h"
29#include "RootExport.h"
30#include <OdPlatform.h>
31#include "TD_PackPush.h"
32#include "OdInterlockedIncDec.h"
33#ifdef OD_POSIX_THREADS
34#include <pthread.h>
35#endif
36#if defined(_MSC_VER)
37#include <winnt.h>
38#endif
39
44protected:
46 }
47
49 }
50
51private:
53 const OdNonCopyable& operator=(const OdNonCopyable&);
54};
55
65{
66#ifdef OD_POSIX_THREADS
67 pthread_mutex_t _mutex;
68public:
70 {
71 pthread_mutexattr_t attr;
72 pthread_mutexattr_init(&attr);
73 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
74 pthread_mutex_init(&_mutex, &attr);
75 pthread_mutexattr_destroy(&attr);
76 }
78 {
79 pthread_mutex_destroy((pthread_mutex_t*)&_mutex);
80 }
84 void lock()
85 {
86 pthread_mutex_lock(&_mutex);
87 }
91 void unlock()
92 {
93 pthread_mutex_unlock(&_mutex);
94 }
95#elif (defined(ODA_WINDOWS)) && !defined(_WIN32_WCE) && !defined(_WINRT)
96 CRITICAL_SECTION _mutex;
97public:
98 OdMutex()
99 {
100 InitializeCriticalSection(&_mutex);
101 }
102 ~OdMutex()
103 {
104 DeleteCriticalSection(&_mutex);
105 }
109 void lock()
110 {
111 EnterCriticalSection(&_mutex);
112 }
116 void unlock()
117 {
118 LeaveCriticalSection(&_mutex);
119 }
120#else
121public:
122 OdMutex() {}
123 ~OdMutex() {}
127 void lock() {}
131 void unlock() {}
132#endif
133};
134
148{
149public:
152 OdMutexAutoLock(OdMutex& mutex) : m_Mutex(mutex)
153 {
154 m_Mutex.lock();
155 }
157 {
158 m_Mutex.unlock();
159 }
160private:
161 OdMutex& m_Mutex;
162};
163
164#ifndef TD_SINGLE_THREAD
165#define TD_AUTOLOCK(Mutex) OdMutexAutoLock autoLock(Mutex);
166#else
167#define TD_AUTOLOCK(Mutex)
168#endif
169
170
171#ifndef TD_SINGLE_THREAD
172#if defined(_MSC_VER) && (_M_IX86) && (_M_IX86 >= 400) && !defined(_WIN32_WCE)
173// Intel486 platform with Microsoft compiler
174#pragma warning(push)
175#pragma warning(disable:4035)
176#pragma warning(disable:4793)
177inline int OdInterlockedExchange(volatile int* dest, int val)
178{
179 __asm
180 {
181 mov edx, dest
182 mov eax, val
183 lock xchg [edx], eax
184 }
185}
186inline int OdInterlockedExchangeAdd(volatile int* dest, int incr)
187{
188 __asm
189 {
190 mov edx, dest
191 mov eax, incr
192 lock xadd [edx], eax
193 }
194}
195
196inline int OdInterlockedCompareExchange(volatile int* dest, int x, int compare)
197{
198 __asm
199 {
200 mov eax, compare
201 mov ecx, x
202 mov edx, dest
203 lock cmpxchg[edx], ecx
204 }
205}
206
207#pragma warning(pop)
208#elif (defined(_WIN32) || defined(_WIN64)) && !defined(ODA_WINDOWS_GCC)
209// Windows platform with generic compiler - use interlocked functions from Win32 API
210#define OdInterlockedExchange(dest, val) InterlockedExchange((LONG*)(dest), val)
211#define OdInterlockedExchangeAdd(dest, incr) InterlockedExchangeAdd((LONG*)(dest), incr)
212#define OdInterlockedCompareExchange(dest, x, compare) InterlockedCompareExchange((LONG*)(dest), x, compare)
213#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && !defined(ANDROID) && !defined(_APPLE_)
214// Intel platform with GCC compiler
215inline int OdInterlockedExchange(volatile int* dest, int val)
216{
217 int ret;
218 __asm__ __volatile__ (
219 "lock; xchgl %0, (%1)"
220 : "=r" (ret)
221 : "r" (dest), "0" (val)
222 : "memory");
223 return ret;
224}
225inline int OdInterlockedCompareExchange(int volatile *dest, int xchg, int compare)
226{
227 int ret;
228 __asm__ __volatile__("lock; cmpxchgl %2,(%1)"
229 : "=a" (ret) : "r" (dest), "r" (xchg), "0" (compare) : "memory");
230 return ret;
231}
232#elif defined(__GNUC__) && defined(__POWERPC__)
233// Macintosh PowerPC platform with GCC compiler
234inline int OdInterlockedExchange(volatile int* dest, int val)
235{
236 // Assembler code is taken from Wine 0.9.4 sources
237 // See http://cvs.winehq.org/cvsweb/wine/libs/port/interlocked.c?rev=1.7&content-type=text/x-cvsweb-markup
238 int ret = 0;
239 __asm__ __volatile__ (
240 "0: lwarx %0, 0, %1\n"
241 " stwcx. %2, 0, %1\n"
242 " bne- 0b\n"
243 " isync\n"
244 : "=&r"(ret)
245 : "r"(dest), "r"(val)
246 : "cr0", "memory", "r0");
247 return ret;
248}
249inline int OdInterlockedExchangeAdd(volatile int* dest, int incr)
250{
251 // Assembler code is taken from Wine 0.9.4 sources
252 // See http://cvs.winehq.org/cvsweb/wine/libs/port/interlocked.c?rev=1.7&content-type=text/x-cvsweb-markup
253 int ret = 0;
254 int zero = 0;
255 __asm__ __volatile__ (
256 "0: lwarx %0, %3, %1\n"
257 " add %0, %2, %0\n"
258 " stwcx. %0, %3, %1\n"
259 " bne- 0b\n"
260 " isync\n"
261 : "=&r" (ret)
262 : "r"(dest), "r"(incr), "r"(zero)
263 : "cr0", "memory", "r0");
264 return ret - incr;
265}
266
267inline int OdInterlockedCompareExchange(volatile int *dest, int xchg, int compare)
268{
269 int ret = 0;
270 int scratch;
271 __asm__ __volatile__(
272 "0: lwarx %0,0,%2\n"
273 " xor. %1,%4,%0\n"
274 " bne 1f\n"
275 " stwcx. %3,0,%2\n"
276 " bne- 0b\n"
277 " isync\n"
278 "1: "
279 : "=&r"(ret), "=&r"(scratch)
280 : "r"(dest), "r"(xchg), "r"(compare)
281 : "cr0", "memory", "r0");
282 return ret;
283}
284
285#elif defined(__APPLE__)
286// iOS or Mac platform
287#include <libkern/OSAtomic.h>
288inline int OdInterlockedExchange(volatile int* dest, int val)
289{
290 int oldValue = *dest;
291 while (!OSAtomicCompareAndSwapIntBarrier(oldValue, val, dest))
292 oldValue = *dest;
293 return oldValue;
294}
295inline int OdInterlockedExchangeAdd(volatile int* dest, int incr)
296{
297 return OSAtomicAdd32Barrier(incr, dest) - incr;
298}
299inline int OdInterlockedCompareExchange(volatile int *dest, int xchg, int compare)
300{
301 // This is not an exact equivalent of InterlockedCompareExchange but it is enough for atomic arithmetics
302 return OSAtomicCompareAndSwapIntBarrier(compare, xchg, dest) ? compare : xchg;
303}
304#elif defined(ANDROID) && !defined(ANDROID_GOOGLE)
305//FELIX_CHANGE_BEGIN
306/*
307#elif defined(ANDROID) && !defined(ANDROID_GOOGLE)
308//TODO Android r10c NDK doesn't provide such functionality
309// Android platform with GCC or MinGW compiler
310#include <sys/atomics.h>
311inline int OdInterlockedExchange(volatile int* dest, int val)
312{
313 return __atomic_swap(val, dest);
314}
315inline int OdInterlockedExchangeAdd(volatile int* dest, int incr)
316{
317 // There is no atomic instruction to add. This implementation isn't completely safe.
318 return __atomic_swap(*dest + incr, dest);
319}
320inline int OdInterlockedCompareExchange(volatile int *dest, int xchg, int compare)
321{
322 return __atomic_cmpxchg(dest, xchg, compare);
323}
324#define OdInterlockedExchange(dest, val) InterlockedExchange((LONG*)(dest), val)
325#define OdInterlockedExchangeAdd(dest, incr) InterlockedExchangeAdd((LONG*)(dest), incr)
326#define OdInterlockedCompareExchange(dest, x, compare) InterlockedCompareExchange((LONG*)(dest), x, compare)
327struct OdVolatile
328{
329 typedef int VolatileType;
330 volatile VolatileType _val;
331 OdVolatile& operator = (VolatileType n) { _val = 0; OdInterlockedExchange(&_val, n); return *this; }
332 operator VolatileType () const { return OdInterlockedExchangeAdd(const_cast<VolatileType*>(&_val), 0); }
333 VolatileType operator|=(VolatileType n) { return OdInterlockedExchange(&_val, _val | n); }
334 VolatileType operator&=(VolatileType n) { return OdInterlockedExchange(&_val, _val&n); }
335 OdVolatile() : _val(0) {}
336 OdVolatile(int n) : _val(n) {}
337};*/
338*/
339#elif defined(ANDROID)
340inline int OdInterlockedExchange(volatile int* dest, int val)
341{
342 return __sync_lock_test_and_set(dest, val);
343}
344inline int OdInterlockedExchangeAdd(volatile int* dest, int incr)
345{
346 // There is no atomic instruction to add. This implementation isn't completely safe.
347 return __sync_fetch_and_add(dest, incr);
348}
349inline int OdInterlockedIncrement(volatile int* dest)
350{
351 return __sync_fetch_and_add(dest, 1) + 1;
352}
353inline int OdInterlockedDecrement(volatile int* dest)
354{
355 return __sync_fetch_and_sub(dest, 1) - 1;
356}
357//FELIX_CHANGE_END
358/*
359#elif defined(__sun)
360// sparc on Sun Studio compiler, solaris
361#include <atomic.h>
362inline int OdInterlockedExchange(volatile int* dest, int val)
363{
364 return (int)atomic_swap_uint((volatile uint_t*)dest, (uint_t)val);
365}
366inline int OdInterlockedExchangeAdd(volatile int* dest, int incr)
367{
368 return (int)atomic_add_int_nv((volatile uint_t*)dest, incr) - incr;
369}
370#elif defined (__hpux)
371// HPUX (require libatomic: https://h20392.www2.hp.com/portal/swdepot/displayProductInfo.do?productNumber=Atomic)
372#include <atomic.h>
373inline int OdInterlockedExchange(volatile int* dest, int val)
374{
375 return (int)atomic_swap_32((volatile uint32_t*)dest, (uint32_t)val);
376}
377inline int OdInterlockedExchangeAdd(volatile int* dest, int incr)
378{
379 // There is no atomic instruction to add. This implementation isn't completely safe.
380 return (int)atomic_swap_32((volatile uint32_t*)dest, (uint32_t)(*desc + incr));
381}*/
382#elif defined(ANDROID) //&& defined(ANDROID_GOOGLE)
383
384inline int OdInterlockedExchange(volatile int* dest, int val)
385{
386 int oldVal = *dest;
387 __sync_val_compare_and_swap(dest, oldVal, val);
388 return oldVal;
389}
390inline int OdInterlockedExchangeAdd(volatile int* dest, int incr)
391{
392 int oldVal = *dest;
393 __sync_val_compare_and_swap(dest, oldVal, incr + oldVal);
394 return oldVal;
395}
396inline int OdInterlockedCompareExchange(volatile int *dest, int xchg, int compare)
397{
398 bool bRes = __sync_bool_compare_and_swap(dest, compare, xchg);
399 return bRes ? xchg : compare;
400}
404struct OdRefCounter
405{
406 typedef int RefCounterType;
407 volatile RefCounterType _ref_count;
408 OdRefCounter& operator = (RefCounterType n) { _ref_count = 0; OdInterlockedExchange(&_ref_count, n); return *this; }
409 operator RefCounterType () const { return OdInterlockedExchangeAdd(const_cast<RefCounterType*>(&_ref_count), 0); }
410 RefCounterType operator ++ () { return OdInterlockedIncrement(&_ref_count); }
411 RefCounterType operator -- () { return OdInterlockedDecrement(&_ref_count); }
412 // 1 as default is not correct for all classes
413 // (see for example OdArrayBuffer, CAllocator)
414 OdRefCounter() : _ref_count(-1) {} // undefined
415 OdRefCounter(int n) : _ref_count(n) {}
416};
417
421struct OdVolatile
422{
423 typedef int VolatileType;
424 volatile VolatileType _val;
425 OdVolatile& operator = (VolatileType n) { _val = 0; OdInterlockedExchange(&_val, n); return *this; }
426 operator VolatileType () const { return OdInterlockedExchangeAdd(const_cast<VolatileType*>(&_val), 0); }
427 VolatileType operator|=(VolatileType n) { return OdInterlockedExchange(&_val, _val | n); }
428 VolatileType operator&=(VolatileType n) { return OdInterlockedExchange(&_val, _val&n); }
429 OdVolatile() : _val(0) {}
430 OdVolatile(int n) : _val(n) {}
431};
432#else
433// here should go other platforms
434// synchronization is disabled if no atomic functions are defined
435#define TD_SINGLE_THREAD
436#endif //architecture
437#endif //TD_SINGLE_THREAD
438
445#if !(defined(ANDROID)) //&& defined(ANDROID_GOOGLE))
446#ifndef TD_SINGLE_THREAD
447#ifdef _MANAGED
448#pragma managed(push, off)
449#endif
453 struct OdRefCounter
454{
455 typedef int RefCounterType;
456 volatile RefCounterType _ref_count;
457 OdRefCounter& operator = (RefCounterType n) { _ref_count = 0; OdInterlockedExchange(&_ref_count, n); return *this; }
458 operator RefCounterType () const { return OdInterlockedExchangeAdd(const_cast<RefCounterType*>(&_ref_count), 0); }
459 RefCounterType operator ++ () { return OdInterlockedIncrement(&_ref_count); }
460 RefCounterType operator -- () { return OdInterlockedDecrement(&_ref_count); }
461 // 1 as default is not correct for all classes
462 // (see for example OdArrayBuffer, CAllocator)
463 OdRefCounter() : _ref_count(-1) {} // undefined
464 OdRefCounter(int n) : _ref_count(n) {}
465};
466
470 struct OdVolatile
471{
472 typedef int VolatileType;
473 volatile VolatileType _val;
474 OdVolatile& operator = (VolatileType n) { _val = 0; OdInterlockedExchange(&_val, n); return *this; }
475 operator VolatileType () const { return OdInterlockedExchangeAdd(const_cast<VolatileType*>(&_val), 0); }
476 VolatileType operator|=(VolatileType n) { return OdInterlockedExchange(&_val, _val|n); }
477 VolatileType operator&=(VolatileType n) { return OdInterlockedExchange(&_val, _val&n); }
478 OdVolatile() : _val(0) {}
479 OdVolatile(int n): _val(n) {}
480};
481
482#ifdef _MANAGED
483#pragma managed(pop)
484#endif
485
486#else
487typedef int OdRefCounter;
488typedef int OdVolatile;
489#endif
490#endif
491#include "TD_PackPop.h"
492#endif
int OdVolatile
Definition: OdMutex.h:488
int OdRefCounter
Definition: OdMutex.h:487
#define FIRSTDLL_EXPORT
Definition: RootExport.h:39
OdMutexAutoLock(OdMutex &mutex)
Definition: OdMutex.h:152
void lock()
Definition: OdMutex.h:84
void unlock()
Definition: OdMutex.h:91
~OdMutex()
Definition: OdMutex.h:77
OdMutex()
Definition: OdMutex.h:69
~OdNonCopyable()
Definition: OdMutex.h:48
OdNonCopyable()
Definition: OdMutex.h:45
GLfloat x
Definition: gles2_ext.h:314