mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +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:
		
							
								
								
									
										3
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								configure
									
									
									
									
										vendored
									
									
								
							@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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 */
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user