summaryrefslogtreecommitdiff
path: root/sql/mysqld.cc
diff options
context:
space:
mode:
authorDavi Arnaut <davi.arnaut@oracle.com>2010-12-15 20:59:21 -0200
committerDavi Arnaut <davi.arnaut@oracle.com>2010-12-15 20:59:21 -0200
commit4e2cf44180cac803013d086bd50fe06ab3d863a5 (patch)
tree40ac241a8b0dc4aaa69489f0e28b7b759da0511f /sql/mysqld.cc
parent4ccb32c09aa0a4c9678e8cf499a552259c19d743 (diff)
downloadmariadb-git-4e2cf44180cac803013d086bd50fe06ab3d863a5.tar.gz
Bug#58136: Crash in vio_close at concurrent disconnect and KILL
The problem is a race between a session closing its vio (i.e. after a COM_QUIT) at the same time it is being killed by another thread. This could trigger a assertion in vio_close() as the two threads could end up closing the same vio, at the same time. This could happen due to the implementation of SIGNAL_WITH_VIO_CLOSE, which closes the vio of the thread being killed. The solution is to serialize the close of the Vio under LOCK_thd_data, which protects THD data. No regression test is added as this is essentially a debug issue and the test case would be quite convoluted as we would need to synchronize a session that is being killed -- which is a bit difficult since debug sync points code does not synchronize killed sessions. sql/mysqld.cc: Drop lock parameter from close_connection, its not necessary any more. The newly introduced THD::disconnect method will take care of locking. sql/mysqld.h: Change prototype, add a default parameter for the error code. sql/sql_class.cc: In case SIGNAL_WITH_VIO_CLOSE is defined, the active vio is closed and cleared. Subsequent calls will only close the vio owned by the session.
Diffstat (limited to 'sql/mysqld.cc')
-rw-r--r--sql/mysqld.cc45
1 files changed, 17 insertions, 28 deletions
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 5fb63fb61ba..68795ca377b 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -1134,7 +1134,7 @@ static void close_connections(void)
tmp->thread_id,
(tmp->main_security_ctx.user ?
tmp->main_security_ctx.user : ""));
- close_connection(tmp,0,0);
+ close_connection(tmp);
}
#endif
DBUG_PRINT("quit",("Unlocking LOCK_thread_count"));
@@ -1960,39 +1960,28 @@ static void network_init(void)
/**
Close a connection.
- @param thd Thread handle
- @param errcode Error code to print to console
- @param lock 1 if we have have to lock LOCK_thread_count
+ @param thd Thread handle.
+ @param sql_errno The error code to send before disconnect.
@note
For the connection that is doing shutdown, this is called twice
*/
-void close_connection(THD *thd, uint errcode, bool lock)
+void close_connection(THD *thd, uint sql_errno)
{
- st_vio *vio;
DBUG_ENTER("close_connection");
- DBUG_PRINT("enter",("fd: %s error: '%s'",
- thd->net.vio ? vio_description(thd->net.vio) :
- "(not connected)",
- errcode ? ER_DEFAULT(errcode) : ""));
- if (lock)
- mysql_mutex_lock(&LOCK_thread_count);
- thd->killed= THD::KILL_CONNECTION;
- if ((vio= thd->net.vio) != 0)
- {
- if (errcode)
- net_send_error(thd, errcode,
- ER_DEFAULT(errcode), NULL); /* purecov: inspected */
- vio_close(vio); /* vio is freed in delete thd */
- }
- if (lock)
- mysql_mutex_unlock(&LOCK_thread_count);
- MYSQL_CONNECTION_DONE((int) errcode, thd->thread_id);
+
+ if (sql_errno)
+ net_send_error(thd, sql_errno, ER_DEFAULT(sql_errno), NULL);
+
+ thd->disconnect();
+
+ MYSQL_CONNECTION_DONE((int) sql_errno, thd->thread_id);
+
if (MYSQL_CONNECTION_DONE_ENABLED())
{
sleep(0); /* Workaround to avoid tailcall optimisation */
}
- MYSQL_AUDIT_NOTIFY_CONNECTION_DISCONNECT(thd, errcode);
+ MYSQL_AUDIT_NOTIFY_CONNECTION_DISCONNECT(thd, sql_errno);
DBUG_VOID_RETURN;
}
#endif /* EMBEDDED_LIBRARY */
@@ -4951,8 +4940,8 @@ void create_thread_to_handle_connection(THD *thd)
my_snprintf(error_message_buff, sizeof(error_message_buff),
ER_THD(thd, ER_CANT_CREATE_THREAD), error);
net_send_error(thd, ER_CANT_CREATE_THREAD, error_message_buff, NULL);
+ close_connection(thd);
mysql_mutex_lock(&LOCK_thread_count);
- close_connection(thd,0,0);
delete thd;
mysql_mutex_unlock(&LOCK_thread_count);
return;
@@ -4993,7 +4982,7 @@ static void create_new_thread(THD *thd)
mysql_mutex_unlock(&LOCK_connection_count);
DBUG_PRINT("error",("Too many connections"));
- close_connection(thd, ER_CON_COUNT_ERROR, 1);
+ close_connection(thd, ER_CON_COUNT_ERROR);
delete thd;
DBUG_VOID_RETURN;
}
@@ -5374,7 +5363,7 @@ pthread_handler_t handle_connections_namedpipes(void *arg)
if (!(thd->net.vio= vio_new_win32pipe(hConnectedPipe)) ||
my_net_init(&thd->net, thd->net.vio))
{
- close_connection(thd, ER_OUT_OF_RESOURCES, 1);
+ close_connection(thd, ER_OUT_OF_RESOURCES);
delete thd;
continue;
}
@@ -5569,7 +5558,7 @@ pthread_handler_t handle_connections_shared_memory(void *arg)
event_conn_closed)) ||
my_net_init(&thd->net, thd->net.vio))
{
- close_connection(thd, ER_OUT_OF_RESOURCES, 1);
+ close_connection(thd, ER_OUT_OF_RESOURCES);
errmsg= 0;
goto errorconn;
}