Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:04:58

0001 // Created on: 2007-09-04
0002 // Created by: Andrey BETENEV
0003 // Copyright (c) 2007-2014 OPEN CASCADE SAS
0004 //
0005 // This file is part of Open CASCADE Technology software library.
0006 //
0007 // This library is free software; you can redistribute it and/or modify it under
0008 // the terms of the GNU Lesser General Public License version 2.1 as published
0009 // by the Free Software Foundation, with special exception defined in the file
0010 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0011 // distribution for complete text of the license and disclaimer of any warranty.
0012 //
0013 // Alternatively, this file may be used under the terms of Open CASCADE
0014 // commercial license or contractual agreement.
0015 
0016 //! @file
0017 //! Implementation of some atomic operations (elementary operations
0018 //! with data that cannot be interrupted by parallel threads in the
0019 //! multithread process) on various platforms
0020 //!
0021 //! By the moment, only operations necessary for reference counter
0022 //! in Standard_Transient objects are implemented.
0023 //!
0024 //! This is preferred to use fixed size types "int32_t" / "int64_t" for
0025 //! correct function declarations however we leave "int" assuming it is 32bits for now.
0026 
0027 #ifndef _Standard_Atomic_HeaderFile
0028 #define _Standard_Atomic_HeaderFile
0029 
0030 //! Increments atomically integer variable pointed by theValue
0031 //! and returns resulting incremented value.
0032 inline int Standard_Atomic_Increment (volatile int* theValue);
0033 
0034 //! Decrements atomically integer variable pointed by theValue
0035 //! and returns resulting decremented value.
0036 inline int Standard_Atomic_Decrement (volatile int* theValue);
0037 
0038 //! Perform an atomic compare and swap.
0039 //! That is, if the current value of *theValue is theOldValue, then write theNewValue into *theValue.
0040 //! @param theValue    pointer to variable to modify
0041 //! @param theOldValue expected value to perform modification
0042 //! @param theNewValue new value to set in case if *theValue was equal to theOldValue
0043 //! @return TRUE if theNewValue has been set to *theValue
0044 inline bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue);
0045 
0046 // Platform-dependent implementation
0047 #if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(__EMSCRIPTEN__)
0048 // gcc explicitly defines the macros __GCC_HAVE_SYNC_COMPARE_AND_SWAP_*
0049 // starting with version 4.4+, although built-in functions
0050 // are available since 4.1.x. However unless __GCC_HAVE_SYNC_COMPARE_AND_SWAP_*
0051 // are defined, linking may fail without specifying -march option when
0052 // building for 32bit architecture on 64bit (using -m32 option). To avoid
0053 // making -march mandatory, check for __GCC_HAVE_SYNC_COMPARE_AND_SWAP_* is
0054 // enforced.
0055 
0056 int Standard_Atomic_Increment (volatile int* theValue)
0057 {
0058   return __sync_add_and_fetch (theValue, 1);
0059 }
0060 
0061 int Standard_Atomic_Decrement (volatile int* theValue)
0062 {
0063   return __sync_sub_and_fetch (theValue, 1);
0064 }
0065 
0066 bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
0067 {
0068   return __sync_val_compare_and_swap (theValue, theOldValue, theNewValue) == theOldValue;
0069 }
0070 
0071 #elif defined(_WIN32)
0072 extern "C" {
0073   long _InterlockedIncrement (volatile long* lpAddend);
0074   long _InterlockedDecrement (volatile long* lpAddend);
0075   long _InterlockedCompareExchange (long volatile* Destination, long Exchange, long Comparand);
0076 }
0077 
0078 #if defined(_MSC_VER) && ! defined(__INTEL_COMPILER)
0079   // force intrinsic instead of WinAPI calls
0080   #pragma intrinsic (_InterlockedIncrement)
0081   #pragma intrinsic (_InterlockedDecrement)
0082   #pragma intrinsic (_InterlockedCompareExchange)
0083 #endif
0084 
0085 // WinAPI function or MSVC intrinsic
0086 // Note that we safely cast int* to long*, as they have same size and endian-ness
0087 
0088 int Standard_Atomic_Increment (volatile int* theValue)
0089 {
0090   return _InterlockedIncrement (reinterpret_cast<volatile long*>(theValue));
0091 }
0092 
0093 int Standard_Atomic_Decrement (volatile int* theValue)
0094 {
0095   return _InterlockedDecrement (reinterpret_cast<volatile long*>(theValue));
0096 }
0097 
0098 bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
0099 {
0100   return _InterlockedCompareExchange (reinterpret_cast<volatile long*>(theValue), theNewValue, theOldValue) == theOldValue;
0101 }
0102 
0103 #elif defined(__APPLE__)
0104 // use atomic operations provided by MacOS
0105 
0106 #include <libkern/OSAtomic.h>
0107 
0108 int Standard_Atomic_Increment (volatile int* theValue)
0109 {
0110   return OSAtomicIncrement32Barrier (theValue);
0111 }
0112 
0113 int Standard_Atomic_Decrement (volatile int* theValue)
0114 {
0115   return OSAtomicDecrement32Barrier (theValue);
0116 }
0117 
0118 bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
0119 {
0120   return OSAtomicCompareAndSwapInt (theOldValue, theNewValue, theValue);
0121 }
0122 
0123 #elif defined(__ANDROID__)
0124 
0125 // Atomic operations that were exported by the C library didn't
0126 // provide any memory barriers, which created potential issues on
0127 // multi-core devices. Starting from ndk version r7b they are defined as
0128 // inlined calls to GCC sync builtins, which always provide a full barrier.
0129 // It is strongly recommended to use newer versions of ndk.
0130 #include <sys/atomics.h>
0131 
0132 int Standard_Atomic_Increment (volatile int* theValue)
0133 {
0134   return __atomic_inc (theValue) + 1; // analog of __sync_fetch_and_add
0135 }
0136 
0137 int Standard_Atomic_Decrement (volatile int* theValue)
0138 {
0139   return __atomic_dec (theValue) - 1; // analog of __sync_fetch_and_sub
0140 }
0141 
0142 bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
0143 {
0144   return __atomic_cmpxchg (theOldValue, theNewValue, theValue) == 0;
0145 }
0146 
0147 #else
0148 
0149 #ifndef IGNORE_NO_ATOMICS
0150   #error "Atomic operation isn't implemented for current platform!"
0151 #endif
0152 int Standard_Atomic_Increment (volatile int* theValue)
0153 {
0154   return ++(*theValue);
0155 }
0156 
0157 int Standard_Atomic_Decrement (volatile int* theValue)
0158 {
0159   return --(*theValue);
0160 }
0161 
0162 bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
0163 {
0164   if (*theValue == theOldValue)
0165   {
0166     *theValue = theNewValue;
0167     return true;
0168   }
0169   return false;
0170 }
0171 
0172 #endif
0173 
0174 #endif //_Standard_Atomic_HeaderFile