X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=blobdiff_plain;f=folly%2FPicoSpinLock.h;h=7d4fe2c1fd4cabc46204900d57f6b69bdc917c71;hp=19472b31fd0d86e913114f03e71fa05777e011f4;hb=2e5089d514ad890d04d9243c14db91a7c4814583;hpb=ed14d607d70bc342818ea2f6875316654dbc1002 diff --git a/folly/PicoSpinLock.h b/folly/PicoSpinLock.h index 19472b31..7d4fe2c1 100644 --- a/folly/PicoSpinLock.h +++ b/folly/PicoSpinLock.h @@ -1,5 +1,5 @@ /* - * Copyright 2016 Facebook, Inc. + * Copyright 2015-present Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ */ #pragma once +#define FOLLY_PICO_SPIN_LOCK_H_ /* * @author Keith Adams @@ -38,19 +39,19 @@ */ #include +#include #include -#include #include -#include #include -#include +#include #include -#include + #include +#include -#if !FOLLY_X64 && !FOLLY_A64 && !FOLLY_PPC64 -# error "PicoSpinLock.h is currently x64, aarch64 and ppc64 only." +#if !FOLLY_X64 && !FOLLY_AARCH64 && !FOLLY_PPC64 +#error "PicoSpinLock.h is currently x64, aarch64 and ppc64 only." #endif namespace folly { @@ -68,7 +69,7 @@ namespace folly { * have a real constructor because we want this to be a POD type so we * can put it into packed structs. */ -template +template struct PicoSpinLock { // Internally we deal with the unsigned version of the type. typedef typename std::make_unsigned::type UIntType; @@ -81,7 +82,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 @@ -93,7 +94,8 @@ struct PicoSpinLock { */ void init(IntType initialValue = 0) { CHECK(!(initialValue & kLockBitMask_)); - lock_ = initialValue; + reinterpret_cast*>(&lock_)->store( + UIntType(initialValue), std::memory_order_release); } /* @@ -106,7 +108,10 @@ struct PicoSpinLock { * as you normally get.) */ IntType getData() const { - return static_cast(lock_ & ~kLockBitMask_); + auto res = reinterpret_cast*>(&lock_)->load( + std::memory_order_relaxed) & + ~kLockBitMask_; + return res; } /* @@ -117,7 +122,10 @@ struct PicoSpinLock { */ void setData(IntType w) { CHECK(!(w & kLockBitMask_)); - lock_ = (lock_ & kLockBitMask_) | w; + auto l = reinterpret_cast*>(&lock_); + l->store( + (l->load(std::memory_order_relaxed) & kLockBitMask_) | w, + std::memory_order_relaxed); } /* @@ -127,7 +135,28 @@ struct PicoSpinLock { bool try_lock() const { bool ret = false; -#if FOLLY_X64 +#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*>(&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_, (short)kLockBitMask_) & kLockBitMask_; + break; + case 4: + ret = _interlockedbittestandset((volatile long*)&lock_, Bit); + break; + case 8: + ret = _interlockedbittestandset64((volatile long long*)&lock_, Bit); + break; + } +#elif FOLLY_X64 #define FB_DOBTS(size) \ asm volatile("lock; bts" #size " %1, (%2); setnc %0" \ : "=r" (ret) \ @@ -142,8 +171,11 @@ struct PicoSpinLock { } #undef FB_DOBTS -#elif FOLLY_A64 - ret = __atomic_fetch_or(&lock_, 1 << Bit, __ATOMIC_SEQ_CST); +#elif FOLLY_AARCH64 + using SIntType = typename std::make_signed::type; + auto const lock = reinterpret_cast(&lock_); + auto const mask = static_cast(kLockBitMask_); + return !(mask & __atomic_fetch_or(lock, mask, __ATOMIC_ACQUIRE)); #elif FOLLY_PPC64 #define FB_DOBTS(size) \ asm volatile("\teieio\n" \ @@ -192,7 +224,20 @@ struct PicoSpinLock { * integer. */ void unlock() const { -#if FOLLY_X64 +#ifdef _MSC_VER + switch (sizeof(IntType)) { + case 2: + // There is no _interlockedbittestandreset16 for some reason :( + _InterlockedAnd16((volatile short*)&lock_, (short)~kLockBitMask_); + break; + case 4: + _interlockedbittestandreset((volatile long*)&lock_, Bit); + break; + case 8: + _interlockedbittestandreset64((volatile long long*)&lock_, Bit); + break; + } +#elif FOLLY_X64 #define FB_DOBTR(size) \ asm volatile("lock; btr" #size " %0, (%1)" \ : \ @@ -210,8 +255,11 @@ struct PicoSpinLock { } #undef FB_DOBTR -#elif FOLLY_A64 - __atomic_fetch_and(&lock_, ~(1 << Bit), __ATOMIC_SEQ_CST); +#elif FOLLY_AARCH64 + using SIntType = typename std::make_signed::type; + auto const lock = reinterpret_cast(&lock_); + auto const mask = static_cast(kLockBitMask_); + __atomic_fetch_and(lock, ~mask, __ATOMIC_RELEASE); #elif FOLLY_PPC64 #define FB_DOBTR(size) \ asm volatile("\teieio\n" \ @@ -240,4 +288,4 @@ struct PicoSpinLock { } }; -} +} // namespace folly