mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
MDEV-6582: DEBUG_SYNC does not reset mysys_var->current_mutex, causes assertion "Trying to unlock mutex that wasn't locked"
The bug was in DEBUG_SYNC. When waiting, debug_sync_execute() temporarily sets thd->mysys_var->current_mutex to a new value while waiting. However, if the old value of current_mutex was NULL, it was not restored, current_mutex remained set to the temporary value (debug_sync_global.ds_mutex). This made possible the following race: Thread T1 goes to KILL thread T2. In THD::awake(), T1 loads T2->mysys_var->current_mutex, it is set to ds_mutex, T1 locks this mutex. Now T2 runs, it does ENTER_COND, it sets T2->mysys_var->current_mutex to LOCK_wait_commit (for example). Then T1 resumes, it reloads mysys_var->current_mutex, now it is set to LOCK_wait_commit, T1 unlocks this mutex instead of the ds_mutex that it locked previously. This causes safe_mutex to assert with the message: "Trying to unlock mutex LOCK_wait_commit that wasn't locked". The fix is to ensure that DEBUG_SYNC also will restore mysys_var->current_mutex in the case where the original value was NULL.
This commit is contained in:
@ -1394,8 +1394,9 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
|
|||||||
|
|
||||||
if (action->wait_for.length())
|
if (action->wait_for.length())
|
||||||
{
|
{
|
||||||
mysql_mutex_t *old_mutex;
|
mysql_mutex_t *old_mutex= NULL;
|
||||||
mysql_cond_t *old_cond= NULL;
|
mysql_cond_t *old_cond= NULL;
|
||||||
|
bool restore_current_mutex;
|
||||||
int error= 0;
|
int error= 0;
|
||||||
struct timespec abstime;
|
struct timespec abstime;
|
||||||
|
|
||||||
@ -1412,11 +1413,12 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
|
|||||||
{
|
{
|
||||||
old_mutex= thd->mysys_var->current_mutex;
|
old_mutex= thd->mysys_var->current_mutex;
|
||||||
old_cond= thd->mysys_var->current_cond;
|
old_cond= thd->mysys_var->current_cond;
|
||||||
|
restore_current_mutex = true;
|
||||||
thd->mysys_var->current_mutex= &debug_sync_global.ds_mutex;
|
thd->mysys_var->current_mutex= &debug_sync_global.ds_mutex;
|
||||||
thd->mysys_var->current_cond= &debug_sync_global.ds_cond;
|
thd->mysys_var->current_cond= &debug_sync_global.ds_cond;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
old_mutex= NULL;
|
restore_current_mutex = false;
|
||||||
|
|
||||||
set_timespec(abstime, action->timeout);
|
set_timespec(abstime, action->timeout);
|
||||||
DBUG_EXECUTE("debug_sync_exec", {
|
DBUG_EXECUTE("debug_sync_exec", {
|
||||||
@ -1476,7 +1478,7 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
|
|||||||
is locked. (See comment in THD::exit_cond().)
|
is locked. (See comment in THD::exit_cond().)
|
||||||
*/
|
*/
|
||||||
mysql_mutex_unlock(&debug_sync_global.ds_mutex);
|
mysql_mutex_unlock(&debug_sync_global.ds_mutex);
|
||||||
if (old_mutex)
|
if (restore_current_mutex)
|
||||||
{
|
{
|
||||||
mysql_mutex_lock(&thd->mysys_var->mutex);
|
mysql_mutex_lock(&thd->mysys_var->mutex);
|
||||||
thd->mysys_var->current_mutex= old_mutex;
|
thd->mysys_var->current_mutex= old_mutex;
|
||||||
|
Reference in New Issue
Block a user