summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2021-09-29 10:15:07 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2021-09-29 10:15:07 +0300
commit309209c51c211d0733a6c7a67fb70a523a1706f7 (patch)
treefd473cb070c019f43628b1ca78e02cb0d5794a61
parent27738bd774a5435026602ef94a3abc492f1f72e6 (diff)
downloadmariadb-git-bb-10.6-MDEV-26467.tar.gz
MDEV-26467: Use LOCK BTS also with the Microsoft compilerbb-10.6-MDEV-26467
Microsoft does not define inline assembler syntax for AMD64, but it defines the intrinsic function _interlockedbittestandset() that we can use. ssux_lock_impl<bool>::rd_wait(): Remove a call to yield, because writer.wr_lock() will take care of context switches between loop iterations. This addresses suggestions by Vladislav Vaintroub.
-rw-r--r--storage/innobase/sync/srw_lock.cc96
1 files changed, 47 insertions, 49 deletions
diff --git a/storage/innobase/sync/srw_lock.cc b/storage/innobase/sync/srw_lock.cc
index f38847f852b..7d26dd2b590 100644
--- a/storage/innobase/sync/srw_lock.cc
+++ b/storage/innobase/sync/srw_lock.cc
@@ -295,6 +295,35 @@ template void ssux_lock_impl<false>::wake();
template void srw_mutex_impl<true>::wake();
template void ssux_lock_impl<true>::wake();
+/*
+
+Unfortunately, compilers targeting IA-32 or AMD64 currently cannot
+translate the following single-bit operations into Intel 80386 instructions:
+
+ m.fetch_or(1<<b) & 1<<b LOCK BTS b, m
+ m.fetch_and(~(1<<b)) & 1<<b LOCK BTR b, m
+ m.fetch_xor(1<<b) & 1<<b LOCK BTC b, m
+
+Hence, we will manually translate fetch_or() using GCC-style inline
+assembler code or a Microsoft intrinsic function.
+
+*/
+#if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
+# define IF_FETCH_OR_GOTO(mem, bit, label) \
+ __asm__ goto("lock btsl $" #bit ", %0\n\t" \
+ "jc %l1" : : "m" (mem) : "cc", "memory" : label);
+# define IF_NOT_FETCH_OR_GOTO(mem, bit, label) \
+ __asm__ goto("lock btsl $" #bit ", %0\n\t" \
+ "jnc %l1" : : "m" (mem) : "cc", "memory" : label);
+#elif defined _MSC_VER && (defined _M_IX86 || defined _M_IX64)
+# define IF_FETCH_OR_GOTO(mem, bit, label) \
+ if (_interlockedbittestandset(reinterpret_cast<volatile long*>(&mem), bit)) \
+ goto label;
+# define IF_NOT_FETCH_OR_GOTO(mem, bit, label) \
+ if (!_interlockedbittestandset(reinterpret_cast<volatile long*>(&mem), bit))\
+ goto label;
+#endif
+
template<>
void srw_mutex_impl<true>::wait_and_lock()
{
@@ -307,24 +336,15 @@ void srw_mutex_impl<true>::wait_and_lock()
DBUG_ASSERT(~HOLDER & lk);
if (lk & HOLDER)
lk= lock.load(std::memory_order_relaxed);
-#if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
-#elif defined _M_IX86||defined _M_X64||defined __i386__||defined __x86_64__
- else if (lock.compare_exchange_weak(lk, lk | HOLDER,
- std::memory_order_acquire,
- std::memory_order_relaxed))
- return;
-#else
- else if (!((lk= lock.fetch_or(HOLDER, std::memory_order_relaxed)) &
- HOLDER))
- goto acquired;
-#endif
else
{
-#if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
+#ifdef IF_NOT_FETCH_OR_GOTO
static_assert(HOLDER == (1U << 31), "compatibility");
- __asm__ goto("lock btsl $31, %0\n\t"
- "jnc %l1" : : "m" (*this) : "cc", "memory" : acquired);
+ IF_NOT_FETCH_OR_GOTO(*this, 31, acquired);
lk|= HOLDER;
+#else
+ if (!((lk= lock.fetch_or(HOLDER, std::memory_order_relaxed)) & HOLDER))
+ goto acquired;
#endif
srw_pause(delay);
}
@@ -338,36 +358,25 @@ void srw_mutex_impl<true>::wait_and_lock()
if (lk & HOLDER)
{
wait(lk);
-#if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
+#ifdef IF_FETCH_OR_GOTO
reload:
#endif
lk= lock.load(std::memory_order_relaxed);
}
-#if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
else
{
+#ifdef IF_FETCH_OR_GOTO
static_assert(HOLDER == (1U << 31), "compatibility");
- __asm__ goto("lock btsl $31, %0\n\t"
- "jc %l1" : : "m" (*this) : "cc", "memory" : reload);
-acquired:
- std::atomic_thread_fence(std::memory_order_acquire);
- return;
- }
-#elif defined _M_IX86||defined _M_X64||defined __i386__||defined __x86_64__
- else if (lock.compare_exchange_weak(lk, lk | HOLDER,
- std::memory_order_acquire,
- std::memory_order_relaxed))
- return;
+ IF_FETCH_OR_GOTO(*this, 31, reload);
#else
- else if (!((lk= lock.fetch_or(HOLDER, std::memory_order_relaxed)) &
- HOLDER))
- {
-acquired:
+ if ((lk= lock.fetch_or(HOLDER, std::memory_order_relaxed)) & HOLDER)
+ continue;
DBUG_ASSERT(lk);
+#endif
+acquired:
std::atomic_thread_fence(std::memory_order_acquire);
return;
}
-#endif
}
}
@@ -380,34 +389,24 @@ void srw_mutex_impl<false>::wait_and_lock()
if (lk & HOLDER)
{
wait(lk);
-#if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
+#ifdef IF_FETCH_OR_GOTO
reload:
#endif
lk= lock.load(std::memory_order_relaxed);
}
-#if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
else
{
+#ifdef IF_FETCH_OR_GOTO
static_assert(HOLDER == (1U << 31), "compatibility");
- __asm__ goto("lock btsl $31, %0\n\t"
- "jc %l1" : : "m" (*this) : "cc", "memory" : reload);
- std::atomic_thread_fence(std::memory_order_acquire);
- return;
- }
-#elif defined _M_IX86||defined _M_X64||defined __i386__||defined __x86_64__
- else if (lock.compare_exchange_weak(lk, lk | HOLDER,
- std::memory_order_acquire,
- std::memory_order_relaxed))
- return;
+ IF_FETCH_OR_GOTO(*this, 31, reload);
#else
- else if (!((lk= lock.fetch_or(HOLDER, std::memory_order_relaxed)) &
- HOLDER))
- {
+ if ((lk= lock.fetch_or(HOLDER, std::memory_order_relaxed)) & HOLDER)
+ continue;
DBUG_ASSERT(lk);
+#endif
std::atomic_thread_fence(std::memory_order_acquire);
return;
}
-#endif
}
}
@@ -456,7 +455,6 @@ void ssux_lock_impl<spinloop>::rd_wait()
writer.wr_unlock();
if (acquired)
break;
- std::this_thread::yield();
}
}