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 #if defined(__ANDROID__)
31 #include <sys/atomics.h>
34 //! Increments atomically integer variable pointed by theValue
35 //! and returns resulting incremented value.
36 inline int Standard_Atomic_Increment (volatile int* theValue);
38 //! Decrements atomically integer variable pointed by theValue
39 //! and returns resulting decremented value.
40 inline int Standard_Atomic_Decrement (volatile int* theValue);
42 // Platform-dependent implementation
43 #if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
44 // gcc explicitly defines the macros __GCC_HAVE_SYNC_COMPARE_AND_SWAP_*
45 // starting with version 4.4+, although built-in functions
46 // are available since 4.1.x. However unless __GCC_HAVE_SYNC_COMPARE_AND_SWAP_*
47 // are defined, linking may fail without specifying -march option when
48 // building for 32bit architecture on 64bit (using -m32 option). To avoid
49 // making -march mandatory, check for __GCC_HAVE_SYNC_COMPARE_AND_SWAP_* is
52 int Standard_Atomic_Increment (volatile int* theValue)
54 return __sync_add_and_fetch (theValue, 1);
57 int Standard_Atomic_Decrement (volatile int* theValue)
59 return __sync_sub_and_fetch (theValue, 1);
62 #elif defined(_WIN32) || defined(__WIN32__)
64 long _InterlockedIncrement (volatile long* lpAddend);
65 long _InterlockedDecrement (volatile long* lpAddend);
69 // force intrinsic instead of WinAPI calls
70 #pragma intrinsic (_InterlockedIncrement)
71 #pragma intrinsic (_InterlockedDecrement)
74 // WinAPI function or MSVC intrinsic
75 // Note that we safely cast int* to long*, as they have same size and endian-ness
77 int Standard_Atomic_Increment (volatile int* theValue)
79 return _InterlockedIncrement (reinterpret_cast<volatile long*>(theValue));
82 int Standard_Atomic_Decrement (volatile int* theValue)
84 return _InterlockedDecrement (reinterpret_cast<volatile long*>(theValue));
87 #elif defined(__APPLE__)
88 // use atomic operations provided by MacOS
90 #include <libkern/OSAtomic.h>
92 int Standard_Atomic_Increment (volatile int* theValue)
94 return OSAtomicIncrement32Barrier (theValue);
97 int Standard_Atomic_Decrement (volatile int* theValue)
99 return OSAtomicDecrement32Barrier (theValue);
102 #elif defined(__ANDROID__)
103 // Atomic operations that were exported by the C library didn't
104 // provide any memory barriers, which created potential issues on
105 // multi-core devices. Starting from ndk version r7b they are defined as
106 // inlined calls to GCC sync builtins, which always provide a full barrier.
107 // It is strongly recommended to use newer versions of ndk.
109 int Standard_Atomic_Increment (volatile int* theValue)
111 return __atomic_inc (theValue);
114 int Standard_Atomic_Decrement (volatile int* theValue)
116 return __atomic_dec (theValue);
119 #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64))
120 // use x86 / x86_64 inline assembly (compatibility with alien compilers / old GCC)
122 inline int Standard_Atomic_Add (volatile int* theValue, int theVal)
125 // *theValue += theVal;
132 : "=q"(previous), "=m"(*theValue) //output
133 : "0"(theVal), "m"(*theValue) //input
134 : "memory" //clobbers
136 return previous + theVal;
139 int Standard_Atomic_Increment (volatile int* theValue)
141 return Standard_Atomic_Add (theValue, 1);
144 int Standard_Atomic_Decrement (volatile int* theValue)
146 return Standard_Atomic_Add (theValue, -1);
151 #ifndef IGNORE_NO_ATOMICS
152 #error "Atomic operation isn't implemented for current platform!"
154 int Standard_Atomic_Increment (volatile int* theValue)
156 return ++(*theValue);
159 int Standard_Atomic_Decrement (volatile int* theValue)
161 return --(*theValue);
166 #endif //_Standard_Atomic_HeaderFile