diff options
author | Mathias Stearn <mathias@10gen.com> | 2015-10-12 19:19:17 -0400 |
---|---|---|
committer | Mathias Stearn <mathias@10gen.com> | 2015-11-18 18:18:00 -0500 |
commit | 18600ed909f739ab1bc3032c2a230aeac1abe1c2 (patch) | |
tree | ba24acdecf08c3b8581c41ba4c048b2948de515e /src/mongo | |
parent | 23136883e394b73cbc26f873cd0276779adef3df (diff) | |
download | mongo-18600ed909f739ab1bc3032c2a230aeac1abe1c2.tar.gz |
SERVER-21542 Optimize spinlock on non-windows systems
Now uses std::atomic_flag rather than pthread_spinlock.
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/util/concurrency/spin_lock.cpp | 72 | ||||
-rw-r--r-- | src/mongo/util/concurrency/spin_lock.h | 86 | ||||
-rw-r--r-- | src/mongo/util/concurrency/spin_lock_test.cpp | 3 |
3 files changed, 45 insertions, 116 deletions
diff --git a/src/mongo/util/concurrency/spin_lock.cpp b/src/mongo/util/concurrency/spin_lock.cpp index 601dcd0f53b..7fbb33f02bb 100644 --- a/src/mongo/util/concurrency/spin_lock.cpp +++ b/src/mongo/util/concurrency/spin_lock.cpp @@ -27,44 +27,19 @@ * then also delete it in the license file. */ +#if !defined(_WIN32) + #include "mongo/platform/basic.h" -#undef MONGO_PCH_WHITELISTED // todo eliminate this include #include "mongo/util/concurrency/spin_lock.h" #include <time.h> -#include "mongo/bson/inline_decls.h" namespace mongo { -SpinLock::~SpinLock() { -#if defined(_WIN32) - DeleteCriticalSection(&_cs); -#elif defined(__USE_XOPEN2K) - pthread_spin_destroy(&_lock); -#endif -} - -SpinLock::SpinLock() -#if defined(_WIN32) -{ - InitializeCriticalSectionAndSpinCount(&_cs, 4000); -} -#elif defined(__USE_XOPEN2K) -{ - pthread_spin_init(&_lock, 0); -} -#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) - : _locked(false) { -} -#else - : _mutex("SpinLock") { -} -#endif -#if defined(__USE_XOPEN2K) -NOINLINE_DECL void SpinLock::_lk() { +void SpinLock::_lockSlowPath() { /** * this is designed to perform close to the default spin lock * the reason for the mild insanity is to prevent horrible performance @@ -74,15 +49,15 @@ NOINLINE_DECL void SpinLock::_lk() { */ for (int i = 0; i < 1000; i++) { - if (pthread_spin_trylock(&_lock) == 0) + if (_tryLock()) return; #if defined(__i386__) || defined(__x86_64__) - asm volatile("pause"); // maybe trylock does this; just in case. + asm volatile("pause"); #endif } for (int i = 0; i < 1000; i++) { - if (pthread_spin_trylock(&_lock) == 0) + if (_tryLock()) return; pthread_yield(); } @@ -91,42 +66,11 @@ NOINLINE_DECL void SpinLock::_lk() { t.tv_sec = 0; t.tv_nsec = 5000000; - while (pthread_spin_trylock(&_lock) != 0) { + while (!_tryLock()) { nanosleep(&t, NULL); } } -#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) -void SpinLock::lock() { - // fast path - if (!_locked && !__sync_lock_test_and_set(&_locked, true)) { - return; - } - - // wait for lock - int wait = 1000; - while ((wait-- > 0) && (_locked)) { -#if defined(__i386__) || defined(__x86_64__) - asm volatile("pause"); -#endif - } - // if failed to grab lock, sleep - struct timespec t; - t.tv_sec = 0; - t.tv_nsec = 5000000; - while (__sync_lock_test_and_set(&_locked, true)) { - nanosleep(&t, NULL); - } -} -#endif +} // namespace mongo -bool SpinLock::isfast() { -#if defined(_WIN32) || defined(__USE_XOPEN2K) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) - return true; -#else - return false; #endif -} - - -} // namespace mongo diff --git a/src/mongo/util/concurrency/spin_lock.h b/src/mongo/util/concurrency/spin_lock.h index e56458d6cf8..9e4b707f160 100644 --- a/src/mongo/util/concurrency/spin_lock.h +++ b/src/mongo/util/concurrency/spin_lock.h @@ -32,84 +32,72 @@ #ifdef _WIN32 #include "mongo/platform/windows_basic.h" +#else +#include <atomic> #endif -#include "mutex.h" +#include "mongo/base/disallow_copying.h" +#include "mongo/platform/compiler.h" +#include "mongo/stdx/mutex.h" namespace mongo { -/** - * The spinlock currently requires late GCC support routines to be efficient. - * Other platforms default to a mutex implemenation. - */ +#if defined(_WIN32) class SpinLock { MONGO_DISALLOW_COPYING(SpinLock); public: - SpinLock(); - ~SpinLock(); - - static bool isfast(); // true if a real spinlock on this platform + SpinLock() { + InitializeCriticalSectionAndSpinCount(&_cs, 4000); + } -private: -#if defined(_WIN32) - CRITICAL_SECTION _cs; + ~SpinLock() { + DeleteCriticalSection(&_cs); + } -public: void lock() { EnterCriticalSection(&_cs); } + void unlock() { LeaveCriticalSection(&_cs); } -#elif defined(__USE_XOPEN2K) - pthread_spinlock_t _lock; - void _lk(); -public: - void unlock() { - pthread_spin_unlock(&_lock); - } - void lock() { - if (MONGO_likely(pthread_spin_trylock(&_lock) == 0)) - return; - _lk(); - } -#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) - volatile bool _locked; +private: + CRITICAL_SECTION _cs; +}; -public: - void unlock() { - __sync_lock_release(&_locked); - } - void lock(); #else - // default to a mutex if not implemented - SimpleMutex _mutex; + +class SpinLock { + MONGO_DISALLOW_COPYING(SpinLock); public: + SpinLock() = default; + void unlock() { - _mutex.unlock(); + _locked.clear(std::memory_order_release); } + void lock() { - _mutex.lock(); + if (MONGO_likely(_tryLock())) + return; + _lockSlowPath(); } -#endif -}; - -class scoped_spinlock { - MONGO_DISALLOW_COPYING(scoped_spinlock); -public: - scoped_spinlock(SpinLock& l) : _l(l) { - _l.lock(); - } - ~scoped_spinlock() { - _l.unlock(); +private: + bool _tryLock() { + bool wasLocked = _locked.test_and_set(std::memory_order_acquire); + return !wasLocked; } -private: - SpinLock& _l; + void _lockSlowPath(); + + // Initializes to the cleared state. + std::atomic_flag _locked = ATOMIC_FLAG_INIT; // NOLINT }; +#endif + +using scoped_spinlock = stdx::lock_guard<SpinLock>; } // namespace mongo diff --git a/src/mongo/util/concurrency/spin_lock_test.cpp b/src/mongo/util/concurrency/spin_lock_test.cpp index 8a2e1f47cec..27bd9e83681 100644 --- a/src/mongo/util/concurrency/spin_lock_test.cpp +++ b/src/mongo/util/concurrency/spin_lock_test.cpp @@ -106,9 +106,6 @@ TEST(Concurrency, ConcurrentIncs) { mongo::unittest::log() << "spinlock ConcurrentIncs time: " << ms << std::endl; ASSERT_EQUALS(counter, threads * incs); -#if defined(__linux__) - ASSERT(SpinLock::isfast()); -#endif } } // namespace |