]> granicus.if.org Git - postgresql/commitdiff
On Darwin, detect and report a multithreaded postmaster.
authorNoah Misch <noah@leadboat.com>
Thu, 8 Jan 2015 03:35:44 +0000 (22:35 -0500)
committerNoah Misch <noah@leadboat.com>
Thu, 8 Jan 2015 03:36:35 +0000 (22:36 -0500)
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).

configure
configure.in
src/backend/postmaster/postmaster.c
src/common/exec.c
src/include/pg_config.h.in

index 7e6b0faa474d6abd9aaa404b6f360d68437005f8..a75927cd00db67cde4960684764fe35496c3bab9 100755 (executable)
--- a/configure
+++ b/configure
@@ -11301,7 +11301,7 @@ fi
 LIBS_including_readline="$LIBS"
 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 shm_open 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 shm_open 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`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
index 349d4ddaf345be6f874f4204ced2fecffcad3a16..882d542b701fc23502395363157597b90096ee6a 100644 (file)
@@ -1280,7 +1280,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 shm_open 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 shm_open sigprocmask symlink sync_file_range towlower utime utimes wcstombs wcstombs_l])
 
 AC_REPLACE_FUNCS(fseeko)
 case $host_os in
index 268ef0036ed6b6642a23594d2aadb10208ca9438..460ef9f5dc3afe9780d3c100a89f3a1ed3025d9f 100644 (file)
 #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"
@@ -1203,6 +1207,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
         */
@@ -1660,6 +1682,15 @@ ServerLoop(void)
                        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
+
                /*
                 * If we already sent SIGQUIT to children and they are slow to shut
                 * down, it's time to send them SIGKILL.  This doesn't happen
@@ -4738,6 +4769,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 */
 
        /*
index 037bef2210cc4a8923e30eefc88220db3c2ab9f8..cdf20a60af25b94d8f9abba3dc4750ca55c3d393 100644 (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;
 
index d30a2a701b063fd1cf566b974958f9b9edcd3e10..6ce59076422484df2613e97e3d6aa5c184bdd0fb 100644 (file)
 /* 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