0026937: Eliminate NO_CXX_EXCEPTION macro support
[occt.git] / src / Standard / Standard_Atomic.hxx
CommitLineData
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.
32inline int Standard_Atomic_Increment (volatile int* theValue);
33
34//! Decrements atomically integer variable pointed by theValue
35//! and returns resulting decremented value.
36inline 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
48int Standard_Atomic_Increment (volatile int* theValue)
49{
50 return __sync_add_and_fetch (theValue, 1);
51}
52
53int Standard_Atomic_Decrement (volatile int* theValue)
54{
55 return __sync_sub_and_fetch (theValue, 1);
56}
7fd59977 57
9bf6baed 58#elif defined(_WIN32)
7fd59977 59extern "C" {
1365140b
RL
60 long _InterlockedIncrement (volatile long* lpAddend);
61 long _InterlockedDecrement (volatile long* lpAddend);
7fd59977 62}
63
e33e7e78
RK
64#if defined(_MSC_VER)
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
73int Standard_Atomic_Increment (volatile int* theValue)
7fd59977 74{
1365140b
RL
75 return _InterlockedIncrement (reinterpret_cast<volatile long*>(theValue));
76}
77
78int 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
88int Standard_Atomic_Increment (volatile int* theValue)
89{
90 return OSAtomicIncrement32Barrier (theValue);
91}
92
93int 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
107int Standard_Atomic_Increment (volatile int* theValue)
108{
9bf6baed 109 return __atomic_inc (theValue) + 1; // analog of __sync_fetch_and_add
0304f711 110}
111
112int 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
120inline 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
137int Standard_Atomic_Increment (volatile int* theValue)
138{
139 return Standard_Atomic_Add (theValue, 1);
140}
141
142int 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
152int Standard_Atomic_Increment (volatile int* theValue)
153{
154 return ++(*theValue);
7fd59977 155}
156
1365140b 157int 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