X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=blobdiff_plain;f=folly%2FRWSpinLock.h;h=2f177ed001bdc71142fe4b76218ab9819892f1f4;hp=a5b6053467ab8c6f8e686c04f1ca0312fbae62e8;hb=eba5e7f2236a0950957a8a247a0e83385149d13c;hpb=fe33916f8b77db93ca0737ad9d00cd48d216c6e4 diff --git a/folly/RWSpinLock.h b/folly/RWSpinLock.h index a5b60534..2f177ed0 100644 --- a/folly/RWSpinLock.h +++ b/folly/RWSpinLock.h @@ -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. @@ -81,8 +81,7 @@ * @author Xin Liu */ -#ifndef FOLLY_RWSPINLOCK_H_ -#define FOLLY_RWSPINLOCK_H_ +#pragma once /* ======================================================================== @@ -139,29 +138,29 @@ pthread_rwlock_t Read 728698 24us 101ns 7.28ms 194us #include #include -#if defined(__GNUC__) && \ - (defined(__i386) || FOLLY_X64 || \ - defined(ARCH_K8)) -# define RW_SPINLOCK_USE_X86_INTRINSIC_ -# include +#if defined(__GNUC__) && (defined(__i386) || FOLLY_X64 || defined(ARCH_K8)) +#define RW_SPINLOCK_USE_X86_INTRINSIC_ +#include #elif defined(_MSC_VER) && defined(FOLLY_X64) -# define RW_SPINLOCK_USE_X86_INTRINSIC_ +#define RW_SPINLOCK_USE_X86_INTRINSIC_ +#elif FOLLY_AARCH64 +#define RW_SPINLOCK_USE_X86_INTRINSIC_ #else -# undef RW_SPINLOCK_USE_X86_INTRINSIC_ +#undef RW_SPINLOCK_USE_X86_INTRINSIC_ #endif // iOS doesn't define _mm_cvtsi64_si128 and friends -#if (FOLLY_SSE >= 2) && !FOLLY_MOBILE +#if (FOLLY_SSE >= 2) && !FOLLY_MOBILE && FOLLY_X64 #define RW_SPINLOCK_USE_SSE_INSTRUCTIONS_ #else #undef RW_SPINLOCK_USE_SSE_INSTRUCTIONS_ #endif +#include #include #include -#include +#include -#include #include #include @@ -193,9 +192,11 @@ class RWSpinLock { // Lockable Concept void lock() { - int count = 0; + uint_fast32_t count = 0; while (!LIKELY(try_lock())) { - if (++count > 1000) sched_yield(); + if (++count > 1000) { + std::this_thread::yield(); + } } } @@ -207,9 +208,11 @@ class RWSpinLock { // SharedLockable Concept void lock_shared() { - int count = 0; + uint_fast32_t count = 0; while (!LIKELY(try_lock_shared())) { - if (++count > 1000) sched_yield(); + if (++count > 1000) { + std::this_thread::yield(); + } } } @@ -225,9 +228,11 @@ class RWSpinLock { // UpgradeLockable Concept void lock_upgrade() { - int count = 0; + uint_fast32_t count = 0; while (!try_lock_upgrade()) { - if (++count > 1000) sched_yield(); + if (++count > 1000) { + std::this_thread::yield(); + } } } @@ -239,7 +244,9 @@ class RWSpinLock { void unlock_upgrade_and_lock() { int64_t count = 0; while (!try_unlock_upgrade_and_lock()) { - if (++count > 1000) sched_yield(); + if (++count > 1000) { + std::this_thread::yield(); + } } } @@ -308,8 +315,10 @@ class RWSpinLock { class ReadHolder { public: - explicit ReadHolder(RWSpinLock* lock = nullptr) : lock_(lock) { - if (lock_) lock_->lock_shared(); + explicit ReadHolder(RWSpinLock* lock) : lock_(lock) { + if (lock_) { + lock_->lock_shared(); + } } explicit ReadHolder(RWSpinLock& lock) : lock_(&lock) { @@ -323,12 +332,16 @@ class RWSpinLock { // down-grade explicit ReadHolder(UpgradedHolder&& upgraded) : lock_(upgraded.lock_) { upgraded.lock_ = nullptr; - if (lock_) lock_->unlock_upgrade_and_lock_shared(); + if (lock_) { + lock_->unlock_upgrade_and_lock_shared(); + } } explicit ReadHolder(WriteHolder&& writer) : lock_(writer.lock_) { writer.lock_ = nullptr; - if (lock_) lock_->unlock_and_lock_shared(); + if (lock_) { + lock_->unlock_and_lock_shared(); + } } ReadHolder& operator=(ReadHolder&& other) { @@ -340,13 +353,23 @@ class RWSpinLock { ReadHolder(const ReadHolder& other) = delete; ReadHolder& operator=(const ReadHolder& other) = delete; - ~ReadHolder() { if (lock_) lock_->unlock_shared(); } + ~ReadHolder() { + if (lock_) { + lock_->unlock_shared(); + } + } void reset(RWSpinLock* lock = nullptr) { - if (lock == lock_) return; - if (lock_) lock_->unlock_shared(); + if (lock == lock_) { + return; + } + if (lock_) { + lock_->unlock_shared(); + } lock_ = lock; - if (lock_) lock_->lock_shared(); + if (lock_) { + lock_->lock_shared(); + } } void swap(ReadHolder* other) { @@ -361,8 +384,10 @@ class RWSpinLock { class UpgradedHolder { public: - explicit UpgradedHolder(RWSpinLock* lock = nullptr) : lock_(lock) { - if (lock_) lock_->lock_upgrade(); + explicit UpgradedHolder(RWSpinLock* lock) : lock_(lock) { + if (lock_) { + lock_->lock_upgrade(); + } } explicit UpgradedHolder(RWSpinLock& lock) : lock_(&lock) { @@ -372,7 +397,9 @@ class RWSpinLock { explicit UpgradedHolder(WriteHolder&& writer) { lock_ = writer.lock_; writer.lock_ = nullptr; - if (lock_) lock_->unlock_and_lock_upgrade(); + if (lock_) { + lock_->unlock_and_lock_upgrade(); + } } UpgradedHolder(UpgradedHolder&& other) noexcept : lock_(other.lock_) { @@ -388,13 +415,23 @@ class RWSpinLock { UpgradedHolder(const UpgradedHolder& other) = delete; UpgradedHolder& operator =(const UpgradedHolder& other) = delete; - ~UpgradedHolder() { if (lock_) lock_->unlock_upgrade(); } + ~UpgradedHolder() { + if (lock_) { + lock_->unlock_upgrade(); + } + } void reset(RWSpinLock* lock = nullptr) { - if (lock == lock_) return; - if (lock_) lock_->unlock_upgrade(); + if (lock == lock_) { + return; + } + if (lock_) { + lock_->unlock_upgrade(); + } lock_ = lock; - if (lock_) lock_->lock_upgrade(); + if (lock_) { + lock_->lock_upgrade(); + } } void swap(UpgradedHolder* other) { @@ -410,8 +447,10 @@ class RWSpinLock { class WriteHolder { public: - explicit WriteHolder(RWSpinLock* lock = nullptr) : lock_(lock) { - if (lock_) lock_->lock(); + explicit WriteHolder(RWSpinLock* lock) : lock_(lock) { + if (lock_) { + lock_->lock(); + } } explicit WriteHolder(RWSpinLock& lock) : lock_(&lock) { @@ -422,7 +461,9 @@ class RWSpinLock { explicit WriteHolder(UpgradedHolder&& upgraded) { lock_ = upgraded.lock_; upgraded.lock_ = nullptr; - if (lock_) lock_->unlock_upgrade_and_lock(); + if (lock_) { + lock_->unlock_upgrade_and_lock(); + } } WriteHolder(WriteHolder&& other) noexcept : lock_(other.lock_) { @@ -438,13 +479,23 @@ class RWSpinLock { WriteHolder(const WriteHolder& other) = delete; WriteHolder& operator =(const WriteHolder& other) = delete; - ~WriteHolder () { if (lock_) lock_->unlock(); } + ~WriteHolder() { + if (lock_) { + lock_->unlock(); + } + } void reset(RWSpinLock* lock = nullptr) { - if (lock == lock_) return; - if (lock_) lock_->unlock(); + if (lock == lock_) { + return; + } + if (lock_) { + lock_->unlock(); + } lock_ = lock; - if (lock_) lock_->lock(); + if (lock_) { + lock_->lock(); + } } void swap(WriteHolder* other) { @@ -458,12 +509,6 @@ class RWSpinLock { RWSpinLock* lock_; }; - // Synchronized<> adaptors - friend void acquireRead(RWSpinLock& l) { return l.lock_shared(); } - friend void acquireReadWrite(RWSpinLock& l) { return l.lock(); } - friend void releaseRead(RWSpinLock& l) { return l.unlock_shared(); } - friend void releaseReadWrite(RWSpinLock& l) { return l.unlock(); } - private: std::atomic bits_; }; @@ -486,13 +531,14 @@ struct RWTicketIntTrait<64> { #ifdef RW_SPINLOCK_USE_SSE_INSTRUCTIONS_ static __m128i make128(const uint16_t v[4]) { - return _mm_set_epi16(0, 0, 0, 0, v[3], v[2], v[1], v[0]); + return _mm_set_epi16(0, 0, 0, 0, + short(v[3]), short(v[2]), short(v[1]), short(v[0])); } static inline __m128i fromInteger(uint64_t from) { - return _mm_cvtsi64_si128(from); + return _mm_cvtsi64_si128(int64_t(from)); } static inline uint64_t toInteger(__m128i in) { - return _mm_cvtsi128_si64(in); + return uint64_t(_mm_cvtsi128_si64(in)); } static inline uint64_t addParallel(__m128i in, __m128i kDelta) { return toInteger(_mm_add_epi16(in, kDelta)); @@ -508,24 +554,26 @@ struct RWTicketIntTrait<32> { #ifdef RW_SPINLOCK_USE_SSE_INSTRUCTIONS_ static __m128i make128(const uint8_t v[4]) { - return _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, v[3], v[2], v[1], v[0]); + return _mm_set_epi8( + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + char(v[3]), char(v[2]), char(v[1]), char(v[0])); } static inline __m128i fromInteger(uint32_t from) { - return _mm_cvtsi32_si128(from); + return _mm_cvtsi32_si128(int32_t(from)); } static inline uint32_t toInteger(__m128i in) { - return _mm_cvtsi128_si32(in); + return uint32_t(_mm_cvtsi128_si32(in)); } static inline uint32_t addParallel(__m128i in, __m128i kDelta) { return toInteger(_mm_add_epi8(in, kDelta)); } #endif }; -} // detail - +} // namespace detail -template +template class RWTicketSpinLockT { typedef detail::RWTicketIntTrait IntTraitType; typedef typename detail::RWTicketIntTrait::FullInt FullInt; @@ -545,13 +593,13 @@ class RWTicketSpinLockT { } ticket; private: // Some x64-specific utilities for atomic access to ticket. - template static T load_acquire(T* addr) { + template static T load_acquire(T* addr) { T t = *addr; // acquire barrier asm_volatile_memory(); return t; } - template + template static void store_release(T* addr, T v) { asm_volatile_memory(); *addr = v; // release barrier @@ -592,7 +640,9 @@ class RWTicketSpinLockT { bool try_lock() { RWTicket t; FullInt old = t.whole = load_acquire(&ticket.whole); - if (t.users != t.write) return false; + if (t.users != t.write) { + return false; + } ++t.users; return __sync_bool_compare_and_swap(&ticket.whole, old, t.whole); } @@ -604,16 +654,18 @@ class RWTicketSpinLockT { * turns. */ void writeLockAggressive() { - // sched_yield() is needed here to avoid a pathology if the number + // std::this_thread::yield() is needed here to avoid a pathology if the number // of threads attempting concurrent writes is >= the number of real // cores allocated to this process. This is less likely than the // corresponding situation in lock_shared(), but we still want to // avoid it - int count = 0; + uint_fast32_t count = 0; QuarterInt val = __sync_fetch_and_add(&ticket.users, 1); while (val != load_acquire(&ticket.write)) { asm_volatile_pause(); - if (UNLIKELY(++count > 1000)) sched_yield(); + if (UNLIKELY(++count > 1000)) { + std::this_thread::yield(); + } } } @@ -626,7 +678,7 @@ class RWTicketSpinLockT { // there are a lot of competing readers. The aggressive spinning // can help to avoid starving writers. // - // We don't worry about sched_yield() here because the caller + // We don't worry about std::this_thread::yield() here because the caller // has already explicitly abandoned fairness. while (!try_lock()) {} } @@ -640,9 +692,9 @@ class RWTicketSpinLockT { void unlock() { RWTicket t; t.whole = load_acquire(&ticket.whole); - FullInt old = t.whole; #ifdef RW_SPINLOCK_USE_SSE_INSTRUCTIONS_ + FullInt old = t.whole; // SSE2 can reduce the lock and unlock overhead by 10% static const QuarterInt kDeltaBuf[4] = { 1, 1, 0, 0 }; // write/read/user static const __m128i kDelta = IntTraitType::make128(kDeltaBuf); @@ -656,13 +708,15 @@ class RWTicketSpinLockT { } void lock_shared() { - // sched_yield() is important here because we can't grab the + // std::this_thread::yield() is important here because we can't grab the // shared lock if there is a pending writeLockAggressive, so we // need to let threads that already have a shared lock complete - int count = 0; + uint_fast32_t count = 0; while (!LIKELY(try_lock_shared())) { asm_volatile_pause(); - if (UNLIKELY((++count & 1023) == 0)) sched_yield(); + if (UNLIKELY((++count & 1023) == 0)) { + std::this_thread::yield(); + } } } @@ -684,7 +738,7 @@ class RWTicketSpinLockT { } void unlock_shared() { - QuarterInt val = __sync_fetch_and_add(&ticket.write, 1); + __sync_fetch_and_add(&ticket.write, 1); } class WriteHolder; @@ -695,13 +749,16 @@ class RWTicketSpinLockT { ReadHolder(ReadHolder const&) = delete; ReadHolder& operator=(ReadHolder const&) = delete; - explicit ReadHolder(RWSpinLock *lock = nullptr) : - lock_(lock) { - if (lock_) lock_->lock_shared(); + explicit ReadHolder(RWSpinLock* lock) : lock_(lock) { + if (lock_) { + lock_->lock_shared(); + } } explicit ReadHolder(RWSpinLock &lock) : lock_ (&lock) { - if (lock_) lock_->lock_shared(); + if (lock_) { + lock_->lock_shared(); + } } // atomically unlock the write-lock from writer and acquire the read-lock @@ -713,13 +770,19 @@ class RWTicketSpinLockT { } ~ReadHolder() { - if (lock_) lock_->unlock_shared(); + if (lock_) { + lock_->unlock_shared(); + } } void reset(RWSpinLock *lock = nullptr) { - if (lock_) lock_->unlock_shared(); + if (lock_) { + lock_->unlock_shared(); + } lock_ = lock; - if (lock_) lock_->lock_shared(); + if (lock_) { + lock_->lock_shared(); + } } void swap(ReadHolder *other) { @@ -735,22 +798,34 @@ class RWTicketSpinLockT { WriteHolder(WriteHolder const&) = delete; WriteHolder& operator=(WriteHolder const&) = delete; - explicit WriteHolder(RWSpinLock *lock = nullptr) : lock_(lock) { - if (lock_) lock_->lock(); + explicit WriteHolder(RWSpinLock* lock) : lock_(lock) { + if (lock_) { + lock_->lock(); + } } explicit WriteHolder(RWSpinLock &lock) : lock_ (&lock) { - if (lock_) lock_->lock(); + if (lock_) { + lock_->lock(); + } } ~WriteHolder() { - if (lock_) lock_->unlock(); + if (lock_) { + lock_->unlock(); + } } void reset(RWSpinLock *lock = nullptr) { - if (lock == lock_) return; - if (lock_) lock_->unlock(); + if (lock == lock_) { + return; + } + if (lock_) { + lock_->unlock(); + } lock_ = lock; - if (lock_) lock_->lock(); + if (lock_) { + lock_->lock(); + } } void swap(WriteHolder *other) { @@ -761,20 +836,6 @@ class RWTicketSpinLockT { friend class ReadHolder; RWSpinLock *lock_; }; - - // Synchronized<> adaptors. - friend void acquireRead(RWTicketSpinLockT& mutex) { - mutex.lock_shared(); - } - friend void acquireReadWrite(RWTicketSpinLockT& mutex) { - mutex.lock(); - } - friend void releaseRead(RWTicketSpinLockT& mutex) { - mutex.unlock_shared(); - } - friend void releaseReadWrite(RWTicketSpinLockT& mutex) { - mutex.unlock(); - } }; typedef RWTicketSpinLockT<32> RWTicketSpinLock32; @@ -782,10 +843,8 @@ typedef RWTicketSpinLockT<64> RWTicketSpinLock64; #endif // RW_SPINLOCK_USE_X86_INTRINSIC_ -} // namespace folly +} // namespace folly #ifdef RW_SPINLOCK_USE_X86_INTRINSIC_ #undef RW_SPINLOCK_USE_X86_INTRINSIC_ #endif - -#endif // FOLLY_RWSPINLOCK_H_