#At file:///home/vlad/bzr/mysql-5.1-bugteam/
2718 Vladislav Vaintroub 2008-08-23
Bug#38522: 5 seconds delay when closing application using embedded server
The problem here is that embedded server starts handle_thread manager
thread on mysql_library_init() does not stop it on mysql_library_end().
At shutdown, my_thread_global_end() waits for thread count to become 0,
but since we did not stop the thread it will give up after 5 seconds.
Solution is to move shutdown for handle_manager thread from kill_server()
(mysqld specific) to clean_up() that is used by both embedded and mysqld.
This patch also contains some refactorings - to avoid duplicate code,
start_handle_manager() and stop_handle_manager() functions are introduced.
Unused variables are eliminated. handle_manager does not rely on global
variable abort_loop anymore to stop (abort_loop is not set for embedded).
Note: Specifically on Windows and when using DBUG version of libmysqld,
the complete solution requires removing obsolete code my_thread_init()
from my_thread_var(). This has a side effect that a DBUG statement
after my_thread_end() can cause thread counter to be incremented, and
embedded will hang for some seconds. Or worse, my_thread_init() will
crash if critical sections have been deleted by the global cleanup
routine that runs in a different thread.
modified:
libmysql/libmysql.c
libmysqld/lib_sql.cc
mysys/my_thr_init.c
sql/mysql_priv.h
sql/mysqld.cc
sql/sql_manager.cc
per-file messages:
libmysql/libmysql.c
Removed DBUG_POP call, because when called after my_end(), will access
THR_key_mysys that is already deleted. The result of pthread_get_specific
is not predictable in this case and hence DBUG_POP can crash.
Now, my_end is called without MY_DONT_FREE_DBUG - to free the resouces and prevent unsafe pthread_getspecific call.
mysys/my_thr_init.c
Remove windows-DLL-specific workaround for something (old code, no documentation for what specifically). The problem is that even after
my_thread_end() is finished, DBUG statement can initiate my_thread_init(). This does not happen anywhere else and should not happen on Windows either.
sql/mysql_priv.h
- new functions start_handle_manager() and stop_handle_manager()
- move manager_thread_in_use variable to sql_manager.cc and made
it static
- remove manager_status, as it is unused
sql/mysqld.cc
Code to start/stop handle_manager thread is factored out into start_handle_manager() and stop_handle_manager()
sql/sql_manager.cc
- new functions start_handle_manager() and stop_handle_manager().
- removed unused status and manager status variable.
- don't rely on global abort_loop variable to stop the thread,
(not set in embedded), use static abort_manager that is set
by stop_handle_manager()
- changed DBUG_RETURN in handle_manager() to DBUG_LEAVE + return.
Using DBUG_RETURN is unsafe here, it can access TLS key that is already deleted in my_thread_global_end()
=== modified file 'libmysql/libmysql.c'
--- a/libmysql/libmysql.c 2008-05-20 16:36:26 +0000
+++ b/libmysql/libmysql.c 2008-08-24 01:06:38 +0000
@@ -207,9 +207,7 @@ void STDCALL mysql_server_end()
/* If library called my_init(), free memory allocated by it */
if (!org_my_init_done)
{
- my_end(MY_DONT_FREE_DBUG);
- /* Remove TRACING, if enabled by mysql_debug() */
- DBUG_POP();
+ my_end(0);
}
else
{
=== modified file 'libmysqld/lib_sql.cc'
--- a/libmysqld/lib_sql.cc 2008-08-13 18:50:08 +0000
+++ b/libmysqld/lib_sql.cc 2008-08-24 01:06:38 +0000
@@ -538,12 +538,7 @@ int init_embedded_server(int argc, char
(void) thr_setconcurrency(concurrency); // 10 by default
- if (flush_time && flush_time != ~(ulong) 0L)
- {
- pthread_t hThread;
- if (pthread_create(&hThread,&connection_attrib,handle_manager,0))
- sql_print_error("Warning: Can't create thread to manage maintenance");
- }
+ start_handle_manager();
// FIXME initialize binlog_filter and rpl_filter if not already done
// corresponding delete is in clean_up()
=== modified file 'mysys/my_thr_init.c'
--- a/mysys/my_thr_init.c 2008-04-01 09:21:09 +0000
+++ b/mysys/my_thr_init.c 2008-08-24 01:06:38 +0000
@@ -368,17 +368,7 @@ void my_thread_end(void)
struct st_my_thread_var *_my_thread_var(void)
{
- struct st_my_thread_var *tmp=
- my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
-#if defined(USE_TLS)
- /* This can only happen in a .DLL */
- if (!tmp)
- {
- my_thread_init();
- tmp=my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
- }
-#endif
- return tmp;
+ return my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
}
=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h 2008-08-12 10:26:23 +0000
+++ b/sql/mysql_priv.h 2008-08-24 01:06:38 +0000
@@ -1766,10 +1766,9 @@ int mysql_load(THD *thd, sql_exchange *e
int write_record(THD *thd, TABLE *table, COPY_INFO *info);
/* sql_manager.cc */
-extern ulong volatile manager_status;
-extern bool volatile manager_thread_in_use, mqh_used;
-extern pthread_t manager_thread;
-pthread_handler_t handle_manager(void *arg);
+extern bool volatile mqh_used;
+void start_handle_manager();
+void stop_handle_manager();
bool mysql_manager_submit(void (*action)());
=== modified file 'sql/mysqld.cc'
--- a/sql/mysqld.cc 2008-06-19 14:02:32 +0000
+++ b/sql/mysqld.cc 2008-08-24 01:06:38 +0000
@@ -783,16 +783,6 @@ static void close_connections(void)
kill_cached_threads++;
flush_thread_cache();
- /* kill flush thread */
- (void) pthread_mutex_lock(&LOCK_manager);
- if (manager_thread_in_use)
- {
- DBUG_PRINT("quit", ("killing manager thread: 0x%lx",
- (ulong)manager_thread));
- (void) pthread_cond_signal(&COND_manager);
- }
- (void) pthread_mutex_unlock(&LOCK_manager);
-
/* kill connection thread */
#if !defined(__WIN__) && !defined(__NETWARE__)
DBUG_PRINT("quit", ("waiting for select thread: 0x%lx",
@@ -1195,6 +1185,7 @@ void clean_up(bool print_message)
if (cleanup_done++)
return; /* purecov: inspected */
+ stop_handle_manager();
release_ddl_log();
/*
@@ -4026,17 +4017,6 @@ server.");
#ifndef EMBEDDED_LIBRARY
-static void create_maintenance_thread()
-{
- if (flush_time && flush_time != ~(ulong) 0L)
- {
- pthread_t hThread;
- if (pthread_create(&hThread,&connection_attrib,handle_manager,0))
- sql_print_warning("Can't create thread to manage maintenance");
- }
-}
-
-
static void create_shutdown_thread()
{
#ifdef __WIN__
@@ -4351,7 +4331,7 @@ we force server id to 2, but this MySQL
execute_ddl_log_recovery();
create_shutdown_thread();
- create_maintenance_thread();
+ start_handle_manager();
if (Events::init(opt_noacl))
unireg_abort(1);
=== modified file 'sql/sql_manager.cc'
--- a/sql/sql_manager.cc 2007-05-10 09:59:39 +0000
+++ b/sql/sql_manager.cc 2008-08-24 01:06:38 +0000
@@ -23,8 +23,9 @@
#include "mysql_priv.h"
-ulong volatile manager_status;
-bool volatile manager_thread_in_use;
+
+static bool volatile manager_thread_in_use;
+static bool abort_manager;
pthread_t manager_thread;
pthread_mutex_t LOCK_manager;
@@ -63,7 +64,6 @@ bool mysql_manager_submit(void (*action)
pthread_handler_t handle_manager(void *arg __attribute__((unused)))
{
int error = 0;
- ulong status;
struct timespec abstime;
bool reset_flush_time = TRUE;
struct handler_cb *cb= NULL;
@@ -72,7 +72,6 @@ pthread_handler_t handle_manager(void *a
pthread_detach_this_thread();
manager_thread = pthread_self();
- manager_status = 0;
manager_thread_in_use = 1;
for (;;)
@@ -87,16 +86,14 @@ pthread_handler_t handle_manager(void *a
set_timespec(abstime, flush_time);
reset_flush_time = FALSE;
}
- while (!manager_status && (!error || error == EINTR) && !abort_loop)
+ while ((!error || error == EINTR) && !abort_manager)
error= pthread_cond_timedwait(&COND_manager, &LOCK_manager, &abstime);
}
else
{
- while (!manager_status && (!error || error == EINTR) && !abort_loop)
+ while ((!error || error == EINTR) && !abort_manager)
error= pthread_cond_wait(&COND_manager, &LOCK_manager);
}
- status = manager_status;
- manager_status = 0;
if (cb == NULL)
{
cb= cb_list;
@@ -104,7 +101,7 @@ pthread_handler_t handle_manager(void *a
}
pthread_mutex_unlock(&LOCK_manager);
- if (abort_loop)
+ if (abort_manager)
break;
if (error == ETIMEDOUT || error == ETIME)
@@ -121,11 +118,42 @@ pthread_handler_t handle_manager(void *a
my_free((uchar*)cb, MYF(0));
cb= next;
}
-
- if (status)
- DBUG_PRINT("error", ("manager did not handle something: %lx", status));
}
manager_thread_in_use = 0;
+ DBUG_LEAVE; // Can't use DBUG_RETURN after my_thread_end
my_thread_end();
- DBUG_RETURN(NULL);
+ return (NULL);
}
+
+
+/* Start handle manager thread */
+void start_handle_manager()
+{
+ DBUG_ENTER("start_handle_manager");
+ abort_manager = false;
+ if (flush_time && flush_time != ~(ulong) 0L)
+ {
+ pthread_t hThread;
+ if (pthread_create(&hThread,&connection_attrib,handle_manager,0))
+ sql_print_warning("Can't create handle_manager thread");
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/* Initiate shutdown of handle manager thread */
+void stop_handle_manager()
+{
+ DBUG_ENTER("stop_handle_manager");
+ abort_manager = true;
+ pthread_mutex_lock(&LOCK_manager);
+ if (manager_thread_in_use)
+ {
+ DBUG_PRINT("quit", ("initiate shutdown of handle manager thread: 0x%lx",
+ (ulong)manager_thread));
+ pthread_cond_signal(&COND_manager);
+ }
+ pthread_mutex_unlock(&LOCK_manager);
+ DBUG_VOID_RETURN;
+}
+
| Thread |
|---|
| • bzr commit into mysql-5.1 branch (vvaintroub:2718) Bug#38522 | Vladislav Vaintroub | 24 Aug |