63c1dbf04ddcbd7e26dd424d656e2a4573201422
[occt.git] / src / Standard / Standard_Atomic.hxx
1 // Created on: 2007-09-04
2 // Created by: Andrey BETENEV
3 // Copyright (c) 2007-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
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.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 //! @file
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
20 //!
21 //! By the moment, only operations necessary for reference counter
22 //! in Standard_Transient objects are implemented.
23 //!
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.
26
27 #ifndef _Standard_Atomic_HeaderFile
28 #define _Standard_Atomic_HeaderFile
29
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 }
57
58 #elif defined(_WIN32) || defined(__WIN32__)
59 extern "C" {
60   long _InterlockedIncrement (volatile long* lpAddend);
61   long _InterlockedDecrement (volatile long* lpAddend);
62 }
63
64 #if defined(_MSC_VER)
65   // force intrinsic instead of WinAPI calls
66   #pragma intrinsic (_InterlockedIncrement)
67   #pragma intrinsic (_InterlockedDecrement)
68 #endif
69
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)
74 {
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
98 #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64))
99 // use x86 / x86_64 inline assembly (compatibility with alien compilers / old GCC)
100
101 inline int Standard_Atomic_Add (volatile int* theValue, int theVal)
102 {
103   // C equivalent:
104   // *theValue += theVal;
105   // return *theValue;
106
107   int previous;
108   __asm__ __volatile__
109   (
110     "lock xadd %0,%1"
111   : "=q"(previous), "=m"(*theValue) //output
112   : "0"(theVal), "m"(*theValue) //input
113   : "memory" //clobbers
114   );
115   return previous + theVal;
116 }
117
118 int Standard_Atomic_Increment (volatile int* theValue)
119 {
120   return Standard_Atomic_Add (theValue, 1);
121 }
122
123 int Standard_Atomic_Decrement (volatile int* theValue)
124 {
125   return Standard_Atomic_Add (theValue, -1);
126 }
127
128 #else
129
130 #ifndef IGNORE_NO_ATOMICS
131   #error "Atomic operation isn't implemented for current platform!"
132 #endif
133 int Standard_Atomic_Increment (volatile int* theValue)
134 {
135   return ++(*theValue);
136 }
137
138 int Standard_Atomic_Decrement (volatile int* theValue)
139 {
140   return --(*theValue);
141 }
142
143 #endif
144
145 #endif //_Standard_Atomic_HeaderFile