diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/lock.cc | 16 | ||||
-rw-r--r-- | sql/log.cc | 9 | ||||
-rw-r--r-- | sql/repl_failsafe.cc | 9 | ||||
-rw-r--r-- | sql/slave.cc | 18 | ||||
-rw-r--r-- | sql/sql_class.h | 16 | ||||
-rw-r--r-- | sql/sql_table.cc | 1 |
6 files changed, 33 insertions, 36 deletions
diff --git a/sql/lock.cc b/sql/lock.cc index 5010d115a6c..9ea1ce96175 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -692,15 +692,14 @@ bool lock_global_read_lock(THD *thd) while (protect_against_global_read_lock && !thd->killed) pthread_cond_wait(&COND_refresh, &LOCK_open); waiting_for_read_lock--; - thd->exit_cond(old_message); if (thd->killed) { - (void) pthread_mutex_unlock(&LOCK_open); + thd->exit_cond(old_message); DBUG_RETURN(1); } thd->global_read_lock=1; global_read_lock++; - (void) pthread_mutex_unlock(&LOCK_open); + thd->exit_cond(old_message); } DBUG_RETURN(0); } @@ -721,11 +720,12 @@ void unlock_global_read_lock(THD *thd) bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh) { const char *old_message; - bool result=0; + bool result= 0, need_exit_cond; DBUG_ENTER("wait_if_global_read_lock"); + LINT_INIT(old_message); (void) pthread_mutex_lock(&LOCK_open); - if (global_read_lock) + if (need_exit_cond= (bool)global_read_lock) { if (thd->global_read_lock) // This thread had the read locks { @@ -740,11 +740,13 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh) (void) pthread_cond_wait(&COND_refresh,&LOCK_open); if (thd->killed) result=1; - thd->exit_cond(old_message); } if (!abort_on_refresh && !result) protect_against_global_read_lock++; - pthread_mutex_unlock(&LOCK_open); + if (unlikely(need_exit_cond)) // global read locks are rare + thd->exit_cond(old_message); + else + pthread_mutex_unlock(&LOCK_open); DBUG_RETURN(result); } diff --git a/sql/log.cc b/sql/log.cc index a0e2196cc59..e031656cc6e 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1533,12 +1533,8 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length, NOTES One must have a lock on LOCK_log before calling this function. - This lock will be freed before return! - - The reason for the above is that for enter_cond() / exit_cond() to - work the mutex must be got before enter_cond() but releases before - exit_cond(). - If you don't do it this way, you will get a deadlock in THD::awake() + This lock will be freed before return! That's required by + THD::enter_cond() (see NOTES in sql_class.h). */ @@ -1551,7 +1547,6 @@ the I/O slave thread to update it" : "Has sent all binlog to slave; \ waiting for binlog to be updated"); pthread_cond_wait(&update_cond, &LOCK_log); - pthread_mutex_unlock(&LOCK_log); // See NOTES thd->exit_cond(old_msg); } diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 1edf452d5f6..604938a8ed0 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -584,6 +584,8 @@ pthread_handler_decl(handle_failsafe_rpl,arg) THD *thd = new THD; thd->thread_stack = (char*)&thd; MYSQL* recovery_captain = 0; + const char* msg; + pthread_detach_this_thread(); if (init_failsafe_rpl_thread(thd) || !(recovery_captain=mc_mysql_init(0))) { @@ -591,11 +593,11 @@ pthread_handler_decl(handle_failsafe_rpl,arg) goto err; } pthread_mutex_lock(&LOCK_rpl_status); + msg= thd->enter_cond(&COND_rpl_status, + &LOCK_rpl_status, "Waiting for request"); while (!thd->killed && !abort_loop) { bool break_req_chain = 0; - const char* msg = thd->enter_cond(&COND_rpl_status, - &LOCK_rpl_status, "Waiting for request"); pthread_cond_wait(&COND_rpl_status, &LOCK_rpl_status); thd->proc_info="Processing request"; while (!break_req_chain) @@ -613,9 +615,8 @@ pthread_handler_decl(handle_failsafe_rpl,arg) break; } } - thd->exit_cond(msg); } - pthread_mutex_unlock(&LOCK_rpl_status); + thd->exit_cond(msg); err: if (recovery_captain) mc_mysql_close(recovery_captain); diff --git a/sql/slave.cc b/sql/slave.cc index 2269fc8d8cf..4416a2544ef 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -582,7 +582,7 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock, pthread_mutex_unlock(start_lock); DBUG_RETURN(ER_SLAVE_THREAD); } - if (start_cond && cond_lock) + if (start_cond && cond_lock) // caller has cond_lock { THD* thd = current_thd; while (start_id == *slave_run_id) @@ -592,11 +592,9 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock, "Waiting for slave thread to start"); pthread_cond_wait(start_cond,cond_lock); thd->exit_cond(old_msg); + pthread_mutex_lock(cond_lock); // re-acquire it as exit_cond() released if (thd->killed) - { - pthread_mutex_unlock(cond_lock); DBUG_RETURN(ER_SERVER_SHUTDOWN); - } } } if (start_lock) @@ -1561,7 +1559,6 @@ thread to free enough relay log space"); !rli->ignore_log_space_limit) pthread_cond_wait(&rli->log_space_cond, &rli->log_space_lock); thd->exit_cond(save_proc_info); - pthread_mutex_unlock(&rli->log_space_lock); DBUG_RETURN(slave_killed); } @@ -1965,6 +1962,9 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, (long) timeout)); pthread_mutex_lock(&data_lock); + const char *msg= thd->enter_cond(&data_cond, &data_lock, + "Waiting for the SQL slave thread to " + "advance position"); /* This function will abort when it notices that some CHANGE MASTER or RESET MASTER has changed the master info. @@ -2063,9 +2063,6 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, //wait for master update, with optional timeout. DBUG_PRINT("info",("Waiting for master update")); - const char* msg = thd->enter_cond(&data_cond, &data_lock, - "Waiting for the SQL slave thread to \ -advance position"); /* We are going to pthread_cond_(timed)wait(); if the SQL thread stops it will wake us up. @@ -2087,8 +2084,7 @@ advance position"); } else pthread_cond_wait(&data_cond, &data_lock); - DBUG_PRINT("info",("Got signal of master update")); - thd->exit_cond(msg); + DBUG_PRINT("info",("Got signal of master update or timed out")); if (error == ETIMEDOUT || error == ETIME) { error= -1; @@ -2100,7 +2096,7 @@ advance position"); } err: - pthread_mutex_unlock(&data_lock); + thd->exit_cond(msg); DBUG_PRINT("exit",("killed: %d abort: %d slave_running: %d \ improper_arguments: %d timed_out: %d", (int) thd->killed, diff --git a/sql/sql_class.h b/sql/sql_class.h index df246b42337..e646d33fe5d 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -537,12 +537,9 @@ public: void awake(bool prepare_to_die); /* For enter_cond() / exit_cond() to work the mutex must be got before - enter_cond() but released before exit_cond() (in 4.1, assertions will soon - ensure this). Use must be: - lock mutex; enter_cond(); ...; unlock mutex; exit_cond(). - If you don't do it this way, you will get a deadlock if another thread is - doing a THD::awake() on you. - + enter_cond() (in 4.1 an assertion will soon ensure this); this mutex is + then released by exit_cond(). Use must be: + lock mutex; enter_cond(); your code; exit_cond(). */ inline const char* enter_cond(pthread_cond_t *cond, pthread_mutex_t* mutex, const char* msg) @@ -555,6 +552,13 @@ public: } inline void exit_cond(const char* old_msg) { + /* + Putting the mutex unlock in exit_cond() ensures that + mysys_var->current_mutex is always unlocked _before_ mysys_var->mutex is + locked (if that would not be the case, you'll get a deadlock if someone + does a THD::awake() on you). + */ + pthread_mutex_unlock(mysys_var->current_mutex); pthread_mutex_lock(&mysys_var->mutex); mysys_var->current_mutex = 0; mysys_var->current_cond = 0; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 9ab4859bc13..7f4a8583b78 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1301,7 +1301,6 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, dropping_tables--; } thd->exit_cond(old_message); - pthread_mutex_unlock(&LOCK_open); if (thd->killed) goto err; open_for_modify=0; |