diff --git a/src/interfaces/ecpg/ecpglib/misc.c b/src/interfaces/ecpg/ecpglib/misc.c index 58fff10697d..8b9aefcd9cd 100644 --- a/src/interfaces/ecpg/ecpglib/misc.c +++ b/src/interfaces/ecpg/ecpglib/misc.c @@ -465,13 +465,14 @@ char * ecpg_gettext(const char *msgid) { /* - * If multiple threads come through here at about the same time, it's okay - * for more than one of them to call bindtextdomain(). But it's not okay - * for any of them to reach dgettext() before bindtextdomain() is - * complete, so don't set the flag till that's done. Use "volatile" just - * to be sure the compiler doesn't try to get cute. + * At least on Windows, there are gettext implementations that fail if + * multiple threads call bindtextdomain() concurrently. Use a mutex and + * flag variable to ensure that we call it just once per process. It is + * not known that similar bugs exist on non-Windows platforms, but we + * might as well do it the same way everywhere. */ static volatile bool already_bound = false; + static pthread_mutex_t binddomain_mutex = PTHREAD_MUTEX_INITIALIZER; if (!already_bound) { @@ -481,14 +482,26 @@ ecpg_gettext(const char *msgid) #else int save_errno = errno; #endif - const char *ldir; - /* No relocatable lookup here because the binary could be anywhere */ - ldir = getenv("PGLOCALEDIR"); - if (!ldir) - ldir = LOCALEDIR; - bindtextdomain(PG_TEXTDOMAIN("ecpglib"), ldir); - already_bound = true; + (void) pthread_mutex_lock(&binddomain_mutex); + + if (!already_bound) + { + const char *ldir; + + /* + * No relocatable lookup here because the calling executable could + * be anywhere + */ + ldir = getenv("PGLOCALEDIR"); + if (!ldir) + ldir = LOCALEDIR; + bindtextdomain(PG_TEXTDOMAIN("ecpglib"), ldir); + already_bound = true; + } + + (void) pthread_mutex_unlock(&binddomain_mutex); + #ifdef WIN32 SetLastError(save_errno); #else diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c index 47a28b0a3ab..f2fc78a481c 100644 --- a/src/interfaces/libpq/fe-misc.c +++ b/src/interfaces/libpq/fe-misc.c @@ -1225,13 +1225,14 @@ static void libpq_binddomain(void) { /* - * If multiple threads come through here at about the same time, it's okay - * for more than one of them to call bindtextdomain(). But it's not okay - * for any of them to return to caller before bindtextdomain() is - * complete, so don't set the flag till that's done. Use "volatile" just - * to be sure the compiler doesn't try to get cute. + * At least on Windows, there are gettext implementations that fail if + * multiple threads call bindtextdomain() concurrently. Use a mutex and + * flag variable to ensure that we call it just once per process. It is + * not known that similar bugs exist on non-Windows platforms, but we + * might as well do it the same way everywhere. */ static volatile bool already_bound = false; + static pthread_mutex_t binddomain_mutex = PTHREAD_MUTEX_INITIALIZER; if (!already_bound) { @@ -1241,14 +1242,26 @@ libpq_binddomain(void) #else int save_errno = errno; #endif - const char *ldir; - /* No relocatable lookup here because the binary could be anywhere */ - ldir = getenv("PGLOCALEDIR"); - if (!ldir) - ldir = LOCALEDIR; - bindtextdomain(PG_TEXTDOMAIN("libpq"), ldir); - already_bound = true; + (void) pthread_mutex_lock(&binddomain_mutex); + + if (!already_bound) + { + const char *ldir; + + /* + * No relocatable lookup here because the calling executable could + * be anywhere + */ + ldir = getenv("PGLOCALEDIR"); + if (!ldir) + ldir = LOCALEDIR; + bindtextdomain(PG_TEXTDOMAIN("libpq"), ldir); + already_bound = true; + } + + (void) pthread_mutex_unlock(&binddomain_mutex); + #ifdef WIN32 SetLastError(save_errno); #else