Skip to content

Commit 8dc8310

Browse files
committed
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).
1 parent 05bb4fc commit 8dc8310

File tree

5 files changed

+61
-2
lines changed

5 files changed

+61
-2
lines changed

configure

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19157,7 +19157,8 @@ LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
1915719157

1915819158

1915919159

19160-
for ac_func in cbrt dlopen fcvt fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll pstat readlink scandir setproctitle setsid sigprocmask symlink sysconf towlower utime utimes waitpid wcstombs wcstombs_l
19160+
19161+
for ac_func in cbrt dlopen fcvt fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll pstat pthread_is_threaded_np readlink scandir setproctitle setsid sigprocmask symlink sysconf towlower utime utimes waitpid wcstombs wcstombs_l
1916119162
do
1916219163
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
1916319164
{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5

configure.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1240,7 +1240,7 @@ PGAC_FUNC_GETTIMEOFDAY_1ARG
12401240
LIBS_including_readline="$LIBS"
12411241
LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
12421242

1243-
AC_CHECK_FUNCS([cbrt dlopen fcvt fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll pstat readlink scandir setproctitle setsid sigprocmask symlink sysconf towlower utime utimes waitpid wcstombs wcstombs_l])
1243+
AC_CHECK_FUNCS([cbrt dlopen fcvt fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll pstat pthread_is_threaded_np readlink scandir setproctitle setsid sigprocmask symlink sysconf towlower utime utimes waitpid wcstombs wcstombs_l])
12441244

12451245
AC_REPLACE_FUNCS(fseeko)
12461246
case $host_os in

src/backend/postmaster/postmaster.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@
9292
#include <dns_sd.h>
9393
#endif
9494

95+
#ifdef HAVE_PTHREAD_IS_THREADED_NP
96+
#include <pthread.h>
97+
#endif
98+
9599
#include "access/transam.h"
96100
#include "access/xlog.h"
97101
#include "bootstrap/bootstrap.h"
@@ -1105,6 +1109,24 @@ PostmasterMain(int argc, char *argv[])
11051109
*/
11061110
RemovePgTempFiles();
11071111

1112+
#ifdef HAVE_PTHREAD_IS_THREADED_NP
1113+
1114+
/*
1115+
* On Darwin, libintl replaces setlocale() with a version that calls
1116+
* CFLocaleCopyCurrent() when its second argument is "" and every relevant
1117+
* environment variable is unset or empty. CFLocaleCopyCurrent() makes
1118+
* the process multithreaded. The postmaster calls sigprocmask() and
1119+
* calls fork() without an immediate exec(), both of which have undefined
1120+
* behavior in a multithreaded program. A multithreaded postmaster is the
1121+
* normal case on Windows, which offers neither fork() nor sigprocmask().
1122+
*/
1123+
if (pthread_is_threaded_np() != 0)
1124+
ereport(LOG,
1125+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1126+
errmsg("postmaster became multithreaded during startup"),
1127+
errhint("Set the LC_ALL environment variable to a valid locale.")));
1128+
#endif
1129+
11081130
/*
11091131
* Remember postmaster startup time
11101132
*/
@@ -1535,6 +1557,15 @@ ServerLoop(void)
15351557
TouchSocketLockFile();
15361558
last_touch_time = now;
15371559
}
1560+
1561+
#ifdef HAVE_PTHREAD_IS_THREADED_NP
1562+
1563+
/*
1564+
* With assertions enabled, check regularly for appearance of
1565+
* additional threads. All builds check at start and exit.
1566+
*/
1567+
Assert(pthread_is_threaded_np() == 0);
1568+
#endif
15381569
}
15391570
}
15401571

@@ -4209,6 +4240,18 @@ SubPostmasterMain(int argc, char *argv[])
42094240
static void
42104241
ExitPostmaster(int status)
42114242
{
4243+
#ifdef HAVE_PTHREAD_IS_THREADED_NP
4244+
4245+
/*
4246+
* There is no known cause for a postmaster to become multithreaded after
4247+
* startup. Recheck to account for the possibility of unknown causes.
4248+
*/
4249+
if (pthread_is_threaded_np() != 0)
4250+
ereport(LOG,
4251+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
4252+
errmsg("postmaster became multithreaded")));
4253+
#endif
4254+
42124255
/* should cleanup shared memory and kill all backends */
42134256

42144257
/*

src/include/pg_config.h.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,9 @@
393393
/* Define if you have POSIX threads libraries and header files. */
394394
#undef HAVE_PTHREAD
395395

396+
/* Define to 1 if you have the `pthread_is_threaded_np' function. */
397+
#undef HAVE_PTHREAD_IS_THREADED_NP
398+
396399
/* Define to 1 if you have the <pwd.h> header file. */
397400
#undef HAVE_PWD_H
398401

src/port/exec.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,8 +570,20 @@ set_pglocale_pgservice(const char *argv0, const char *app)
570570

571571
/* don't set LC_ALL in the backend */
572572
if (strcmp(app, PG_TEXTDOMAIN("postgres")) != 0)
573+
{
573574
setlocale(LC_ALL, "");
574575

576+
/*
577+
* One could make a case for reproducing here PostmasterMain()'s test
578+
* for whether the process is multithreaded. Unlike the postmaster,
579+
* no frontend program calls sigprocmask() or otherwise provides for
580+
* mutual exclusion between signal handlers. While frontends using
581+
* fork(), if multithreaded, are formally exposed to undefined
582+
* behavior, we have not witnessed a concrete bug. Therefore,
583+
* complaining about multithreading here may be mere pedantry.
584+
*/
585+
}
586+
575587
if (find_my_exec(argv0, my_exec_path) < 0)
576588
return;
577589

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy