summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--storage/innobase/include/srw_lock.h9
-rw-r--r--storage/innobase/sync/srw_lock.cc42
2 files changed, 29 insertions, 22 deletions
diff --git a/storage/innobase/include/srw_lock.h b/storage/innobase/include/srw_lock.h
index fdac659d494..fa3368d5c1b 100644
--- a/storage/innobase/include/srw_lock.h
+++ b/storage/innobase/include/srw_lock.h
@@ -36,7 +36,8 @@ public:
/** Futex-based mutex */
class srw_mutex final
{
- /** The lock word, containing HOLDER and a count of waiters */
+ /** The lock word, containing HOLDER + 1 if the lock is being held,
+ plus the number of waiters */
std::atomic<uint32_t> lock;
/** Identifies that the lock is being held */
static constexpr uint32_t HOLDER= 1U << 31;
@@ -62,7 +63,7 @@ public:
bool wr_lock_try()
{
uint32_t lk= 0;
- return lock.compare_exchange_strong(lk, HOLDER,
+ return lock.compare_exchange_strong(lk, HOLDER + 1,
std::memory_order_acquire,
std::memory_order_relaxed);
}
@@ -70,8 +71,8 @@ public:
void wr_lock() { if (!wr_lock_try()) wait_and_lock(); }
void wr_unlock()
{
- const uint32_t lk= lock.fetch_and(~HOLDER, std::memory_order_release);
- if (lk != HOLDER)
+ const uint32_t lk= lock.fetch_sub(HOLDER + 1, std::memory_order_release);
+ if (lk != HOLDER + 1)
{
DBUG_ASSERT(lk & HOLDER);
wake();
diff --git a/storage/innobase/sync/srw_lock.cc b/storage/innobase/sync/srw_lock.cc
index b76194c89e3..780add3f705 100644
--- a/storage/innobase/sync/srw_lock.cc
+++ b/storage/innobase/sync/srw_lock.cc
@@ -233,33 +233,39 @@ void ssux_lock_low::wake() { SRW_FUTEX(&readers, WAKE, 1); }
void srw_mutex::wait_and_lock()
{
uint32_t lk= 1 + lock.fetch_add(1, std::memory_order_relaxed);
- for (auto spin= srv_n_spin_wait_rounds; spin; spin--)
+ for (auto spin= srv_n_spin_wait_rounds;;)
{
- lk&= ~HOLDER;
- DBUG_ASSERT(lk);
- while (!lock.compare_exchange_weak(lk, HOLDER | (lk - 1),
- std::memory_order_acquire,
- std::memory_order_relaxed))
- if (lk & HOLDER)
- goto occupied;
- return;
-occupied:
+ DBUG_ASSERT(~HOLDER & lk);
+ if (lk & HOLDER)
+ lk= lock.load(std::memory_order_relaxed);
+ else
+ {
+ lk= lock.fetch_or(HOLDER, std::memory_order_relaxed);
+ if (!(lk & HOLDER))
+ goto acquired;
+ }
ut_delay(srv_spin_wait_delay);
+ if (!--spin)
+ break;
}
- for (;;)
+ for (;; wait(lk))
{
- lk= lock.load(std::memory_order_relaxed);
- while (!(lk & HOLDER))
+ if (lk & HOLDER)
{
+ lk= lock.load(std::memory_order_relaxed);
+ if (lk & HOLDER)
+ continue;
+ }
+ lk= lock.fetch_or(HOLDER, std::memory_order_relaxed);
+ if (!(lk & HOLDER))
+ {
+acquired:
DBUG_ASSERT(lk);
- if (lock.compare_exchange_weak(lk, HOLDER | (lk - 1),
- std::memory_order_acquire,
- std::memory_order_relaxed))
- return;
+ std::atomic_thread_fence(std::memory_order_acquire);
+ return;
}
DBUG_ASSERT(lk > HOLDER);
- wait(lk);
}
}