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