diff options
author | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2015-11-19 09:54:14 -0500 |
---|---|---|
committer | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2015-11-19 09:54:14 -0500 |
commit | 3f598f1edc57ca0b863b58009e7cca9a986d4da7 (patch) | |
tree | 62517780ad0982ec80b8a6d968a72cf0474df617 /src | |
parent | 30458a9c6160b01925a8bdd768deb98ed8da8cb0 (diff) | |
download | mongo-3f598f1edc57ca0b863b58009e7cca9a986d4da7.tar.gz |
SERVER-21542 Optimize spinlock on non-windows systems
This reverts commit 30458a9c6160b01925a8bdd768deb98ed8da8cb0.
Diffstat (limited to 'src')
-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 cb66ad2abc5..7f01b9d491b 100644 --- a/src/mongo/util/concurrency/spin_lock.cpp +++ b/src/mongo/util/concurrency/spin_lock.cpp @@ -27,45 +27,20 @@ * 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 <sched.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 @@ -75,15 +50,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; sched_yield(); } @@ -92,42 +67,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 |