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 | ||
38 | // Platform-dependent implementation | |
39 | #if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) | |
40 | // gcc explicitly defines the macros __GCC_HAVE_SYNC_COMPARE_AND_SWAP_* | |
41 | // starting with version 4.4+, although built-in functions | |
42 | // are available since 4.1.x. However unless __GCC_HAVE_SYNC_COMPARE_AND_SWAP_* | |
43 | // are defined, linking may fail without specifying -march option when | |
44 | // building for 32bit architecture on 64bit (using -m32 option). To avoid | |
45 | // making -march mandatory, check for __GCC_HAVE_SYNC_COMPARE_AND_SWAP_* is | |
46 | // enforced. | |
47 | ||
48 | int Standard_Atomic_Increment (volatile int* theValue) | |
49 | { | |
50 | return __sync_add_and_fetch (theValue, 1); | |
51 | } | |
52 | ||
53 | int Standard_Atomic_Decrement (volatile int* theValue) | |
54 | { | |
55 | return __sync_sub_and_fetch (theValue, 1); | |
56 | } | |
7fd59977 | 57 | |
9bf6baed | 58 | #elif defined(_WIN32) |
7fd59977 | 59 | extern "C" { |
1365140b RL |
60 | long _InterlockedIncrement (volatile long* lpAddend); |
61 | long _InterlockedDecrement (volatile long* lpAddend); | |
7fd59977 | 62 | } |
63 | ||
cf0786da | 64 | #if defined(_MSC_VER) && ! defined(__INTEL_COMPILER) |
e33e7e78 RK |
65 | // force intrinsic instead of WinAPI calls |
66 | #pragma intrinsic (_InterlockedIncrement) | |
67 | #pragma intrinsic (_InterlockedDecrement) | |
68 | #endif | |
7fd59977 | 69 | |
1365140b RL |
70 | // WinAPI function or MSVC intrinsic |
71 | // Note that we safely cast int* to long*, as they have same size and endian-ness | |
72 | ||
73 | int Standard_Atomic_Increment (volatile int* theValue) | |
7fd59977 | 74 | { |
1365140b RL |
75 | return _InterlockedIncrement (reinterpret_cast<volatile long*>(theValue)); |
76 | } | |
77 | ||
78 | int Standard_Atomic_Decrement (volatile int* theValue) | |
79 | { | |
80 | return _InterlockedDecrement (reinterpret_cast<volatile long*>(theValue)); | |
81 | } | |
82 | ||
83 | #elif defined(__APPLE__) | |
84 | // use atomic operations provided by MacOS | |
85 | ||
86 | #include <libkern/OSAtomic.h> | |
87 | ||
88 | int Standard_Atomic_Increment (volatile int* theValue) | |
89 | { | |
90 | return OSAtomicIncrement32Barrier (theValue); | |
91 | } | |
92 | ||
93 | int Standard_Atomic_Decrement (volatile int* theValue) | |
94 | { | |
95 | return OSAtomicDecrement32Barrier (theValue); | |
96 | } | |
97 | ||
0304f711 | 98 | #elif defined(__ANDROID__) |
9bf6baed | 99 | |
0304f711 | 100 | // Atomic operations that were exported by the C library didn't |
101 | // provide any memory barriers, which created potential issues on | |
102 | // multi-core devices. Starting from ndk version r7b they are defined as | |
103 | // inlined calls to GCC sync builtins, which always provide a full barrier. | |
104 | // It is strongly recommended to use newer versions of ndk. | |
9bf6baed | 105 | #include <sys/atomics.h> |
0304f711 | 106 | |
107 | int Standard_Atomic_Increment (volatile int* theValue) | |
108 | { | |
9bf6baed | 109 | return __atomic_inc (theValue) + 1; // analog of __sync_fetch_and_add |
0304f711 | 110 | } |
111 | ||
112 | int Standard_Atomic_Decrement (volatile int* theValue) | |
113 | { | |
9bf6baed | 114 | return __atomic_dec (theValue) - 1; // analog of __sync_fetch_and_sub |
0304f711 | 115 | } |
116 | ||
1365140b RL |
117 | #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64)) |
118 | // use x86 / x86_64 inline assembly (compatibility with alien compilers / old GCC) | |
119 | ||
120 | inline int Standard_Atomic_Add (volatile int* theValue, int theVal) | |
121 | { | |
122 | // C equivalent: | |
123 | // *theValue += theVal; | |
124 | // return *theValue; | |
125 | ||
126 | int previous; | |
127 | __asm__ __volatile__ | |
128 | ( | |
129 | "lock xadd %0,%1" | |
130 | : "=q"(previous), "=m"(*theValue) //output | |
131 | : "0"(theVal), "m"(*theValue) //input | |
132 | : "memory" //clobbers | |
133 | ); | |
134 | return previous + theVal; | |
135 | } | |
136 | ||
137 | int Standard_Atomic_Increment (volatile int* theValue) | |
138 | { | |
139 | return Standard_Atomic_Add (theValue, 1); | |
140 | } | |
141 | ||
142 | int Standard_Atomic_Decrement (volatile int* theValue) | |
143 | { | |
144 | return Standard_Atomic_Add (theValue, -1); | |
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 | ||
1365140b RL |
162 | #endif |
163 | ||
e33e7e78 | 164 | #endif //_Standard_Atomic_HeaderFile |