diff options
Diffstat (limited to 'storage/innobase/include/rw_lock.h')
-rw-r--r-- | storage/innobase/include/rw_lock.h | 23 |
1 files changed, 20 insertions, 3 deletions
diff --git a/storage/innobase/include/rw_lock.h b/storage/innobase/include/rw_lock.h index cd176f0b35b..ba380b77261 100644 --- a/storage/innobase/include/rw_lock.h +++ b/storage/innobase/include/rw_lock.h @@ -50,9 +50,22 @@ protected: static constexpr uint32_t UPDATER= 1U << 29; #endif /* SUX_LOCK_GENERIC */ + /** Start waiting for an exclusive lock. */ + void write_lock_wait_start() + { +#if defined __GNUC__ && (defined __i386__ || defined __x86_64__) + static_assert(WRITER_WAITING == 1U << 30, "compatibility"); + __asm__ __volatile__("lock btsl $30, %0" : "+m" (lock)); +#elif defined _MSC_VER && (defined _M_IX86 || defined _M_IX64) + static_assert(WRITER_WAITING == 1U << 30, "compatibility"); + _interlockedbittestandset(reinterpret_cast<volatile long*>(&lock), 30); +#else + lock.fetch_or(WRITER_WAITING, std::memory_order_relaxed); +#endif + } /** Start waiting for an exclusive lock. @return current value of the lock word */ - uint32_t write_lock_wait_start() + uint32_t write_lock_wait_start_read() { return lock.fetch_or(WRITER_WAITING, std::memory_order_relaxed); } /** Wait for an exclusive lock. @param l the value of the lock word @@ -183,8 +196,12 @@ public: /** Release an exclusive lock */ void write_unlock() { - IF_DBUG_ASSERT(auto l=,) - lock.fetch_and(~WRITER, std::memory_order_release); + /* Below, we use fetch_sub(WRITER) instead of fetch_and(~WRITER). + The reason is that on IA-32 and AMD64 it translates into the 80486 + instruction LOCK XADD, while fetch_and() translates into a loop + around LOCK CMPXCHG. For other ISA either form should be fine. */ + static_assert(WRITER == 1U << 31, "compatibility"); + IF_DBUG_ASSERT(auto l=,) lock.fetch_sub(WRITER, std::memory_order_release); /* the write lock must have existed */ #ifdef SUX_LOCK_GENERIC DBUG_ASSERT((l & (WRITER | UPDATER)) == WRITER); |