Commit 40497577 authored by Sergey Vojtovich's avatar Sergey Vojtovich

Backport from 10.0:

MDEV-6450 - MariaDB crash on Power8 when built with advance tool
            chain

InnoDB mutex_exit() function calls __sync_test_and_set() to release
the lock. According to manual this function is supposed to create
"acquire" memory barrier whereas in fact we need "release" memory
barrier at mutex_exit().

The problem isn't repeatable with gcc because it creates
"acquire-release" memory barrier for __sync_test_and_set().
ATC creates just "acquire" barrier.

Fixed by creating proper barrier at mutex_exit() by using
__sync_lock_release() instead of __sync_test_and_set().
parent dd25e7f0
...@@ -310,6 +310,9 @@ Returns the old value of *ptr, atomically sets *ptr to new_val */ ...@@ -310,6 +310,9 @@ Returns the old value of *ptr, atomically sets *ptr to new_val */
# define os_atomic_test_and_set_byte(ptr, new_val) \ # define os_atomic_test_and_set_byte(ptr, new_val) \
__sync_lock_test_and_set(ptr, (byte) new_val) __sync_lock_test_and_set(ptr, (byte) new_val)
# define os_atomic_lock_release_byte(ptr) \
__sync_lock_release(ptr)
#elif defined(HAVE_IB_SOLARIS_ATOMICS) #elif defined(HAVE_IB_SOLARIS_ATOMICS)
#define HAVE_ATOMIC_BUILTINS #define HAVE_ATOMIC_BUILTINS
...@@ -363,6 +366,9 @@ Returns the old value of *ptr, atomically sets *ptr to new_val */ ...@@ -363,6 +366,9 @@ Returns the old value of *ptr, atomically sets *ptr to new_val */
# define os_atomic_test_and_set_byte(ptr, new_val) \ # define os_atomic_test_and_set_byte(ptr, new_val) \
atomic_swap_uchar(ptr, new_val) atomic_swap_uchar(ptr, new_val)
# define os_atomic_lock_release_byte(ptr) \
(void) atomic_swap_uchar(ptr, 0)
#elif defined(HAVE_WINDOWS_ATOMICS) #elif defined(HAVE_WINDOWS_ATOMICS)
#define HAVE_ATOMIC_BUILTINS #define HAVE_ATOMIC_BUILTINS
...@@ -456,6 +462,9 @@ clobbered */ ...@@ -456,6 +462,9 @@ clobbered */
# define IB_MEMORY_BARRIER_STARTUP_MSG \ # define IB_MEMORY_BARRIER_STARTUP_MSG \
"_mm_lfence() and _mm_sfence() are used for memory barrier" "_mm_lfence() and _mm_sfence() are used for memory barrier"
# define os_atomic_lock_release_byte(ptr) \
(void) InterlockedExchange(ptr, 0)
#else #else
# define os_rmb do { } while(0) # define os_rmb do { } while(0)
# define os_wmb do { } while(0) # define os_wmb do { } while(0)
......
...@@ -109,10 +109,7 @@ mutex_reset_lock_word( ...@@ -109,10 +109,7 @@ mutex_reset_lock_word(
mutex_t* mutex) /*!< in: mutex */ mutex_t* mutex) /*!< in: mutex */
{ {
#if defined(HAVE_ATOMIC_BUILTINS) #if defined(HAVE_ATOMIC_BUILTINS)
/* In theory __sync_lock_release should be used to release the lock. os_atomic_lock_release_byte(&mutex->lock_word);
Unfortunately, it does not work properly alone. The workaround is
that more conservative __sync_lock_test_and_set is used instead. */
os_atomic_test_and_set_byte(&mutex->lock_word, 0);
#else #else
mutex->lock_word = 0; mutex->lock_word = 0;
......
...@@ -317,6 +317,9 @@ Returns the old value of *ptr, atomically sets *ptr to new_val */ ...@@ -317,6 +317,9 @@ Returns the old value of *ptr, atomically sets *ptr to new_val */
# define os_atomic_test_and_set_byte(ptr, new_val) \ # define os_atomic_test_and_set_byte(ptr, new_val) \
__sync_lock_test_and_set(ptr, (byte) new_val) __sync_lock_test_and_set(ptr, (byte) new_val)
# define os_atomic_lock_release_byte(ptr) \
__sync_lock_release(ptr)
#elif defined(HAVE_IB_SOLARIS_ATOMICS) #elif defined(HAVE_IB_SOLARIS_ATOMICS)
# define HAVE_ATOMIC_BUILTINS # define HAVE_ATOMIC_BUILTINS
...@@ -374,6 +377,9 @@ Returns the old value of *ptr, atomically sets *ptr to new_val */ ...@@ -374,6 +377,9 @@ Returns the old value of *ptr, atomically sets *ptr to new_val */
# define os_atomic_test_and_set_byte(ptr, new_val) \ # define os_atomic_test_and_set_byte(ptr, new_val) \
atomic_swap_uchar(ptr, new_val) atomic_swap_uchar(ptr, new_val)
# define os_atomic_lock_release_byte(ptr) \
(void) atomic_swap_uchar(ptr, 0)
#elif defined(HAVE_WINDOWS_ATOMICS) #elif defined(HAVE_WINDOWS_ATOMICS)
# define HAVE_ATOMIC_BUILTINS # define HAVE_ATOMIC_BUILTINS
...@@ -476,6 +482,9 @@ clobbered */ ...@@ -476,6 +482,9 @@ clobbered */
# define IB_MEMORY_BARRIER_STARTUP_MSG \ # define IB_MEMORY_BARRIER_STARTUP_MSG \
"_mm_lfence() and _mm_sfence() are used for memory barrier" "_mm_lfence() and _mm_sfence() are used for memory barrier"
# define os_atomic_lock_release_byte(ptr) \
(void) InterlockedExchange(ptr, 0)
#else #else
# define os_rmb do { } while(0) # define os_rmb do { } while(0)
# define os_wmb do { } while(0) # define os_wmb do { } while(0)
......
...@@ -109,10 +109,7 @@ mutex_reset_lock_word( ...@@ -109,10 +109,7 @@ mutex_reset_lock_word(
mutex_t* mutex) /*!< in: mutex */ mutex_t* mutex) /*!< in: mutex */
{ {
#if defined(HAVE_ATOMIC_BUILTINS) #if defined(HAVE_ATOMIC_BUILTINS)
/* In theory __sync_lock_release should be used to release the lock. os_atomic_lock_release_byte(&mutex->lock_word);
Unfortunately, it does not work properly alone. The workaround is
that more conservative __sync_lock_test_and_set is used instead. */
os_atomic_test_and_set_byte(&mutex->lock_word, 0);
#else #else
mutex->lock_word = 0; mutex->lock_word = 0;
......
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