Commit 5ad02062 authored by Vicențiu Ciorbaru's avatar Vicențiu Ciorbaru

MDEV-10341: InnoDB: Failing assertion: mutex_own(mutex) - mutex_exit_func

Fix memory barrier issues on releasing mutexes. We must have a full
memory barrier between releasing a mutex lock and reading its waiters.
This prevents us from missing to release waiters due to reading the
number of waiters speculatively before releasing the lock. If threads
try and wait between us reading the waiters count and releasing the
lock, those threads might stall indefinitely.

Also, we must use proper ACQUIRE/RELEASE semantics for atomic
operations, not ACQUIRE/ACQUIRE.
parent 0098d789
...@@ -348,20 +348,13 @@ os_atomic_test_and_set(volatile lock_word_t* ptr) ...@@ -348,20 +348,13 @@ os_atomic_test_and_set(volatile lock_word_t* ptr)
} }
/** Do an atomic release. /** Do an atomic release.
In theory __sync_lock_release should be used to release the lock.
Unfortunately, it does not work properly alone. The workaround is
that more conservative __sync_lock_test_and_set is used instead.
Performance regression was observed at some conditions for Intel
architecture. Disable release barrier on Intel architecture for now.
@param[in,out] ptr Memory location to write to @param[in,out] ptr Memory location to write to
@return the previous value */ @return the previous value */
static inline static inline
lock_word_t void
os_atomic_clear(volatile lock_word_t* ptr) os_atomic_clear(volatile lock_word_t* ptr)
{ {
return(__sync_lock_test_and_set(ptr, 0)); __sync_lock_release(ptr);
} }
# elif defined(HAVE_IB_GCC_ATOMIC_TEST_AND_SET) # elif defined(HAVE_IB_GCC_ATOMIC_TEST_AND_SET)
......
...@@ -178,6 +178,11 @@ mutex_exit_func( ...@@ -178,6 +178,11 @@ mutex_exit_func(
to wake up possible hanging threads if to wake up possible hanging threads if
they are missed in mutex_signal_object. */ they are missed in mutex_signal_object. */
/* We add a memory barrier to prevent reading of the
number of waiters before releasing the lock. */
os_mb;
if (mutex_get_waiters(mutex) != 0) { if (mutex_get_waiters(mutex) != 0) {
mutex_signal_object(mutex); mutex_signal_object(mutex);
......
...@@ -381,20 +381,13 @@ os_atomic_test_and_set(volatile lock_word_t* ptr) ...@@ -381,20 +381,13 @@ os_atomic_test_and_set(volatile lock_word_t* ptr)
} }
/** Do an atomic release. /** Do an atomic release.
In theory __sync_lock_release should be used to release the lock.
Unfortunately, it does not work properly alone. The workaround is
that more conservative __sync_lock_test_and_set is used instead.
Performance regression was observed at some conditions for Intel
architecture. Disable release barrier on Intel architecture for now.
@param[in,out] ptr Memory location to write to @param[in,out] ptr Memory location to write to
@return the previous value */ @return the previous value */
static inline static inline
lock_word_t void
os_atomic_clear(volatile lock_word_t* ptr) os_atomic_clear(volatile lock_word_t* ptr)
{ {
return(__sync_lock_test_and_set(ptr, 0)); __sync_lock_release(ptr);
} }
# elif defined(HAVE_IB_GCC_ATOMIC_TEST_AND_SET) # elif defined(HAVE_IB_GCC_ATOMIC_TEST_AND_SET)
......
...@@ -178,6 +178,11 @@ mutex_exit_func( ...@@ -178,6 +178,11 @@ mutex_exit_func(
to wake up possible hanging threads if to wake up possible hanging threads if
they are missed in mutex_signal_object. */ they are missed in mutex_signal_object. */
/* We add a memory barrier to prevent reading of the
number of waiters before releasing the lock. */
os_mb;
if (mutex_get_waiters(mutex) != 0) { if (mutex_get_waiters(mutex) != 0) {
mutex_signal_object(mutex); mutex_signal_object(mutex);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment