Commit c01c8192 authored by Sergey Vojtovich's avatar Sergey Vojtovich

Backport from 10.0:

MDEV-6483 - Deadlock around rw_lock_debug_mutex on PPC64

This problem affects only debug builds on PPC64.

There are at least two race conditions around
rw_lock_debug_mutex_enter and rw_lock_debug_mutex_exit:

- rw_lock_debug_waiters was loaded/stored without setting
  appropriate locks/memory barriers.
- there is a gap between calls to os_event_reset() and
  os_event_wait() and in such case we're supposed to pass
  return value of the former to the latter.

Fixed by replacing self-cooked spinlocks with system mutexes.
These days system mutexes offer much better performance. OTOH
performance is not that critical for debug builds.
parent 40497577
...@@ -70,14 +70,8 @@ extern mutex_t rw_lock_list_mutex; ...@@ -70,14 +70,8 @@ extern mutex_t rw_lock_list_mutex;
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
/* The global mutex which protects debug info lists of all rw-locks. /* The global mutex which protects debug info lists of all rw-locks.
To modify the debug info list of an rw-lock, this mutex has to be To modify the debug info list of an rw-lock, this mutex has to be
acquired in addition to the mutex protecting the lock. */ acquired in addition to the mutex protecting the lock. */
extern mutex_t rw_lock_debug_mutex; extern os_fast_mutex_t rw_lock_debug_mutex;
extern os_event_t rw_lock_debug_event; /*!< If deadlock detection does
not get immediately the mutex it
may wait for this event */
extern ibool rw_lock_debug_waiters; /*!< This is set to TRUE, if
there may be waiters for the event */
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
/** number of spin waits on rw-latches, /** number of spin waits on rw-latches,
......
...@@ -180,18 +180,12 @@ UNIV_INTERN mysql_pfs_key_t rw_lock_mutex_key; ...@@ -180,18 +180,12 @@ UNIV_INTERN mysql_pfs_key_t rw_lock_mutex_key;
To modify the debug info list of an rw-lock, this mutex has to be To modify the debug info list of an rw-lock, this mutex has to be
acquired in addition to the mutex protecting the lock. */ acquired in addition to the mutex protecting the lock. */
UNIV_INTERN mutex_t rw_lock_debug_mutex; UNIV_INTERN os_fast_mutex_t rw_lock_debug_mutex;
# ifdef UNIV_PFS_MUTEX # ifdef UNIV_PFS_MUTEX
UNIV_INTERN mysql_pfs_key_t rw_lock_debug_mutex_key; UNIV_INTERN mysql_pfs_key_t rw_lock_debug_mutex_key;
# endif # endif
/* If deadlock detection does not get immediately the mutex,
it may wait for this event */
UNIV_INTERN os_event_t rw_lock_debug_event;
/* This is set to TRUE, if there may be waiters for the event */
UNIV_INTERN ibool rw_lock_debug_waiters;
/******************************************************************//** /******************************************************************//**
Creates a debug info struct. */ Creates a debug info struct. */
static static
...@@ -736,22 +730,7 @@ void ...@@ -736,22 +730,7 @@ void
rw_lock_debug_mutex_enter(void) rw_lock_debug_mutex_enter(void)
/*===========================*/ /*===========================*/
{ {
loop: os_fast_mutex_lock(&rw_lock_debug_mutex);
if (0 == mutex_enter_nowait(&rw_lock_debug_mutex)) {
return;
}
os_event_reset(rw_lock_debug_event);
rw_lock_debug_waiters = TRUE;
if (0 == mutex_enter_nowait(&rw_lock_debug_mutex)) {
return;
}
os_event_wait(rw_lock_debug_event);
goto loop;
} }
/******************************************************************//** /******************************************************************//**
...@@ -761,12 +740,7 @@ void ...@@ -761,12 +740,7 @@ void
rw_lock_debug_mutex_exit(void) rw_lock_debug_mutex_exit(void)
/*==========================*/ /*==========================*/
{ {
mutex_exit(&rw_lock_debug_mutex); os_fast_mutex_unlock(&rw_lock_debug_mutex);
if (rw_lock_debug_waiters) {
rw_lock_debug_waiters = FALSE;
os_event_set(rw_lock_debug_event);
}
} }
/******************************************************************//** /******************************************************************//**
......
...@@ -1535,11 +1535,7 @@ sync_init(void) ...@@ -1535,11 +1535,7 @@ sync_init(void)
SYNC_NO_ORDER_CHECK); SYNC_NO_ORDER_CHECK);
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
mutex_create(rw_lock_debug_mutex_key, &rw_lock_debug_mutex, os_fast_mutex_init(rw_lock_debug_mutex_key, &rw_lock_debug_mutex);
SYNC_NO_ORDER_CHECK);
rw_lock_debug_event = os_event_create(NULL);
rw_lock_debug_waiters = FALSE;
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
} }
...@@ -1607,6 +1603,7 @@ sync_close(void) ...@@ -1607,6 +1603,7 @@ sync_close(void)
sync_order_checks_on = FALSE; sync_order_checks_on = FALSE;
sync_thread_level_arrays_free(); sync_thread_level_arrays_free();
os_fast_mutex_free(&rw_lock_debug_mutex);
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
sync_initialized = FALSE; sync_initialized = FALSE;
......
...@@ -70,14 +70,8 @@ extern mutex_t rw_lock_list_mutex; ...@@ -70,14 +70,8 @@ extern mutex_t rw_lock_list_mutex;
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
/* The global mutex which protects debug info lists of all rw-locks. /* The global mutex which protects debug info lists of all rw-locks.
To modify the debug info list of an rw-lock, this mutex has to be To modify the debug info list of an rw-lock, this mutex has to be
acquired in addition to the mutex protecting the lock. */ acquired in addition to the mutex protecting the lock. */
extern mutex_t rw_lock_debug_mutex; extern os_fast_mutex_t rw_lock_debug_mutex;
extern os_event_t rw_lock_debug_event; /*!< If deadlock detection does
not get immediately the mutex it
may wait for this event */
extern ibool rw_lock_debug_waiters; /*!< This is set to TRUE, if
there may be waiters for the event */
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
/** number of spin waits on rw-latches, /** number of spin waits on rw-latches,
......
...@@ -180,18 +180,12 @@ UNIV_INTERN mysql_pfs_key_t rw_lock_mutex_key; ...@@ -180,18 +180,12 @@ UNIV_INTERN mysql_pfs_key_t rw_lock_mutex_key;
To modify the debug info list of an rw-lock, this mutex has to be To modify the debug info list of an rw-lock, this mutex has to be
acquired in addition to the mutex protecting the lock. */ acquired in addition to the mutex protecting the lock. */
UNIV_INTERN mutex_t rw_lock_debug_mutex; UNIV_INTERN os_fast_mutex_t rw_lock_debug_mutex;
# ifdef UNIV_PFS_MUTEX # ifdef UNIV_PFS_MUTEX
UNIV_INTERN mysql_pfs_key_t rw_lock_debug_mutex_key; UNIV_INTERN mysql_pfs_key_t rw_lock_debug_mutex_key;
# endif # endif
/* If deadlock detection does not get immediately the mutex,
it may wait for this event */
UNIV_INTERN os_event_t rw_lock_debug_event;
/* This is set to TRUE, if there may be waiters for the event */
UNIV_INTERN ibool rw_lock_debug_waiters;
/******************************************************************//** /******************************************************************//**
Creates a debug info struct. */ Creates a debug info struct. */
static static
...@@ -731,22 +725,7 @@ void ...@@ -731,22 +725,7 @@ void
rw_lock_debug_mutex_enter(void) rw_lock_debug_mutex_enter(void)
/*===========================*/ /*===========================*/
{ {
loop: os_fast_mutex_lock(&rw_lock_debug_mutex);
if (0 == mutex_enter_nowait(&rw_lock_debug_mutex)) {
return;
}
os_event_reset(rw_lock_debug_event);
rw_lock_debug_waiters = TRUE;
if (0 == mutex_enter_nowait(&rw_lock_debug_mutex)) {
return;
}
os_event_wait(rw_lock_debug_event);
goto loop;
} }
/******************************************************************//** /******************************************************************//**
...@@ -756,12 +735,7 @@ void ...@@ -756,12 +735,7 @@ void
rw_lock_debug_mutex_exit(void) rw_lock_debug_mutex_exit(void)
/*==========================*/ /*==========================*/
{ {
mutex_exit(&rw_lock_debug_mutex); os_fast_mutex_unlock(&rw_lock_debug_mutex);
if (rw_lock_debug_waiters) {
rw_lock_debug_waiters = FALSE;
os_event_set(rw_lock_debug_event);
}
} }
/******************************************************************//** /******************************************************************//**
......
...@@ -1514,11 +1514,7 @@ sync_init(void) ...@@ -1514,11 +1514,7 @@ sync_init(void)
SYNC_NO_ORDER_CHECK); SYNC_NO_ORDER_CHECK);
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
mutex_create(rw_lock_debug_mutex_key, &rw_lock_debug_mutex, os_fast_mutex_init(rw_lock_debug_mutex_key, &rw_lock_debug_mutex);
SYNC_NO_ORDER_CHECK);
rw_lock_debug_event = os_event_create(NULL);
rw_lock_debug_waiters = FALSE;
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
} }
...@@ -1586,6 +1582,7 @@ sync_close(void) ...@@ -1586,6 +1582,7 @@ sync_close(void)
sync_order_checks_on = FALSE; sync_order_checks_on = FALSE;
sync_thread_level_arrays_free(); sync_thread_level_arrays_free();
os_fast_mutex_free(&rw_lock_debug_mutex);
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
sync_initialized = FALSE; sync_initialized = FALSE;
......
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