From 69c834c081d7e7ce063ee6b2bbad85b849680bf4 Mon Sep 17 00:00:00 2001 From: Roavin Date: Sun, 9 Feb 2025 22:27:27 +0100 Subject: [PATCH 1/2] Ensure MySQL is only initialized once --- dbdimp.c | 17 ++++++++++++++++- dbdimp.h | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/dbdimp.c b/dbdimp.c index 39db0336..35ebaabc 100644 --- a/dbdimp.c +++ b/dbdimp.c @@ -57,6 +57,21 @@ 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 in Apache MPM workers. +*/ +pthread_once_t once_mysql_initialized = PTHREAD_ONCE_INIT; + +static void init_mysql_library(void) +{ + mysql_library_init(0, NULL, NULL); +} + +static void ensure_mysql_initialized() +{ + pthread_once(&once_mysql_initialized, init_mysql_library); +} /* @@ -1206,7 +1221,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..ec208da6 100644 --- a/dbdimp.h +++ b/dbdimp.h @@ -22,7 +22,7 @@ #include /* Comes with MySQL-devel */ #include /* Comes MySQL */ #include /* Comes with MySQL-devel */ - +#include #define true 1 #define false 0 From 1d09c3f6951aa82fedce0adcedd154cc01a840c9 Mon Sep 17 00:00:00 2001 From: Roavin Date: Fri, 21 Feb 2025 17:27:57 +0100 Subject: [PATCH 2/2] Add Win32 init path --- Makefile.PL | 10 ++++++++++ dbdimp.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- dbdimp.h | 1 - 3 files changed, 52 insertions(+), 4 deletions(-) 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 35ebaabc..470a9b61 100644 --- a/dbdimp.c +++ b/dbdimp.c @@ -59,20 +59,59 @@ typedef struct sql_type_info_s /* Ensure we only call mysql_library_init once, since that is not threadsafe. - Not doing this before had lead to crashes in Apache MPM workers. + Not doing this before had lead to crashes and deadlocks in Apache MPM workers. */ -pthread_once_t once_mysql_initialized = PTHREAD_ONCE_INIT; static void init_mysql_library(void) { mysql_library_init(0, NULL, NULL); } -static void ensure_mysql_initialized() +#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 + /* This function manually counts the number of placeholders in an SQL statement, diff --git a/dbdimp.h b/dbdimp.h index ec208da6..c08142ab 100644 --- a/dbdimp.h +++ b/dbdimp.h @@ -22,7 +22,6 @@ #include /* Comes with MySQL-devel */ #include /* Comes MySQL */ #include /* Comes with MySQL-devel */ -#include #define true 1 #define false 0