Skip to content

Commit 2e49461

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 3580397 commit 2e49461

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
@@ -18839,7 +18839,8 @@ LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
1883918839

1884018840

1884118841

18842-
for ac_func in cbrt dlopen fcvt fdatasync getifaddrs getpeereid getpeerucred getrlimit memmove poll pstat readlink scandir setproctitle setsid sigprocmask symlink sysconf towlower utime utimes waitpid wcstombs
18842+
18843+
for ac_func in cbrt dlopen fcvt fdatasync getifaddrs getpeereid getpeerucred getrlimit memmove poll pstat pthread_is_threaded_np readlink scandir setproctitle setsid sigprocmask symlink sysconf towlower utime utimes waitpid wcstombs
1884318844
do
1884418845
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
1884518846
{ $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
@@ -1210,7 +1210,7 @@ PGAC_FUNC_GETTIMEOFDAY_1ARG
12101210
LIBS_including_readline="$LIBS"
12111211
LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
12121212

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

12151215
AC_REPLACE_FUNCS(fseeko)
12161216
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"
@@ -1081,6 +1085,24 @@ PostmasterMain(int argc, char *argv[])
10811085
}
10821086
load_ident();
10831087

1088+
#ifdef HAVE_PTHREAD_IS_THREADED_NP
1089+
1090+
/*
1091+
* On Darwin, libintl replaces setlocale() with a version that calls
1092+
* CFLocaleCopyCurrent() when its second argument is "" and every relevant
1093+
* environment variable is unset or empty. CFLocaleCopyCurrent() makes
1094+
* the process multithreaded. The postmaster calls sigprocmask() and
1095+
* calls fork() without an immediate exec(), both of which have undefined
1096+
* behavior in a multithreaded program. A multithreaded postmaster is the
1097+
* normal case on Windows, which offers neither fork() nor sigprocmask().
1098+
*/
1099+
if (pthread_is_threaded_np() != 0)
1100+
ereport(LOG,
1101+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1102+
errmsg("postmaster became multithreaded during startup"),
1103+
errhint("Set the LC_ALL environment variable to a valid locale.")));
1104+
#endif
1105+
10841106
/*
10851107
* Remember postmaster startup time
10861108
*/
@@ -1506,6 +1528,15 @@ ServerLoop(void)
15061528
TouchSocketLockFile();
15071529
last_touch_time = now;
15081530
}
1531+
1532+
#ifdef HAVE_PTHREAD_IS_THREADED_NP
1533+
1534+
/*
1535+
* With assertions enabled, check regularly for appearance of
1536+
* additional threads. All builds check at start and exit.
1537+
*/
1538+
Assert(pthread_is_threaded_np() == 0);
1539+
#endif
15091540
}
15101541
}
15111542

@@ -4155,6 +4186,18 @@ SubPostmasterMain(int argc, char *argv[])
41554186
static void
41564187
ExitPostmaster(int status)
41574188
{
4189+
#ifdef HAVE_PTHREAD_IS_THREADED_NP
4190+
4191+
/*
4192+
* There is no known cause for a postmaster to become multithreaded after
4193+
* startup. Recheck to account for the possibility of unknown causes.
4194+
*/
4195+
if (pthread_is_threaded_np() != 0)
4196+
ereport(LOG,
4197+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
4198+
errmsg("postmaster became multithreaded")));
4199+
#endif
4200+
41584201
/* should cleanup shared memory and kill all backends */
41594202

41604203
/*

src/include/pg_config.h.in

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

390+
/* Define to 1 if you have the `pthread_is_threaded_np' function. */
391+
#undef HAVE_PTHREAD_IS_THREADED_NP
392+
390393
/* Define to 1 if you have the <pwd.h> header file. */
391394
#undef HAVE_PWD_H
392395

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