1
0
mirror of https://github.com/postgres/postgres.git synced 2025-05-09 18:21:05 +03:00

On Darwin, detect and report a multithreaded postmaster.

Darwin --enable-nls builds use a substitute setlocale() that may start a
thread.  Buildfarm member orangutan experienced BackendList corruption
on account of different postmaster threads executing signal handlers
simultaneously.  Furthermore, a multithreaded postmaster risks undefined
behavior from sigprocmask() and fork().  Emit LOG messages about the
problem and its workaround.  Back-patch to 9.0 (all supported versions).
This commit is contained in:
Noah Misch 2015-01-07 22:35:44 -05:00
parent 230865e308
commit 1a366d51ef
5 changed files with 61 additions and 2 deletions

3
configure vendored
View File

@ -19833,7 +19833,8 @@ LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
for ac_func in cbrt dlopen fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll pstat readlink setproctitle setsid sigprocmask symlink sync_file_range towlower utime utimes wcstombs wcstombs_l
for ac_func in cbrt dlopen fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll pstat pthread_is_threaded_np readlink setproctitle setsid sigprocmask symlink sync_file_range towlower utime utimes wcstombs wcstombs_l
do
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5

View File

@ -1259,7 +1259,7 @@ PGAC_FUNC_GETTIMEOFDAY_1ARG
LIBS_including_readline="$LIBS"
LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
AC_CHECK_FUNCS([cbrt dlopen fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll pstat readlink setproctitle setsid sigprocmask symlink sync_file_range towlower utime utimes wcstombs wcstombs_l])
AC_CHECK_FUNCS([cbrt dlopen fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll pstat pthread_is_threaded_np readlink setproctitle setsid sigprocmask symlink sync_file_range towlower utime utimes wcstombs wcstombs_l])
AC_REPLACE_FUNCS(fseeko)
case $host_os in

View File

@ -91,6 +91,10 @@
#include <dns_sd.h>
#endif
#ifdef HAVE_PTHREAD_IS_THREADED_NP
#include <pthread.h>
#endif
#include "access/transam.h"
#include "access/xlog.h"
#include "bootstrap/bootstrap.h"
@ -1233,6 +1237,24 @@ PostmasterMain(int argc, char *argv[])
*/
RemovePgTempFiles();
#ifdef HAVE_PTHREAD_IS_THREADED_NP
/*
* On Darwin, libintl replaces setlocale() with a version that calls
* CFLocaleCopyCurrent() when its second argument is "" and every relevant
* environment variable is unset or empty. CFLocaleCopyCurrent() makes
* the process multithreaded. The postmaster calls sigprocmask() and
* calls fork() without an immediate exec(), both of which have undefined
* behavior in a multithreaded program. A multithreaded postmaster is the
* normal case on Windows, which offers neither fork() nor sigprocmask().
*/
if (pthread_is_threaded_np() != 0)
ereport(LOG,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("postmaster became multithreaded during startup"),
errhint("Set the LC_ALL environment variable to a valid locale.")));
#endif
/*
* Remember postmaster startup time
*/
@ -1675,6 +1697,15 @@ ServerLoop(void)
TouchSocketLockFiles();
last_touch_time = now;
}
#ifdef HAVE_PTHREAD_IS_THREADED_NP
/*
* With assertions enabled, check regularly for appearance of
* additional threads. All builds check at start and exit.
*/
Assert(pthread_is_threaded_np() == 0);
#endif
}
}
@ -4632,6 +4663,18 @@ SubPostmasterMain(int argc, char *argv[])
static void
ExitPostmaster(int status)
{
#ifdef HAVE_PTHREAD_IS_THREADED_NP
/*
* There is no known cause for a postmaster to become multithreaded after
* startup. Recheck to account for the possibility of unknown causes.
*/
if (pthread_is_threaded_np() != 0)
ereport(LOG,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("postmaster became multithreaded")));
#endif
/* should cleanup shared memory and kill all backends */
/*

View File

@ -387,6 +387,9 @@
/* Define if you have POSIX threads libraries and header files. */
#undef HAVE_PTHREAD
/* Define to 1 if you have the `pthread_is_threaded_np' function. */
#undef HAVE_PTHREAD_IS_THREADED_NP
/* Define to 1 if you have the <pwd.h> header file. */
#undef HAVE_PWD_H

View File

@ -556,8 +556,20 @@ set_pglocale_pgservice(const char *argv0, const char *app)
/* don't set LC_ALL in the backend */
if (strcmp(app, PG_TEXTDOMAIN("postgres")) != 0)
{
setlocale(LC_ALL, "");
/*
* One could make a case for reproducing here PostmasterMain()'s test
* for whether the process is multithreaded. Unlike the postmaster,
* no frontend program calls sigprocmask() or otherwise provides for
* mutual exclusion between signal handlers. While frontends using
* fork(), if multithreaded, are formally exposed to undefined
* behavior, we have not witnessed a concrete bug. Therefore,
* complaining about multithreading here may be mere pedantry.
*/
}
if (find_my_exec(argv0, my_exec_path) < 0)
return;