diff --git a/Makefile.PL b/Makefile.PL index 3d707231..c3abe11f 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -198,6 +198,16 @@ if ($^O eq 'VMS') { } $cflags .= " -DDBD_MYSQL_NO_CLIENT_FOUND_ROWS" if $opt->{'nofoundrows'}; $cflags .= " -g "; + +unless ($^O eq 'MSWin32') { + if ($Config{usethreads} || $Config{osname} =~ /darwin|linux/i || $Config{libs} =~ /-l?pthread\b/ || $Config{ldflags} =~ /-l?pthread\b/) { + $cflags .= " -DDBD_MYSQL_HAS_PTHREADS"; + } else { + print "*** This module may crash or deadlock on startup in multi-threaded scenarios ***\n", + " To avoid this, make sure your Perl is compiled with pthreads.\n\n", + } +} + my %o = ( 'NAME' => 'DBD::mysql', 'INC' => $cflags, 'dist'=> { 'SUFFIX' => ".gz", diff --git a/dbdimp.c b/dbdimp.c index 39db0336..470a9b61 100644 --- a/dbdimp.c +++ b/dbdimp.c @@ -57,6 +57,60 @@ typedef struct sql_type_info_s int is_num; } sql_type_info_t; +/* + Ensure we only call mysql_library_init once, since that is not threadsafe. + Not doing this before had lead to crashes and deadlocks in Apache MPM workers. +*/ + +static void init_mysql_library(void) +{ + mysql_library_init(0, NULL, NULL); +} + +#ifdef DBD_MYSQL_HAS_PTHREADS + +#include +static pthread_once_t once_mysql_initialized = PTHREAD_ONCE_INIT; + +static void ensure_mysql_initialized(void) +{ + pthread_once(&once_mysql_initialized, init_mysql_library); +} + +#elif defined(_WIN32) + +#define WIN32_LEAN_AND_MEAN +#include +static INIT_ONCE once_mysql_initialized = INIT_ONCE_STATIC_INIT; + +static BOOL init_mysql_library_thunk(PINIT_ONCE once, PVOID param, PVOID *context) +{ + init_mysql_library(); + return TRUE; +} + +static void ensure_mysql_initialized(void) +{ + InitOnceExecuteOnce(&once_mysql_initialized, init_mysql_library_thunk, NULL, NULL); +} + +#else +static int is_mysql_initialized = 0; + +static void ensure_mysql_initialized(void) +{ + /* Thread-unsafe fallback + * In practice, this will only be used for perls not compiled with threads + * anyway, so it's very unlikely that this would be a problem. + */ + if (!is_mysql_initialized) + { + is_mysql_initialized = 1; + mysql_library_init(0, NULL, NULL); + } +} + +#endif /* @@ -1206,7 +1260,7 @@ MYSQL *mysql_dr_connect( #else client_flag = CLIENT_FOUND_ROWS; #endif - mysql_library_init(0, NULL, NULL); + ensure_mysql_initialized(); mysql_init(sock); if (imp_dbh) diff --git a/dbdimp.h b/dbdimp.h index 3d8c76b6..c08142ab 100644 --- a/dbdimp.h +++ b/dbdimp.h @@ -23,7 +23,6 @@ #include /* Comes MySQL */ #include /* Comes with MySQL-devel */ - #define true 1 #define false 0