summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorMathias Stearn <mathias@10gen.com>2015-10-12 19:19:17 -0400
committerMathias Stearn <mathias@10gen.com>2015-11-18 18:18:00 -0500
commit18600ed909f739ab1bc3032c2a230aeac1abe1c2 (patch)
treeba24acdecf08c3b8581c41ba4c048b2948de515e /src/mongo
parent23136883e394b73cbc26f873cd0276779adef3df (diff)
downloadmongo-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.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 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