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;
#ifdef UNIV_SYNC_DEBUG
/* 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
acquired in addition to the mutex protecting the lock. */
extern ib_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 */
extern os_fast_mutex_t rw_lock_debug_mutex;
#endif /* UNIV_SYNC_DEBUG */
/** Counters for RW locks. */
......
......@@ -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
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
UNIV_INTERN mysql_pfs_key_t rw_lock_debug_mutex_key;
# 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. */
static
......@@ -690,22 +684,7 @@ void
rw_lock_debug_mutex_enter(void)
/*===========================*/
{
loop:
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;
os_fast_mutex_lock(&rw_lock_debug_mutex);
}
/******************************************************************//**
......@@ -715,12 +694,7 @@ void
rw_lock_debug_mutex_exit(void)
/*==========================*/
{
mutex_exit(&rw_lock_debug_mutex);
if (rw_lock_debug_waiters) {
rw_lock_debug_waiters = FALSE;
os_event_set(rw_lock_debug_event);
}
os_fast_mutex_unlock(&rw_lock_debug_mutex);
}
/******************************************************************//**
......
......@@ -1472,11 +1472,7 @@ sync_init(void)
SYNC_NO_ORDER_CHECK);
#ifdef UNIV_SYNC_DEBUG
mutex_create(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;
os_fast_mutex_init(rw_lock_debug_mutex_key, &rw_lock_debug_mutex);
#endif /* UNIV_SYNC_DEBUG */
}
......@@ -1544,6 +1540,7 @@ sync_close(void)
sync_order_checks_on = FALSE;
sync_thread_level_arrays_free();
os_fast_mutex_free(&rw_lock_debug_mutex);
#endif /* UNIV_SYNC_DEBUG */
sync_initialized = FALSE;
......
......@@ -109,14 +109,8 @@ extern ib_mutex_t rw_lock_list_mutex;
#ifdef UNIV_SYNC_DEBUG
/* 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
acquired in addition to the mutex protecting the lock. */
extern ib_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 */
extern os_fast_mutex_t rw_lock_debug_mutex;
#endif /* UNIV_SYNC_DEBUG */
/** Counters for RW locks. */
......
......@@ -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
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
UNIV_INTERN mysql_pfs_key_t rw_lock_debug_mutex_key;
# 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. */
static
......@@ -920,22 +914,7 @@ void
rw_lock_debug_mutex_enter(void)
/*===========================*/
{
loop:
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;
os_fast_mutex_lock(&rw_lock_debug_mutex);
}
/******************************************************************//**
......@@ -945,12 +924,7 @@ void
rw_lock_debug_mutex_exit(void)
/*==========================*/
{
mutex_exit(&rw_lock_debug_mutex);
if (rw_lock_debug_waiters) {
rw_lock_debug_waiters = FALSE;
os_event_set(rw_lock_debug_event);
}
os_fast_mutex_unlock(&rw_lock_debug_mutex);
}
/******************************************************************//**
......
......@@ -1598,11 +1598,7 @@ sync_init(void)
SYNC_NO_ORDER_CHECK);
#ifdef UNIV_SYNC_DEBUG
mutex_create(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;
os_fast_mutex_init(rw_lock_debug_mutex_key, &rw_lock_debug_mutex);
#endif /* UNIV_SYNC_DEBUG */
}
......@@ -1676,6 +1672,7 @@ sync_close(void)
sync_order_checks_on = FALSE;
sync_thread_level_arrays_free();
os_fast_mutex_free(&rw_lock_debug_mutex);
#endif /* UNIV_SYNC_DEBUG */
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