summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKaloian Manassiev <kaloian.manassiev@mongodb.com>2015-11-19 09:54:14 -0500
committerKaloian Manassiev <kaloian.manassiev@mongodb.com>2015-11-19 09:54:14 -0500
commit3f598f1edc57ca0b863b58009e7cca9a986d4da7 (patch)
tree62517780ad0982ec80b8a6d968a72cf0474df617 /src
parent30458a9c6160b01925a8bdd768deb98ed8da8cb0 (diff)
downloadmongo-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.cpp72
-rw-r--r--src/mongo/util/concurrency/spin_lock.h86
-rw-r--r--src/mongo/util/concurrency/spin_lock_test.cpp3
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