X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FSharedMutex.h;h=571af4a7e2749342c5b1a9ea811271bc550ac6a7;hb=44ce72fdb5b5dca54f799f62c2e8c7791c2e2fcc;hp=4ccdff2a0a07162b711a67a806533bc1ee6aef52;hpb=e081efcade6da7cad61741a1d2f856bd7d686995;p=folly.git diff --git a/folly/SharedMutex.h b/folly/SharedMutex.h index 4ccdff2a..571af4a7 100644 --- a/folly/SharedMutex.h +++ b/folly/SharedMutex.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. @@ -204,11 +204,11 @@ // // If you have observed by profiling that your SharedMutex-s are getting // cache misses on deferredReaders[] due to another SharedMutex user, then -// you can use the tag type plus the RWDEFERREDLOCK_DECLARE_STATIC_STORAGE -// macro to create your own instantiation of the type. The contention -// threshold (see kNumSharedToStartDeferring) should make this unnecessary -// in all but the most extreme cases. Make sure to check that the -// increased icache and dcache footprint of the tagged result is worth it. +// you can use the tag type to create your own instantiation of the type. +// The contention threshold (see kNumSharedToStartDeferring) should make +// this unnecessary in all but the most extreme cases. Make sure to check +// that the increased icache and dcache footprint of the tagged result is +// worth it. // SharedMutex's use of thread local storage is as an optimization, so // for the case where thread local storage is not supported, define it @@ -723,6 +723,10 @@ class SharedMutexImpl { // This is the starting location for Token-less unlock_shared(). static FOLLY_SHAREDMUTEX_TLS uint32_t tls_lastTokenlessSlot; + // Last deferred reader slot used. + static FOLLY_SHAREDMUTEX_TLS uint32_t tls_lastDeferredReaderSlot; + + // Only indexes divisible by kDeferredSeparationFactor are used. // If any of those elements points to a SharedMutexImpl, then it // should be considered that there is a shared lock on that instance. @@ -761,7 +765,7 @@ class SharedMutexImpl { } uint32_t after = (state & kMayDefer) == 0 ? 0 : kPrevDefer; - if (!ReaderPriority || (state & (kMayDefer | kHasS)) == 0) { + if (!kReaderPriority || (state & (kMayDefer | kHasS)) == 0) { // Block readers immediately, either because we are in write // priority mode or because we can acquire the lock in one // step. Note that if state has kHasU, then we are doing an @@ -802,7 +806,7 @@ class SharedMutexImpl { return false; } - if (ReaderPriority && (state & kHasE) == 0) { + if (kReaderPriority && (state & kHasE) == 0) { assert((state & kBegunE) != 0); if (!state_.compare_exchange_strong(state, (state & ~kBegunE) | kHasE)) { @@ -1129,10 +1133,15 @@ class SharedMutexImpl { public: class ReadHolder { - public: ReadHolder() : lock_(nullptr) {} - explicit ReadHolder(const SharedMutexImpl* lock) : ReadHolder(*lock) {} + public: + explicit ReadHolder(const SharedMutexImpl* lock) + : lock_(const_cast(lock)) { + if (lock_) { + lock_->lock_shared(token_); + } + } explicit ReadHolder(const SharedMutexImpl& lock) : lock_(const_cast(&lock)) { @@ -1186,10 +1195,14 @@ class SharedMutexImpl { }; class UpgradeHolder { - public: UpgradeHolder() : lock_(nullptr) {} - explicit UpgradeHolder(SharedMutexImpl* lock) : UpgradeHolder(*lock) {} + public: + explicit UpgradeHolder(SharedMutexImpl* lock) : lock_(lock) { + if (lock_) { + lock_->lock_upgrade(); + } + } explicit UpgradeHolder(SharedMutexImpl& lock) : lock_(&lock) { lock_->lock_upgrade(); @@ -1232,10 +1245,14 @@ class SharedMutexImpl { }; class WriteHolder { - public: WriteHolder() : lock_(nullptr) {} - explicit WriteHolder(SharedMutexImpl* lock) : WriteHolder(*lock) {} + public: + explicit WriteHolder(SharedMutexImpl* lock) : lock_(lock) { + if (lock_) { + lock_->lock(); + } + } explicit WriteHolder(SharedMutexImpl& lock) : lock_(&lock) { lock_->lock(); @@ -1343,6 +1360,15 @@ FOLLY_SHAREDMUTEX_TLS uint32_t SharedMutexImpl:: tls_lastTokenlessSlot = 0; +template < + bool ReaderPriority, + typename Tag_, + template class Atom, + bool BlockImmediately> +FOLLY_SHAREDMUTEX_TLS uint32_t + SharedMutexImpl:: + tls_lastDeferredReaderSlot = 0; + template < bool ReaderPriority, typename Tag_, @@ -1377,7 +1403,7 @@ bool SharedMutexImpl:: return false; } - uint32_t slot; + uint32_t slot = tls_lastDeferredReaderSlot; uintptr_t slotValue = 1; // any non-zero value will do bool canAlreadyDefer = (state & kMayDefer) != 0; @@ -1385,21 +1411,26 @@ bool SharedMutexImpl:: (state & kHasS) >= (kNumSharedToStartDeferring - 1) * kIncrHasS; bool drainInProgress = ReaderPriority && (state & kBegunE) != 0; if (canAlreadyDefer || (aboveDeferThreshold && !drainInProgress)) { - // starting point for our empty-slot search, can change after - // calling waitForZeroBits - uint32_t bestSlot = - (uint32_t)folly::detail::AccessSpreader::current( - kMaxDeferredReaders); - - // deferred readers are already enabled, or it is time to - // enable them if we can find a slot - for (uint32_t i = 0; i < kDeferredSearchDistance; ++i) { - slot = bestSlot ^ i; - assert(slot < kMaxDeferredReaders); - slotValue = deferredReader(slot)->load(std::memory_order_relaxed); - if (slotValue == 0) { - // found empty slot - break; + /* Try using the most recent slot first. */ + slotValue = deferredReader(slot)->load(std::memory_order_relaxed); + if (slotValue != 0) { + // starting point for our empty-slot search, can change after + // calling waitForZeroBits + uint32_t bestSlot = + (uint32_t)folly::detail::AccessSpreader::current( + kMaxDeferredReaders); + + // deferred readers are already enabled, or it is time to + // enable them if we can find a slot + for (uint32_t i = 0; i < kDeferredSearchDistance; ++i) { + slot = bestSlot ^ i; + assert(slot < kMaxDeferredReaders); + slotValue = deferredReader(slot)->load(std::memory_order_relaxed); + if (slotValue == 0) { + // found empty slot + tls_lastDeferredReaderSlot = slot; + break; + } } } }