1 // Created on: 2007-09-04
2 // Created by: Andrey BETENEV
3 // Copyright (c) 2007-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
17 //! Implementation of some atomic operations (elementary operations
18 //! with data that cannot be interrupted by parallel threads in the
19 //! multithread process) on various platforms
21 //! By the moment, only operations necessary for reference counter
22 //! in Standard_Transient objects are implemented.
24 //! This is preffered to use fixed size types "int32_t" / "int64_t" for
25 //! correct function declarations however we leave "int" assuming it is 32bits for now.
27 #ifndef _Standard_Atomic_HeaderFile
28 #define _Standard_Atomic_HeaderFile
30 //! Increments atomically integer variable pointed by theValue
31 //! and returns resulting incremented value.
32 inline int Standard_Atomic_Increment (volatile int* theValue);
34 //! Decrements atomically integer variable pointed by theValue
35 //! and returns resulting decremented value.
36 inline int Standard_Atomic_Decrement (volatile int* theValue);
38 //! Perform an atomic compare and swap.
39 //! That is, if the current value of *theValue is theOldValue, then write theNewValue into *theValue.
40 //! @param theValue pointer to variable to modify
41 //! @param theOldValue expected value to perform modification
42 //! @param theNewValue new value to set in case if *theValue was equal to theOldValue
43 //! @return TRUE if theNewValue has been set to *theValue
44 inline bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue);
46 // Platform-dependent implementation
47 #if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(__EMSCRIPTEN__)
48 // gcc explicitly defines the macros __GCC_HAVE_SYNC_COMPARE_AND_SWAP_*
49 // starting with version 4.4+, although built-in functions
50 // are available since 4.1.x. However unless __GCC_HAVE_SYNC_COMPARE_AND_SWAP_*
51 // are defined, linking may fail without specifying -march option when
52 // building for 32bit architecture on 64bit (using -m32 option). To avoid
53 // making -march mandatory, check for __GCC_HAVE_SYNC_COMPARE_AND_SWAP_* is
56 int Standard_Atomic_Increment (volatile int* theValue)
58 return __sync_add_and_fetch (theValue, 1);
61 int Standard_Atomic_Decrement (volatile int* theValue)
63 return __sync_sub_and_fetch (theValue, 1);
66 bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
68 return __sync_val_compare_and_swap (theValue, theOldValue, theNewValue) == theOldValue;
73 long _InterlockedIncrement (volatile long* lpAddend);
74 long _InterlockedDecrement (volatile long* lpAddend);
75 long _InterlockedCompareExchange (long volatile* Destination, long Exchange, long Comparand);
78 #if defined(_MSC_VER) && ! defined(__INTEL_COMPILER)
79 // force intrinsic instead of WinAPI calls
80 #pragma intrinsic (_InterlockedIncrement)
81 #pragma intrinsic (_InterlockedDecrement)
82 #pragma intrinsic (_InterlockedCompareExchange)
85 // WinAPI function or MSVC intrinsic
86 // Note that we safely cast int* to long*, as they have same size and endian-ness
88 int Standard_Atomic_Increment (volatile int* theValue)
90 return _InterlockedIncrement (reinterpret_cast<volatile long*>(theValue));
93 int Standard_Atomic_Decrement (volatile int* theValue)
95 return _InterlockedDecrement (reinterpret_cast<volatile long*>(theValue));
98 bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
100 return _InterlockedCompareExchange (reinterpret_cast<volatile long*>(theValue), theNewValue, theOldValue) == theOldValue;
103 #elif defined(__APPLE__)
104 // use atomic operations provided by MacOS
106 #include <libkern/OSAtomic.h>
108 int Standard_Atomic_Increment (volatile int* theValue)
110 return OSAtomicIncrement32Barrier (theValue);
113 int Standard_Atomic_Decrement (volatile int* theValue)
115 return OSAtomicDecrement32Barrier (theValue);
118 bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
120 return OSAtomicCompareAndSwapInt (theOldValue, theNewValue, theValue);
123 #elif defined(__ANDROID__)
125 // Atomic operations that were exported by the C library didn't
126 // provide any memory barriers, which created potential issues on
127 // multi-core devices. Starting from ndk version r7b they are defined as
128 // inlined calls to GCC sync builtins, which always provide a full barrier.
129 // It is strongly recommended to use newer versions of ndk.
130 #include <sys/atomics.h>
132 int Standard_Atomic_Increment (volatile int* theValue)
134 return __atomic_inc (theValue) + 1; // analog of __sync_fetch_and_add
137 int Standard_Atomic_Decrement (volatile int* theValue)
139 return __atomic_dec (theValue) - 1; // analog of __sync_fetch_and_sub
142 bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
144 return __atomic_cmpxchg (theOldValue, theNewValue, theValue) == 0;
149 #ifndef IGNORE_NO_ATOMICS
150 #error "Atomic operation isn't implemented for current platform!"
152 int Standard_Atomic_Increment (volatile int* theValue)
154 return ++(*theValue);
157 int Standard_Atomic_Decrement (volatile int* theValue)
159 return --(*theValue);
162 bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
164 if (*theValue == theOldValue)
166 *theValue = theNewValue;
174 #endif //_Standard_Atomic_HeaderFile