diff --git a/src/interfaces/ecpg/ecpglib/misc.c b/src/interfaces/ecpg/ecpglib/misc.c index 8b9aefcd9cd..2ae989e3e5d 100644 --- a/src/interfaces/ecpg/ecpglib/misc.c +++ b/src/interfaces/ecpg/ecpglib/misc.c @@ -60,7 +60,7 @@ static pthread_once_t sqlca_key_once = PTHREAD_ONCE_INIT; static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t debug_init_mutex = PTHREAD_MUTEX_INITIALIZER; -static int simple_debug = 0; +static volatile int simple_debug = 0; static FILE *debugstream = NULL; void @@ -203,8 +203,12 @@ ECPGtrans(int lineno, const char *connection_name, const char *transaction) void ECPGdebug(int n, FILE *dbgs) { + /* Interlock against concurrent executions of ECPGdebug() */ pthread_mutex_lock(&debug_init_mutex); + /* Prevent ecpg_log() from printing while we change settings */ + pthread_mutex_lock(&debug_mutex); + if (n > 100) { ecpg_internal_regression_mode = true; @@ -215,6 +219,10 @@ ECPGdebug(int n, FILE *dbgs) debugstream = dbgs; + /* We must release debug_mutex before invoking ecpg_log() ... */ + pthread_mutex_unlock(&debug_mutex); + + /* ... but keep holding debug_init_mutex to avoid racy printout */ ecpg_log("ECPGdebug: set to %d\n", simple_debug); pthread_mutex_unlock(&debug_init_mutex); @@ -229,6 +237,11 @@ ecpg_log(const char *format,...) int bufsize; char *fmt; + /* + * For performance reasons, inspect simple_debug without taking the mutex. + * This could be problematic if fetching an int isn't atomic, but we + * assume that it is in many other places too. + */ if (!simple_debug) return; @@ -251,18 +264,22 @@ ecpg_log(const char *format,...) pthread_mutex_lock(&debug_mutex); - va_start(ap, format); - vfprintf(debugstream, fmt, ap); - va_end(ap); - - /* dump out internal sqlca variables */ - if (ecpg_internal_regression_mode && sqlca != NULL) + /* Now that we hold the mutex, recheck simple_debug */ + if (simple_debug) { - fprintf(debugstream, "[NO_PID]: sqlca: code: %ld, state: %s\n", - sqlca->sqlcode, sqlca->sqlstate); - } + va_start(ap, format); + vfprintf(debugstream, fmt, ap); + va_end(ap); - fflush(debugstream); + /* dump out internal sqlca variables */ + if (ecpg_internal_regression_mode && sqlca != NULL) + { + fprintf(debugstream, "[NO_PID]: sqlca: code: %ld, state: %s\n", + sqlca->sqlcode, sqlca->sqlstate); + } + + fflush(debugstream); + } pthread_mutex_unlock(&debug_mutex);