Fixed documentation in folly/Random.h
[folly.git] / folly / PicoSpinLock.h
index 9f52a7a9a86e5af27b9c94a7730a65f6afa8ed1c..485050f136c9ee895af8e28a3d2111583a49b9da 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include <cstdlib>
 #include <folly/Portability.h>
 #include <mutex>
-#include <pthread.h>
 #include <type_traits>
 
-#include <glog/logging.h>
 #include <folly/detail/Sleeper.h>
+#include <glog/logging.h>
 
 #if !FOLLY_X64 && !FOLLY_A64 && !FOLLY_PPC64
 # error "PicoSpinLock.h is currently x64, aarch64 and ppc64 only."
@@ -82,7 +81,7 @@ struct PicoSpinLock {
 
  public:
   static const UIntType kLockBitMask_ = UIntType(1) << Bit;
-  UIntType lock_;
+  mutable UIntType lock_;
 
   /*
    * You must call this function before using this class, if you
@@ -94,7 +93,8 @@ struct PicoSpinLock {
    */
   void init(IntType initialValue = 0) {
     CHECK(!(initialValue & kLockBitMask_));
-    lock_ = initialValue;
+    reinterpret_cast<std::atomic<UIntType>*>(&lock_)->store(
+        UIntType(initialValue), std::memory_order_release);
   }
 
   /*
@@ -107,7 +107,10 @@ struct PicoSpinLock {
    * as you normally get.)
    */
   IntType getData() const {
-    return static_cast<IntType>(lock_ & ~kLockBitMask_);
+    auto res = reinterpret_cast<std::atomic<UIntType>*>(&lock_)->load(
+                   std::memory_order_relaxed) &
+        ~kLockBitMask_;
+    return res;
   }
 
   /*
@@ -118,7 +121,10 @@ struct PicoSpinLock {
    */
   void setData(IntType w) {
     CHECK(!(w & kLockBitMask_));
-    lock_ = (lock_ & kLockBitMask_) | w;
+    auto l = reinterpret_cast<std::atomic<UIntType>*>(&lock_);
+    l->store(
+        (l->load(std::memory_order_relaxed) & kLockBitMask_) | w,
+        std::memory_order_relaxed);
   }
 
   /*
@@ -128,11 +134,19 @@ struct PicoSpinLock {
   bool try_lock() const {
     bool ret = false;
 
-#ifdef _MSC_VER
+#if defined(FOLLY_SANITIZE_THREAD)
+    // TODO: Might be able to fully move to std::atomic when gcc emits lock btr:
+    // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49244
+    ret =
+        !(reinterpret_cast<std::atomic<UIntType>*>(&lock_)->fetch_or(
+              kLockBitMask_, std::memory_order_acquire) &
+          kLockBitMask_);
+#elif _MSC_VER
     switch (sizeof(IntType)) {
       case 2:
         // There is no _interlockedbittestandset16 for some reason :(
-        ret = _InterlockedOr16((volatile short*)&lock, 1 << Bit) & (1 << Bit);
+        ret = _InterlockedOr16(
+            (volatile short*)&lock_, (short)kLockBitMask_) & kLockBitMask_;
         break;
       case 4:
         ret = _interlockedbittestandset((volatile long*)&lock_, Bit);
@@ -157,7 +171,9 @@ struct PicoSpinLock {
 
 #undef FB_DOBTS
 #elif FOLLY_A64
-    ret = __atomic_fetch_or(&lock_, 1 << Bit, __ATOMIC_SEQ_CST);
+    ret =
+        !(__atomic_fetch_or(&lock_, kLockBitMask_, __ATOMIC_SEQ_CST) &
+          kLockBitMask_);
 #elif FOLLY_PPC64
 #define FB_DOBTS(size)                                 \
     asm volatile("\teieio\n"                           \
@@ -210,7 +226,7 @@ struct PicoSpinLock {
     switch (sizeof(IntType)) {
       case 2:
         // There is no _interlockedbittestandreset16 for some reason :(
-        _InterlockedAnd16((volatile short*)&lock, ~(1 << Bit));
+        _InterlockedAnd16((volatile short*)&lock_, (short)~kLockBitMask_);
         break;
       case 4:
         _interlockedbittestandreset((volatile long*)&lock_, Bit);
@@ -238,7 +254,7 @@ struct PicoSpinLock {
 
 #undef FB_DOBTR
 #elif FOLLY_A64
-    __atomic_fetch_and(&lock_, ~(1 << Bit), __ATOMIC_SEQ_CST);
+    __atomic_fetch_and(&lock_, ~kLockBitMask_, __ATOMIC_SEQ_CST);
 #elif FOLLY_PPC64
 #define FB_DOBTR(size)                                 \
     asm volatile("\teieio\n"                           \