Commit 6192f0bf authored by Sergey Vojtovich's avatar Sergey Vojtovich

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 d466ed90
...@@ -108,14 +108,8 @@ extern ib_mutex_t rw_lock_list_mutex; ...@@ -108,14 +108,8 @@ extern ib_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 ib_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 */
/** Counters for RW locks. */ /** Counters for RW locks. */
......
...@@ -151,18 +151,12 @@ UNIV_INTERN mysql_pfs_key_t rw_lock_mutex_key; ...@@ -151,18 +151,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 ib_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
...@@ -690,22 +684,7 @@ void ...@@ -690,22 +684,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;
} }
/******************************************************************//** /******************************************************************//**
...@@ -715,12 +694,7 @@ void ...@@ -715,12 +694,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);
}
} }
/******************************************************************//** /******************************************************************//**
......
...@@ -1472,11 +1472,7 @@ sync_init(void) ...@@ -1472,11 +1472,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();
rw_lock_debug_waiters = FALSE;
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
} }
...@@ -1544,6 +1540,7 @@ sync_close(void) ...@@ -1544,6 +1540,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;
......
...@@ -109,14 +109,8 @@ extern ib_mutex_t rw_lock_list_mutex; ...@@ -109,14 +109,8 @@ extern ib_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 ib_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 */
/** Counters for RW locks. */ /** Counters for RW locks. */
......
...@@ -151,18 +151,12 @@ UNIV_INTERN mysql_pfs_key_t rw_lock_mutex_key; ...@@ -151,18 +151,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 ib_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
...@@ -920,22 +914,7 @@ void ...@@ -920,22 +914,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;
} }
/******************************************************************//** /******************************************************************//**
...@@ -945,12 +924,7 @@ void ...@@ -945,12 +924,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);
}
} }
/******************************************************************//** /******************************************************************//**
......
...@@ -1598,11 +1598,7 @@ sync_init(void) ...@@ -1598,11 +1598,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();
rw_lock_debug_waiters = FALSE;
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
} }
...@@ -1676,6 +1672,7 @@ sync_close(void) ...@@ -1676,6 +1672,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