0029935: Foundation Classes - introduce OSD_ThreadPool class defining a thread pool
[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
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
44inline 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
56int Standard_Atomic_Increment (volatile int* theValue)
57{
58 return __sync_add_and_fetch (theValue, 1);
59}
60
61int Standard_Atomic_Decrement (volatile int* theValue)
62{
63 return __sync_sub_and_fetch (theValue, 1);
64}
7fd59977 65
6f498847 66bool 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 72extern "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
88int Standard_Atomic_Increment (volatile int* theValue)
7fd59977 89{
1365140b
RL
90 return _InterlockedIncrement (reinterpret_cast<volatile long*>(theValue));
91}
92
93int Standard_Atomic_Decrement (volatile int* theValue)
94{
95 return _InterlockedDecrement (reinterpret_cast<volatile long*>(theValue));
96}
97
6f498847 98bool 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
108int Standard_Atomic_Increment (volatile int* theValue)
109{
110 return OSAtomicIncrement32Barrier (theValue);
111}
112
113int Standard_Atomic_Decrement (volatile int* theValue)
114{
115 return OSAtomicDecrement32Barrier (theValue);
116}
117
6f498847 118bool 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
132int Standard_Atomic_Increment (volatile int* theValue)
133{
9bf6baed 134 return __atomic_inc (theValue) + 1; // analog of __sync_fetch_and_add
0304f711 135}
136
137int Standard_Atomic_Decrement (volatile int* theValue)
138{
9bf6baed 139 return __atomic_dec (theValue) - 1; // analog of __sync_fetch_and_sub
0304f711 140}
141
6f498847 142bool 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
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
6f498847 162bool 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