#At file:///G:/bzr/mysql-6.0-wtf-winthread/
2681 Vladislav Vaintroub 2008-11-24
Cleanup pthread_self(), pthread_create(), pthread_join() implementation on Windows.
Prior implementation is was unnecessarily complicated and even differs in embedded
and non-embedded case.
Improvements in this patch:
* pthread_t is now the unique thread ID, instead of HANDLE returned by beginthread
This simplifies pthread_self() to be just straight GetCurrentThreadId().
prior it was much art involved in passing the beginthread() handle from the caller
to the TLS structure in the child thread ( did not work for the main thread of
course)
* remove MySQL specific my_thread_init()/my_thread_end() from pthread_create.
No automagic is done on Unix on pthread_create(). Having the same on Windows will
improve portability and avoid extra #ifdef's
* remove redefinition of getpid() - it was defined as GetCurrentThreadId()
modified:
include/config-win.h
include/my_pthread.h
mysys/my_thr_init.c
mysys/my_wincond.c
mysys/my_winthread.c
sql/mysqld.cc
sql/sql_connect.cc
sql/sql_insert.cc
per-file messages:
include/config-win.h
Include <process.h> for getpid()
include/my_pthread.h
- change pthread_t to be a real (OS) thread id, not handle
- remove win_pthread_init
- change pthread_yield from Sleep(0) to SwitchToThread(),
as Sleep(0) does yield to threads of lower priority
mysys/my_thr_init.c
- remove win_pthread_init()
- install per-thread SIGABRT handler in my_pthread_init
mysys/my_wincond.c
remove #undef getpid
mysys/my_winthread.c
- Simplify implementation of pthread_create and make it independent
of EMBEDDED_LIBRARY defintion
sql/mysqld.cc
- when handle_connections_sockets is run in a thread different from
the main thread, it needs my_thread_init.
- Windows specific sigabrt handler initialization moved to my_thread_init
- fix warning (not all control paths return value from win_main)
sql/sql_connect.cc
Code for SIGABRT handler moved to my_thread_init()
sql/sql_insert.cc
my_thread_init() was not called for windows.
=== modified file 'include/config-win.h'
--- a/include/config-win.h 2008-07-23 08:52:08 +0000
+++ b/include/config-win.h 2008-11-24 15:30:37 +0000
@@ -37,6 +37,7 @@
#include <io.h>
#include <malloc.h>
#include <sys/stat.h>
+#include <process.h> /* getpid()*/
#define HAVE_SMEM 1
=== modified file 'include/my_pthread.h'
--- a/include/my_pthread.h 2008-11-12 01:37:42 +0000
+++ b/include/my_pthread.h 2008-11-24 15:30:37 +0000
@@ -31,7 +31,7 @@ extern "C" {
#if defined(__WIN__)
typedef CRITICAL_SECTION pthread_mutex_t;
-typedef HANDLE pthread_t;
+typedef DWORD pthread_t;
typedef struct thread_attr {
DWORD dwStackSize ;
DWORD dwCreatingFlag ;
@@ -63,8 +63,7 @@ typedef struct {
typedef int pthread_mutexattr_t;
-#define win_pthread_self my_thread_var->pthread_self
-#define pthread_self() win_pthread_self
+#define pthread_self() GetCurrentThreadId()
#define pthread_handler_t EXTERNC void * __cdecl
typedef void * (__cdecl *pthread_handler)(void *);
@@ -100,7 +99,7 @@ struct timespec {
set_timespec_time_nsec((ABSTIME), tv.i64, (NSEC)); \
} while(0)
-void win_pthread_init(void);
+
int win_pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_create(pthread_t *,pthread_attr_t *,pthread_handler,void *);
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
@@ -116,11 +115,11 @@ int pthread_attr_destroy(pthread_attr_t
struct tm *localtime_r(const time_t *timep,struct tm *tmp);
struct tm *gmtime_r(const time_t *timep,struct tm *tmp);
+void pthread_exit(void *a);
+int pthread_join(pthread_t thread, void **value_ptr);
-void pthread_exit(void *a); /* was #define pthread_exit(A) ExitThread(A)*/
#define ETIMEDOUT 145 /* Win32 doesn't have this */
-#define getpid() GetCurrentThreadId()
#define HAVE_LOCALTIME_R 1
#define _REENTRANT 1
#define HAVE_PTHREAD_ATTR_SETSTACKSIZE 1
@@ -144,7 +143,6 @@ void pthread_exit(void *a); /* was #def
#define pthread_mutex_destroy(A) DeleteCriticalSection(A)
#define pthread_kill(A,B) pthread_dummy((A) ? 0 : ESRCH)
-#define pthread_join(A,B) (WaitForSingleObject((A), INFINITE) != WAIT_OBJECT_0)
/* Dummy defines for easier code */
#define pthread_attr_setdetachstate(A,B) pthread_dummy(0)
@@ -152,10 +150,8 @@ void pthread_exit(void *a); /* was #def
#define pthread_detach_this_thread()
#define pthread_condattr_init(A)
#define pthread_condattr_destroy(A)
-#define pthread_yield() Sleep(0) /* according to MSDN */
+#define pthread_yield() SwitchToThread()
-/* per the platform's documentation */
-#define pthread_yield() Sleep(0)
#else /* Normal threads */
=== modified file 'mysys/my_thr_init.c'
--- a/mysys/my_thr_init.c 2008-10-31 18:02:34 +0000
+++ b/mysys/my_thr_init.c 2008-11-24 15:30:37 +0000
@@ -47,7 +47,9 @@ pthread_mutexattr_t my_fast_mutexattr;
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
pthread_mutexattr_t my_errorcheck_mutexattr;
#endif
-
+#ifdef _MSC_VER
+static void install_sigabrt_handler();
+#endif
#ifdef TARGET_OS_LINUX
/*
@@ -151,9 +153,7 @@ my_bool my_thread_global_init(void)
pthread_mutex_init(&THR_LOCK_threads,MY_MUTEX_INIT_FAST);
pthread_mutex_init(&THR_LOCK_time,MY_MUTEX_INIT_FAST);
pthread_cond_init(&THR_COND_threads, NULL);
-#if defined( __WIN__) || defined(OS2)
- win_pthread_init();
-#endif
+
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
pthread_mutex_init(&LOCK_localtime_r,MY_MUTEX_INIT_SLOW);
#endif
@@ -269,17 +269,18 @@ my_bool my_thread_init(void)
#endif
goto end;
}
+
+#ifdef _MSC_VER
+ install_sigabrt_handler();
+#endif
+
if (!(tmp= (struct st_my_thread_var *) calloc(1, sizeof(*tmp))))
{
error= 1;
goto end;
}
pthread_setspecific(THR_KEY_mysys,tmp);
-#if defined(__WIN__) && defined(EMBEDDED_LIBRARY)
- tmp->pthread_self= (pthread_t) getpid();
-#else
tmp->pthread_self= pthread_self();
-#endif
pthread_mutex_init(&tmp->mutex,MY_MUTEX_INIT_FAST);
pthread_cond_init(&tmp->suspend, NULL);
@@ -426,4 +427,30 @@ static uint get_thread_lib(void)
return THD_LIB_OTHER;
}
+#ifdef _WIN32
+/*
+ In Visual Studio 2005 and later, default SIGABRT handler will overwrite
+ any unhandled exception filter set by the application and will try to
+ call JIT debugger. This is not what we want, this we calling __debugbreak
+ to stop in debugger, if process is being debugged or to generate
+ EXCEPTION_BREAKPOINT and then handle_segfault will do its magic.
+*/
+
+#if (_MSC_VER >= 1400)
+static void my_sigabrt_handler(int sig)
+{
+ __debugbreak();
+}
+#endif /*_MSC_VER >=1400 */
+
+static void install_sigabrt_handler(void)
+{
+#if (_MSC_VER >=1400)
+ /*abort() should not override our exception filter*/
+ _set_abort_behavior(0,_CALL_REPORTFAULT);
+ signal(SIGABRT,my_sigabrt_handler);
+#endif /* _MSC_VER >=1400 */
+}
+#endif
+
#endif /* THREAD */
=== modified file 'mysys/my_wincond.c'
--- a/mysys/my_wincond.c 2008-11-06 18:39:27 +0000
+++ b/mysys/my_wincond.c 2008-11-24 15:30:37 +0000
@@ -16,12 +16,11 @@
/*****************************************************************************
** The following is a simple implementation of posix conditions
*****************************************************************************/
+#if defined(_WIN32)
#undef SAFE_MUTEX /* Avoid safe_mutex redefinitions */
#include "mysys_priv.h"
-#if defined(THREAD) && defined(__WIN__)
#include <m_string.h>
-#undef getpid
#include <process.h>
#include <sys/timeb.h>
=== modified file 'mysys/my_winthread.c'
--- a/mysys/my_winthread.c 2008-11-12 01:37:42 +0000
+++ b/mysys/my_winthread.c 2008-11-24 15:30:37 +0000
@@ -14,33 +14,23 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*****************************************************************************
-** Simulation of posix threads calls for WIN95 and NT
+** Simulation of posix threads calls for Windows
*****************************************************************************/
-
+#if defined (_WIN32)
/* SAFE_MUTEX will not work until the thread structure is up to date */
#undef SAFE_MUTEX
-
#include "mysys_priv.h"
-#if defined(THREAD) && defined(__WIN__)
-#include <m_string.h>
-#undef getpid
#include <process.h>
+#include <signal.h>
-static pthread_mutex_t THR_LOCK_thread;
+static void install_sigabrt_handler(void);
-struct pthread_map
+struct thread_start_parameter
{
- HANDLE pthreadself;
pthread_handler func;
- void *param;
+ void *arg;
};
-void win_pthread_init(void)
-{
- pthread_mutex_init(&THR_LOCK_thread,MY_MUTEX_INIT_FAST);
-}
-
-
/**
Adapter to @c pthread_mutex_trylock()
@@ -62,79 +52,81 @@ win_pthread_mutex_trylock(pthread_mutex_
return EBUSY;
}
-
-/*
-** We have tried to use '_beginthreadex' instead of '_beginthread' here
-** but in this case the program leaks about 512 characters for each
-** created thread !
-** As we want to save the created thread handler for other threads to
-** use and to be returned by pthread_self() (instead of the Win32 pseudo
-** handler), we have to go trough pthread_start() to catch the returned handler
-** in the new thread.
-*/
-
-pthread_handler_t pthread_start(void *param)
-{
- pthread_handler func=((struct pthread_map *) param)->func;
- void *func_param=((struct pthread_map *) param)->param;
- void *result;
- my_thread_init(); /* Will always succeed in windows */
- pthread_mutex_lock(&THR_LOCK_thread); /* Wait for beginthread to return */
- win_pthread_self=((struct pthread_map *) param)->pthreadself;
- pthread_mutex_unlock(&THR_LOCK_thread);
- free((char*) param); /* Free param from create */
- result= (void*) (*func)(func_param);
- my_thread_end();
- pthread_exit(result);
- return 0; /* Safety */
+static unsigned int __stdcall pthread_start(void *p)
+{
+ struct thread_start_parameter *par= (struct thread_start_parameter *)p;
+ pthread_handler func= par->func;
+ void *arg= par->arg;
+ free(p);
+ (*func)(arg);
+ return 0;
}
int pthread_create(pthread_t *thread_id, pthread_attr_t *attr,
- pthread_handler func, void *param)
+ pthread_handler func, void *param)
{
- HANDLE hThread;
- struct pthread_map *map;
- DWORD StackSize= 0;
+ uintptr_t handle;
+ struct thread_start_parameter *par;
+ unsigned int stack_size;
DBUG_ENTER("pthread_create");
- if (!(map=malloc(sizeof(*map))))
- DBUG_RETURN(-1);
- map->func=func;
- map->param=param;
- if (attr != NULL)
- {
- StackSize= attr->dwStackSize;
- }
- if (StackSize == 0)
- StackSize= PTHREAD_STACK_MIN;
- pthread_mutex_lock(&THR_LOCK_thread);
-#ifdef __BORLANDC__
- hThread=(HANDLE)_beginthread((void(_USERENTRY *)(void *)) pthread_start,
- StackSize, (void*) map);
-#else
- hThread=(HANDLE)_beginthread((void( __cdecl *)(void *)) pthread_start,
- StackSize, (void*) map);
-#endif
- DBUG_PRINT("info", ("hThread=%lu",(long) hThread));
- *thread_id=map->pthreadself=hThread;
- pthread_mutex_unlock(&THR_LOCK_thread);
+ par= (struct thread_start_parameter *)malloc(sizeof(*par));
+ if (!par)
+ goto error_return;
+
+ par->func= func;
+ par->arg= param;
+ stack_size= attr?attr->dwStackSize:0;
+
+ handle= _beginthreadex(NULL, stack_size , pthread_start, par, 0, thread_id);
+ if (!handle)
+ goto error_return;
+ DBUG_PRINT("info", ("thread id=%u",*thread_id));
- if (hThread == (HANDLE) -1)
- {
- int error=errno;
- DBUG_PRINT("error",
- ("Can't create thread to handle request (error %d)",error));
- DBUG_RETURN(error ? error : -1);
- }
+ /* Do not need thread handle, close it */
+ CloseHandle((HANDLE)handle);
DBUG_RETURN(0);
+
+error_return:
+ DBUG_PRINT("error",
+ ("Can't create thread to handle request (error %d)",errno));
+ DBUG_RETURN(-1);
}
void pthread_exit(void *a)
{
- _endthread();
+ _endthreadex(0);
}
+int pthread_join(pthread_t thread, void **value_ptr)
+{
+ DWORD ret;
+ HANDLE handle;
+
+ handle= OpenThread(SYNCHRONIZE, FALSE, thread);
+ if (!handle)
+ {
+ errno= EINVAL;
+ goto error_return;
+ }
+
+ ret= WaitForSingleObject(handle, INFINITE);
+
+ if(ret != WAIT_OBJECT_0)
+ {
+ errno= EINVAL;
+ goto error_return;
+ }
+
+ CloseHandle(handle);
+ return 0;
+
+error_return:
+ if(handle)
+ CloseHandle(handle);
+ return -1;
+}
#endif
=== modified file 'sql/mysqld.cc'
--- a/sql/mysqld.cc 2008-11-15 17:02:01 +0000
+++ b/sql/mysqld.cc 2008-11-24 15:30:37 +0000
@@ -841,7 +841,10 @@ static void set_server_version(void);
static int init_thread_environment();
static char *get_relative_path(const char *path);
static void fix_paths(void);
-pthread_handler_t handle_connections_sockets(void *arg);
+void handle_connections_sockets();
+#ifdef _WIN32
+pthread_handler_t handle_connections_sockets_thread(void *arg);
+#endif
pthread_handler_t kill_server_thread(void *arg);
static void bootstrap(FILE *file);
static bool read_init_file(char *file_name);
@@ -2129,29 +2132,6 @@ static BOOL WINAPI console_event_handler
}
-/*
- In Visual Studio 2005 and later, default SIGABRT handler will overwrite
- any unhandled exception filter set by the application and will try to
- call JIT debugger. This is not what we want, this we calling __debugbreak
- to stop in debugger, if process is being debugged or to generate
- EXCEPTION_BREAKPOINT and then handle_segfault will do its magic.
-*/
-
-#if (_MSC_VER >= 1400)
-static void my_sigabrt_handler(int sig)
-{
- __debugbreak();
-}
-#endif /*_MSC_VER >=1400 */
-
-void win_install_sigabrt_handler(void)
-{
-#if (_MSC_VER >=1400)
- /*abort() should not override our exception filter*/
- _set_abort_behavior(0,_CALL_REPORTFAULT);
- signal(SIGABRT,my_sigabrt_handler);
-#endif /* _MSC_VER >=1400 */
-}
#ifdef DEBUG_UNHANDLED_EXCEPTION_FILTER
#define DEBUGGER_ATTACH_TIMEOUT 120
@@ -2230,7 +2210,6 @@ LONG WINAPI my_unhandler_exception_filte
static void init_signals(void)
{
- win_install_sigabrt_handler();
if(opt_console)
SetConsoleCtrlHandler(console_event_handler,TRUE);
else
@@ -4401,8 +4380,8 @@ static void handle_connections_methods()
if (have_tcpip && !opt_disable_networking)
{
handler_count++;
- if (pthread_create(&hThread,&connection_attrib,
- handle_connections_sockets, 0))
+ if (pthread_create(&hThread,&connection_attrib,
+ handle_connections_sockets_thread, 0))
{
sql_print_warning("Can't create thread to handle TCP/IP");
handler_count--;
@@ -4678,14 +4657,7 @@ int main(int argc, char **argv)
#if defined(_WIN32) || defined(HAVE_SMEM)
handle_connections_methods();
#else
-#ifdef __WIN__
- if (!have_tcpip || opt_disable_networking)
- {
- sql_print_error("TCP/IP unavailable or disabled with --skip-networking; no available
interfaces");
- unireg_abort(1);
- }
-#endif
- handle_connections_sockets(0);
+ handle_connections_sockets();
#endif /* _WIN32 || HAVE_SMEM */
/* (void) pthread_attr_destroy(&connection_attrib); */
@@ -4724,6 +4696,7 @@ int main(int argc, char **argv)
#endif
clean_up(1);
mysqld_exit(0);
+ return 0; /* purecov: inspected */
}
#endif /* !EMBEDDED_LIBRARY */
@@ -5137,7 +5110,8 @@ inline void kill_broken_server()
/* Handle new connections and spawn new process to handle them */
#ifndef EMBEDDED_LIBRARY
-pthread_handler_t handle_connections_sockets(void *arg __attribute__((unused)))
+
+void handle_connections_sockets()
{
my_socket sock,new_sock;
uint error_count=0;
@@ -5339,13 +5313,19 @@ pthread_handler_t handle_connections_soc
create_new_thread(thd);
}
-
- decrement_handler_count();
- DBUG_RETURN(0);
+ DBUG_VOID_RETURN;
}
#ifdef _WIN32
+pthread_handler_t handle_connections_sockets_thread(void *arg)
+{
+ my_thread_init();
+ handle_connections_sockets();
+ decrement_handler_count();
+ return 0;
+}
+
pthread_handler_t handle_connections_namedpipes(void *arg)
{
HANDLE hConnectedPipe;
=== modified file 'sql/sql_connect.cc'
--- a/sql/sql_connect.cc 2008-10-17 17:47:16 +0000
+++ b/sql/sql_connect.cc 2008-11-24 15:30:37 +0000
@@ -39,10 +39,6 @@
#define MIN_HANDSHAKE_SIZE 6
#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
-#ifdef __WIN__
-extern void win_install_sigabrt_handler();
-#endif
-
/*
Get structure for logging connection data for the current user
*/
@@ -636,13 +632,8 @@ void thd_init_client_charset(THD *thd, u
bool init_new_connection_handler_thread()
{
pthread_detach_this_thread();
-#if defined(__WIN__)
- win_install_sigabrt_handler();
-#else
- /* Win32 calls this in pthread_create */
if (my_thread_init())
return 1;
-#endif /* __WIN__ */
return 0;
}
=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc 2008-11-06 18:39:27 +0000
+++ b/sql/sql_insert.cc 2008-11-24 15:30:37 +0000
@@ -2344,7 +2344,6 @@ pthread_handler_t handle_delayed_insert(
since it does not find one in the list.
*/
pthread_mutex_lock(&di->mutex);
-#if !defined( __WIN__) /* Win32 calls this in pthread_create */
if (my_thread_init())
{
/* Can't use my_error since store_globals has not yet been called */
@@ -2352,8 +2351,6 @@ pthread_handler_t handle_delayed_insert(
ER(ER_OUT_OF_RESOURCES));
goto end;
}
-#endif
-
DBUG_ENTER("handle_delayed_insert");
thd->thread_stack= (char*) &thd;
if (init_thr_lock() || thd->store_globals())
@@ -2544,9 +2541,7 @@ err:
*/
trans_rollback_stmt(thd);
-#ifndef __WIN__
end:
-#endif
/*
di should be unlinked from the thread handler list and have no active
clients
| Thread |
|---|
| • bzr commit into mysql-6.0 branch (vvaintroub:2681) | Vladislav Vaintroub | 24 Nov |