Commit | Line | Data |
---|---|---|
b311480e | 1 | // Created on: 2007-09-04 |
2 | // Created by: Andrey BETENEV | |
973c2be1 | 3 | // Copyright (c) 2007-2014 OPEN CASCADE SAS |
b311480e | 4 | // |
973c2be1 | 5 | // This file is part of Open CASCADE Technology software library. |
b311480e | 6 | // |
d5f74e42 | 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 | |
973c2be1 | 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. | |
b311480e | 12 | // |
973c2be1 | 13 | // Alternatively, this file may be used under the terms of Open CASCADE |
14 | // commercial license or contractual agreement. | |
b311480e | 15 | |
1365140b RL |
16 | //! @file |
17 | //! Implementation of some atomic operations (elementary operations | |
7fd59977 | 18 | //! with data that cannot be interrupted by parallel threads in the |
19 | //! multithread process) on various platforms | |
20 | //! | |
1365140b | 21 | //! By the moment, only operations necessary for reference counter |
7fd59977 | 22 | //! in Standard_Transient objects are implemented. |
1365140b | 23 | //! |
e33e7e78 RK |
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. | |
7fd59977 | 26 | |
e33e7e78 RK |
27 | #ifndef _Standard_Atomic_HeaderFile |
28 | #define _Standard_Atomic_HeaderFile | |
7fd59977 | 29 | |
1365140b RL |
30 | //! Increments atomically integer variable pointed by theValue |
31 | //! and returns resulting incremented value. | |
32 | inline int Standard_Atomic_Increment (volatile int* theValue); | |
33 | ||
34 | //! Decrements atomically integer variable pointed by theValue | |
35 | //! and returns resulting decremented value. | |
36 | inline int Standard_Atomic_Decrement (volatile int* theValue); | |
37 | ||
6f498847 | 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); | |
45 | ||
1365140b RL |
46 | // Platform-dependent implementation |
47 | #if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) | |
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 | |
54 | // enforced. | |
55 | ||
56 | int Standard_Atomic_Increment (volatile int* theValue) | |
57 | { | |
58 | return __sync_add_and_fetch (theValue, 1); | |
59 | } | |
60 | ||
61 | int Standard_Atomic_Decrement (volatile int* theValue) | |
62 | { | |
63 | return __sync_sub_and_fetch (theValue, 1); | |
64 | } | |
7fd59977 | 65 | |
6f498847 | 66 | bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue) |
67 | { | |
68 | return __sync_val_compare_and_swap (theValue, theOldValue, theNewValue) == theOldValue; | |
69 | } | |
70 | ||
9bf6baed | 71 | #elif defined(_WIN32) |
7fd59977 | 72 | extern "C" { |
1365140b RL |
73 | long _InterlockedIncrement (volatile long* lpAddend); |
74 | long _InterlockedDecrement (volatile long* lpAddend); | |
6f498847 | 75 | long _InterlockedCompareExchange (long volatile* Destination, long Exchange, long Comparand); |
7fd59977 | 76 | } |
77 | ||
cf0786da | 78 | #if defined(_MSC_VER) && ! defined(__INTEL_COMPILER) |
e33e7e78 RK |
79 | // force intrinsic instead of WinAPI calls |
80 | #pragma intrinsic (_InterlockedIncrement) | |
81 | #pragma intrinsic (_InterlockedDecrement) | |
6f498847 | 82 | #pragma intrinsic (_InterlockedCompareExchange) |
e33e7e78 | 83 | #endif |
7fd59977 | 84 | |
1365140b RL |
85 | // WinAPI function or MSVC intrinsic |
86 | // Note that we safely cast int* to long*, as they have same size and endian-ness | |
87 | ||
88 | int Standard_Atomic_Increment (volatile int* theValue) | |
7fd59977 | 89 | { |
1365140b RL |
90 | return _InterlockedIncrement (reinterpret_cast<volatile long*>(theValue)); |
91 | } | |
92 | ||
93 | int Standard_Atomic_Decrement (volatile int* theValue) | |
94 | { | |
95 | return _InterlockedDecrement (reinterpret_cast<volatile long*>(theValue)); | |
96 | } | |
97 | ||
6f498847 | 98 | bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue) |
99 | { | |
100 | return _InterlockedCompareExchange (reinterpret_cast<volatile long*>(theValue), theNewValue, theOldValue) == theOldValue; | |
101 | } | |
102 | ||
1365140b RL |
103 | #elif defined(__APPLE__) |
104 | // use atomic operations provided by MacOS | |
105 | ||
106 | #include <libkern/OSAtomic.h> | |
107 | ||
108 | int Standard_Atomic_Increment (volatile int* theValue) | |
109 | { | |
110 | return OSAtomicIncrement32Barrier (theValue); | |
111 | } | |
112 | ||
113 | int Standard_Atomic_Decrement (volatile int* theValue) | |
114 | { | |
115 | return OSAtomicDecrement32Barrier (theValue); | |
116 | } | |
117 | ||
6f498847 | 118 | bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue) |
119 | { | |
120 | return OSAtomicCompareAndSwapInt (theOldValue, theNewValue, theValue); | |
121 | } | |
122 | ||
0304f711 | 123 | #elif defined(__ANDROID__) |
9bf6baed | 124 | |
0304f711 | 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. | |
9bf6baed | 130 | #include <sys/atomics.h> |
0304f711 | 131 | |
132 | int Standard_Atomic_Increment (volatile int* theValue) | |
133 | { | |
9bf6baed | 134 | return __atomic_inc (theValue) + 1; // analog of __sync_fetch_and_add |
0304f711 | 135 | } |
136 | ||
137 | int Standard_Atomic_Decrement (volatile int* theValue) | |
138 | { | |
9bf6baed | 139 | return __atomic_dec (theValue) - 1; // analog of __sync_fetch_and_sub |
0304f711 | 140 | } |
141 | ||
6f498847 | 142 | bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue) |
1365140b | 143 | { |
6f498847 | 144 | return __atomic_cmpxchg (theOldValue, theNewValue, theValue) == 0; |
1365140b RL |
145 | } |
146 | ||
7fd59977 | 147 | #else |
1365140b RL |
148 | |
149 | #ifndef IGNORE_NO_ATOMICS | |
150 | #error "Atomic operation isn't implemented for current platform!" | |
e33e7e78 | 151 | #endif |
1365140b RL |
152 | int Standard_Atomic_Increment (volatile int* theValue) |
153 | { | |
154 | return ++(*theValue); | |
7fd59977 | 155 | } |
156 | ||
1365140b | 157 | int Standard_Atomic_Decrement (volatile int* theValue) |
7fd59977 | 158 | { |
e33e7e78 | 159 | return --(*theValue); |
7fd59977 | 160 | } |
161 | ||
6f498847 | 162 | bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue) |
163 | { | |
164 | if (*theValue == theOldValue) | |
165 | { | |
166 | *theValue = theNewValue; | |
167 | return true; | |
168 | } | |
169 | return false; | |
170 | } | |
171 | ||
1365140b RL |
172 | #endif |
173 | ||
e33e7e78 | 174 | #endif //_Standard_Atomic_HeaderFile |