OCC22577 Thread-safety/re-entrability improvements
[occt.git] / src / Standard / Standard_Atomic.hxx
index 93f80ec..4208ae2 100755 (executable)
 //! By the moment, only operations necessary for reference counter 
 //! in Standard_Transient objects are implemented.
 //! 
-//! Currently only two x86-based configurations (Windows NT with 
-//! MS VC++ compiler and Linix with GCC) are really supported.
-//! Other configurations use non-atomic C equivalent.
+//! This is preffered to use fixed size types "int32_t" / "int64_t" for
+//! correct function declarations however we leave "int" assuming it is 32bits for now.
 
-//! @fn     void Standard_Atomic_Increment (int volatile* var)
-//! @brief  Increments atomically integer variable pointed by var
+#ifndef _Standard_Atomic_HeaderFile
+#define _Standard_Atomic_HeaderFile
 
-//! @fn     int Standard_Atomic_DecrementTest (int volatile* var)
-//! @brief  Decrements atomically integer variable pointed by var;
-//!         returns 1 if result is zero, 0 otherwise
-
-//===================================================
-// Windows NT, MSVC++ compiler
-//===================================================
-#if defined(WNT)
+#include <Standard_Macro.hxx>
 
+#if (defined(_WIN32) || defined(__WIN32__))
 extern "C" {
-long _InterlockedIncrement(long volatile* lpAddend);
-long _InterlockedDecrement(long volatile* lpAddend);
+  long _InterlockedIncrement(long volatile* lpAddend);
+  long _InterlockedDecrement(long volatile* lpAddend);
 }
+#endif
 
-#pragma intrinsic (_InterlockedIncrement)
-#pragma intrinsic (_InterlockedDecrement)
-
-inline void Standard_Atomic_Increment (int volatile* var)
-{
-  _InterlockedIncrement (reinterpret_cast<long volatile*>(var));
-}
+#if defined(_MSC_VER)
+  // force intrinsic instead of WinAPI calls
+  #pragma intrinsic (_InterlockedIncrement)
+  #pragma intrinsic (_InterlockedDecrement)
+#endif
 
-inline int Standard_Atomic_DecrementTest (int volatile* var)
+//! Increments atomically integer variable pointed by theValue
+//! and returns resulting incremented value.
+static int Standard_Atomic_Increment (volatile int* theValue)
 {
-  return _InterlockedDecrement (reinterpret_cast<long volatile*>(var)) == 0;
-}
-
-//===================================================
-// Linux, GCC compiler
-// Note: Linux kernel 2.6x provides definitions for atomic operators
-//       in the header file /usr/include/asm/atomic.h,
-//       however these definitions involve specific type atomic_t
-// Note: The same code probably would work for Intel compiler
-//===================================================
+#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
+  // mordern g++ compiler (gcc4.4+)
+  // built-in functions available for appropriate CPUs (at least -march=i486 should be specified on x86 platform)
+  return __sync_add_and_fetch (theValue, 1);
+#elif (defined(_WIN32) || defined(__WIN32__))
+  // WinAPI function or MSVC intrinsic
+  return _InterlockedIncrement(reinterpret_cast<long volatile*>(theValue));
 #elif defined(LIN)
-
-inline void Standard_Atomic_Increment (int volatile* var)
-{
-  // C equivalent:
-  // ++(*var);
-
-  __asm__ __volatile__
-  (
-    "lock incl %0"
-  : "=m"(*var) // out
-  : "m" (*var) // in 
-  );
-}
-
-inline int Standard_Atomic_DecrementTest (int volatile* var)
-{
-  // C equivalent:
-  // return --(*var) == 0;
-
-  unsigned char c;
-  __asm__ __volatile__
-  (
-    "lock decl %0; sete %1"
-  : "=m"(*var), "=qm"(c) // out
-  : "m" (*var)           // in
-  : "memory"
-  );
-  return c != 0;
-}
-
-//===================================================
-// Default stub implementation, not atomic actually
-//===================================================
+  // use x86 / x86_64 inline assembly (compatibility with alien compilers / old GCC)
+  int anIncResult;
+  __asm__ __volatile__ (
+  #if defined(_OCC64)
+    "lock xaddl %%ebx, (%%rax) \n\t"
+    "incl %%ebx                \n\t"
+    : "=b" (anIncResult)
+    : "a" (theValue), "b" (1)
+    : "cc", "memory");
+  #else
+    "lock xaddl %%eax, (%%ecx) \n\t"
+    "incl %%eax                \n\t"
+    : "=a" (anIncResult)
+    : "c" (theValue), "a" (1)
+    : "memory");
+  #endif
+  return anIncResult;
 #else
-
-inline void Standard_Atomic_Increment (int volatile* var)
-{
-  ++(*var);
+  //#error "Atomic operation doesn't implemented for current platform!"
+  return ++(*theValue);
+#endif
 }
 
-inline int Standard_Atomic_DecrementTest (int volatile* var)
+//! Decrements atomically integer variable pointed by theValue
+//! and returns resulting decremented value.
+static int Standard_Atomic_Decrement (volatile int* theValue)
 {
-  return --(*var) == 0;
+#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
+  // mordern g++ compiler (gcc4.4+)
+  // built-in functions available for appropriate CPUs (at least -march=i486 should be specified on x86 platform)
+  return __sync_sub_and_fetch (theValue, 1);
+#elif (defined(_WIN32) || defined(__WIN32__))
+  // WinAPI function or MSVC intrinsic
+  return _InterlockedDecrement(reinterpret_cast<long volatile*>(theValue));
+#elif defined(LIN)
+  // use x86 / x86_64 inline assembly (compatibility with alien compilers / old GCC)
+  int aDecResult;
+  __asm__ __volatile__ (
+  #if defined(_OCC64)
+    "lock xaddl %%ebx, (%%rax) \n\t"
+    "decl %%ebx                \n\t"
+    : "=b" (aDecResult)
+    : "a" (theValue), "b" (-1)
+    : "cc", "memory");
+  #else
+    "lock xaddl %%eax, (%%ecx) \n\t"
+    "decl %%eax                \n\t"
+    : "=a" (aDecResult)
+    : "c" (theValue), "a" (-1)
+    : "memory");
+  #endif
+  return aDecResult;
+#else
+  //#error "Atomic operation doesn't implemented for current platform!"
+  return --(*theValue);
+#endif
 }
 
-#endif
+#endif //_Standard_Atomic_HeaderFile