Commit d475643d authored by unknown's avatar unknown

Avoiding a theoretically possible crash (pthread_mutex_lock(0)) which could...

Avoiding a theoretically possible crash (pthread_mutex_lock(0)) which could (at least in POSIX Threads books)
happen on SMP machines, when a thread is going to wait on a condition and it is KILLed at the
same time.
Cleaning code a bit by adding a test in enter_cond() that we have the mutex (was already the case in all places
where it's called except one which is fixed here).


sql/log.cc:
  safe_mutex_assert_owner() is now in THD::enter_cond()
sql/slave.cc:
  lock mutex before waiting on condition.
sql/sql_class.cc:
  THD::awake(): before locking the mutex, let's test it's not zero;
  in theory indeed, the killer thread may see current_cond non-zero and current_mutex zero
  (order of assignments is not guaranteed by POSIX).
  A comment noting that there is still a small chance a KILL does not work and needs
  being re-issued.
sql/sql_class.h:
  Assert in enter_cond() that we have the mutex.
  It is already the case in all places where we call enter_cond(), so better ensure it there.
parent 382ff793
...@@ -1544,7 +1544,6 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length, ...@@ -1544,7 +1544,6 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
void MYSQL_LOG:: wait_for_update(THD* thd, bool master_or_slave) void MYSQL_LOG:: wait_for_update(THD* thd, bool master_or_slave)
{ {
safe_mutex_assert_owner(&LOCK_log);
const char* old_msg = thd->enter_cond(&update_cond, &LOCK_log, const char* old_msg = thd->enter_cond(&update_cond, &LOCK_log,
master_or_slave ? master_or_slave ?
"Has read all relay log; waiting for \ "Has read all relay log; waiting for \
......
...@@ -588,6 +588,7 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock, ...@@ -588,6 +588,7 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock,
while (start_id == *slave_run_id) while (start_id == *slave_run_id)
{ {
DBUG_PRINT("sleep",("Waiting for slave thread to start")); DBUG_PRINT("sleep",("Waiting for slave thread to start"));
pthread_mutex_lock(cond_lock);
const char* old_msg = thd->enter_cond(start_cond,cond_lock, const char* old_msg = thd->enter_cond(start_cond,cond_lock,
"Waiting for slave thread to start"); "Waiting for slave thread to start");
pthread_cond_wait(start_cond,cond_lock); pthread_cond_wait(start_cond,cond_lock);
......
...@@ -299,8 +299,18 @@ void THD::awake(bool prepare_to_die) ...@@ -299,8 +299,18 @@ void THD::awake(bool prepare_to_die)
exits the cond in the time between read and broadcast, but that is exits the cond in the time between read and broadcast, but that is
ok since all we want to do is to make the victim thread get out ok since all we want to do is to make the victim thread get out
of waiting on current_cond. of waiting on current_cond.
If we see a non-zero current_cond: it cannot be an old value (because
then exit_cond() should have run and it can't because we have mutex); so
it is the true value but maybe current_mutex is not yet non-zero (we're
in the middle of enter_cond() and there is a "memory order
inversion"). So we test the mutex too to not lock 0.
Note that there is a small chance we fail to kill. If victim has locked
current_mutex, and hasn't entered enter_cond(), then we don't know it's
going to wait on cond. Then victim goes into its cond "forever" (until
we issue a second KILL). True we have set its thd->killed but it may not
see it immediately and so may have time to reach the cond_wait().
*/ */
if (mysys_var->current_cond) if (mysys_var->current_cond && mysys_var->current_mutex)
{ {
pthread_mutex_lock(mysys_var->current_mutex); pthread_mutex_lock(mysys_var->current_mutex);
pthread_cond_broadcast(mysys_var->current_cond); pthread_cond_broadcast(mysys_var->current_cond);
......
...@@ -539,6 +539,7 @@ class THD :public ilink ...@@ -539,6 +539,7 @@ class THD :public ilink
const char* msg) const char* msg)
{ {
const char* old_msg = proc_info; const char* old_msg = proc_info;
safe_mutex_assert_owner(mutex);
mysys_var->current_mutex = mutex; mysys_var->current_mutex = mutex;
mysys_var->current_cond = cond; mysys_var->current_cond = cond;
proc_info = msg; proc_info = msg;
......
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