From 164adc4d3924d5f0310dba24d4035313ca69245d Mon Sep 17 00:00:00 2001
From: Neil Conway <neilc@samurai.com>
Date: Thu, 10 Mar 2005 07:14:03 +0000
Subject: [PATCH] Refactor fork()-related code. We need to do various
 housekeeping tasks before we can invoke fork() -- flush stdio buffers, save
 and restore the profiling timer on Linux with LINUX_PROFILE, and handle BeOS
 stuff. This patch moves that code into a single function, fork_process(),
 instead of duplicating it at the various callsites of fork().

This patch doesn't address the EXEC_BACKEND case; there is room for
further cleanup there.
---
 src/backend/port/beos/support.c       |   2 +-
 src/backend/postmaster/Makefile       |   4 +-
 src/backend/postmaster/fork_process.c |  80 +++++++++++++++++
 src/backend/postmaster/pgarch.c       |  21 +----
 src/backend/postmaster/postmaster.c   | 120 +++-----------------------
 src/backend/postmaster/syslogger.c    |  24 +-----
 src/include/postmaster/fork_process.h |   8 ++
 7 files changed, 108 insertions(+), 151 deletions(-)
 create mode 100644 src/backend/postmaster/fork_process.c
 create mode 100644 src/include/postmaster/fork_process.h

diff --git a/src/backend/port/beos/support.c b/src/backend/port/beos/support.c
index 2c0b3a9d495..3bfb6ae0d4a 100644
--- a/src/backend/port/beos/support.c
+++ b/src/backend/port/beos/support.c
@@ -265,7 +265,7 @@ beos_startup(int argc, char **argv)
 
 
 
-/* The behavior of fork is borken on beos regarding shared memory. In fact
+/* The behavior of fork is broken on beos regarding shared memory. In fact
 all shared memory areas are clones in copy on write mode in the new process.
 
 We need to do a remapping of these areas. Just afer the fork we performe the
diff --git a/src/backend/postmaster/Makefile b/src/backend/postmaster/Makefile
index fdb12febb4a..054bb090609 100644
--- a/src/backend/postmaster/Makefile
+++ b/src/backend/postmaster/Makefile
@@ -4,7 +4,7 @@
 #    Makefile for src/backend/postmaster
 #
 # IDENTIFICATION
-#    $PostgreSQL: pgsql/src/backend/postmaster/Makefile,v 1.19 2004/08/05 23:32:10 tgl Exp $
+#    $PostgreSQL: pgsql/src/backend/postmaster/Makefile,v 1.20 2005/03/10 07:14:03 neilc Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -12,7 +12,7 @@ subdir = src/backend/postmaster
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
-OBJS = postmaster.o bgwriter.o pgstat.o pgarch.o syslogger.o
+OBJS = bgwriter.o fork_process.o pgarch.o pgstat.o postmaster.o syslogger.o
 
 all: SUBSYS.o
 
diff --git a/src/backend/postmaster/fork_process.c b/src/backend/postmaster/fork_process.c
new file mode 100644
index 00000000000..3098087db44
--- /dev/null
+++ b/src/backend/postmaster/fork_process.c
@@ -0,0 +1,80 @@
+/*
+ * fork_process.c
+ *   A simple wrapper on top of fork(). This does not handle the
+ *   EXEC_BACKEND case; it might be extended to do so, but it would be
+ *   considerably more complex.
+ *
+ * Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *	  $PostgreSQL: pgsql/src/backend/postmaster/fork_process.c,v 1.1 2005/03/10 07:14:03 neilc Exp $
+ */
+#include "postgres.h"
+#include "postmaster/fork_process.h"
+
+#include <unistd.h>
+
+/*
+ * Wrapper for fork(). Return values are the same as those for fork():
+ * -1 if the fork failed, 0 in the child process, and the PID of the
+ * child in the parent process.
+ */
+pid_t
+fork_process(void)
+{
+	pid_t result;
+#ifdef LINUX_PROFILE
+	struct itimerval prof_itimer;
+#endif
+
+	/*
+	 * Flush stdio channels just before fork, to avoid double-output
+	 * problems. Ideally we'd use fflush(NULL) here, but there are still a
+	 * few non-ANSI stdio libraries out there (like SunOS 4.1.x) that
+	 * coredump if we do. Presently stdout and stderr are the only stdio
+	 * output channels used by the postmaster, so fflush'ing them should
+	 * be sufficient.
+	 */
+	fflush(stdout);
+	fflush(stderr);
+
+#ifdef LINUX_PROFILE
+	/*
+	 * Linux's fork() resets the profiling timer in the child process. If
+	 * we want to profile child processes then we need to save and restore
+	 * the timer setting.  This is a waste of time if not profiling,
+	 * however, so only do it if commanded by specific -DLINUX_PROFILE
+	 * switch.
+	 */
+	getitimer(ITIMER_PROF, &prof_itimer);
+#endif
+
+#ifdef __BEOS__
+	/* Specific beos actions before backend startup */
+	beos_before_backend_startup();
+#endif
+
+	result = fork();
+	if (result == (pid_t) -1)
+	{
+		/* fork failed */
+#ifdef __BEOS__
+		/* Specific beos backend startup actions */
+		beos_backend_startup_failed();
+#endif
+	}
+	else if (result == 0)
+	{
+		/* fork succeeded, in child */
+#ifdef LINUX_PROFILE
+		setitimer(ITIMER_PROF, &prof_itimer, NULL);
+#endif
+
+#ifdef __BEOS__
+		/* Specific beos backend startup actions */
+		beos_backend_startup();
+#endif
+	}
+
+	return result;
+}
diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c
index 616e0a63272..fc2d9ce7299 100644
--- a/src/backend/postmaster/pgarch.c
+++ b/src/backend/postmaster/pgarch.c
@@ -19,7 +19,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/postmaster/pgarch.c,v 1.14 2004/12/31 22:00:40 pgsql Exp $
+ *	  $PostgreSQL: pgsql/src/backend/postmaster/pgarch.c,v 1.15 2005/03/10 07:14:03 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -34,6 +34,7 @@
 #include "access/xlog_internal.h"
 #include "libpq/pqsignal.h"
 #include "miscadmin.h"
+#include "postmaster/fork_process.h"
 #include "postmaster/pgarch.h"
 #include "postmaster/postmaster.h"
 #include "storage/fd.h"
@@ -141,25 +142,13 @@ pgarch_start(void)
 		return 0;
 	last_pgarch_start_time = curtime;
 
-	fflush(stdout);
-	fflush(stderr);
-
-#ifdef __BEOS__
-	/* Specific beos actions before backend startup */
-	beos_before_backend_startup();
-#endif
-
 #ifdef EXEC_BACKEND
 	switch ((pgArchPid = pgarch_forkexec()))
 #else
-	switch ((pgArchPid = fork()))
+	switch ((pgArchPid = fork_process()))
 #endif
 	{
 		case -1:
-#ifdef __BEOS__
-			/* Specific beos actions */
-			beos_backend_startup_failed();
-#endif
 			ereport(LOG,
 					(errmsg("could not fork archiver: %m")));
 			return 0;
@@ -167,10 +156,6 @@ pgarch_start(void)
 #ifndef EXEC_BACKEND
 		case 0:
 			/* in postmaster child ... */
-#ifdef __BEOS__
-			/* Specific beos actions after backend startup */
-			beos_backend_startup();
-#endif
 			/* Close the postmaster's sockets */
 			ClosePostmasterPorts(false);
 
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index d84bf277576..8df917e4e8e 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.445 2005/02/22 04:36:36 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.446 2005/03/10 07:14:03 neilc Exp $
  *
  * NOTES
  *
@@ -92,6 +92,8 @@
 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
 #endif
 
+#include "access/xlog.h"
+#include "bootstrap/bootstrap.h"
 #include "catalog/pg_control.h"
 #include "catalog/pg_database.h"
 #include "commands/async.h"
@@ -103,23 +105,22 @@
 #include "libpq/pqsignal.h"
 #include "miscadmin.h"
 #include "nodes/nodes.h"
-#include "postmaster/postmaster.h"
+#include "pgstat.h"
+#include "postmaster/fork_process.h"
 #include "postmaster/pgarch.h"
+#include "postmaster/postmaster.h"
 #include "postmaster/syslogger.h"
+#include "storage/bufmgr.h"
 #include "storage/fd.h"
 #include "storage/ipc.h"
 #include "storage/pg_shmem.h"
 #include "storage/pmsignal.h"
 #include "storage/proc.h"
-#include "storage/bufmgr.h"
-#include "access/xlog.h"
 #include "tcop/tcopprot.h"
 #include "utils/builtins.h"
 #include "utils/guc.h"
 #include "utils/memutils.h"
 #include "utils/ps_status.h"
-#include "bootstrap/bootstrap.h"
-#include "pgstat.h"
 
 #ifdef EXEC_BACKEND
 #include "storage/spin.h"
@@ -1008,16 +1009,7 @@ pmdaemonize(void)
 	int			i;
 	pid_t		pid;
 
-#ifdef LINUX_PROFILE
-	struct itimerval prof_itimer;
-#endif
-
-#ifdef LINUX_PROFILE
-	/* see comments in BackendStartup */
-	getitimer(ITIMER_PROF, &prof_itimer);
-#endif
-
-	pid = fork();
+	pid = fork_process();
 	if (pid == (pid_t) -1)
 	{
 		write_stderr("%s: could not fork background process: %s\n",
@@ -1030,10 +1022,6 @@ pmdaemonize(void)
 		_exit(0);
 	}
 
-#ifdef LINUX_PROFILE
-	setitimer(ITIMER_PROF, &prof_itimer, NULL);
-#endif
-
 	MyProcPid = PostmasterPid = getpid();		/* reset PID vars to child */
 
 /* GH: If there's no setsid(), we hopefully don't need silent mode.
@@ -2382,10 +2370,6 @@ BackendStartup(Port *port)
 	Backend    *bn;				/* for backend cleanup */
 	pid_t		pid;
 
-#ifdef LINUX_PROFILE
-	struct itimerval prof_itimer;
-#endif
-
 	/*
 	 * Compute the cancel key that will be assigned to this backend. The
 	 * backend will have its own copy in the forked-off process' value of
@@ -2409,54 +2393,13 @@ BackendStartup(Port *port)
 	/* Pass down canAcceptConnections state (kluge for EXEC_BACKEND case) */
 	port->canAcceptConnections = canAcceptConnections();
 
-	/*
-	 * Flush stdio channels just before fork, to avoid double-output
-	 * problems. Ideally we'd use fflush(NULL) here, but there are still a
-	 * few non-ANSI stdio libraries out there (like SunOS 4.1.x) that
-	 * coredump if we do. Presently stdout and stderr are the only stdio
-	 * output channels used by the postmaster, so fflush'ing them should
-	 * be sufficient.
-	 */
-	fflush(stdout);
-	fflush(stderr);
-
 #ifdef EXEC_BACKEND
-
 	pid = backend_forkexec(port);
-
 #else							/* !EXEC_BACKEND */
-
-#ifdef LINUX_PROFILE
-
-	/*
-	 * Linux's fork() resets the profiling timer in the child process. If
-	 * we want to profile child processes then we need to save and restore
-	 * the timer setting.  This is a waste of time if not profiling,
-	 * however, so only do it if commanded by specific -DLINUX_PROFILE
-	 * switch.
-	 */
-	getitimer(ITIMER_PROF, &prof_itimer);
-#endif
-
-#ifdef __BEOS__
-	/* Specific beos actions before backend startup */
-	beos_before_backend_startup();
-#endif
-
-	pid = fork();
-
+	pid = fork_process();
 	if (pid == 0)				/* child */
 	{
-#ifdef LINUX_PROFILE
-		setitimer(ITIMER_PROF, &prof_itimer, NULL);
-#endif
-
-#ifdef __BEOS__
-		/* Specific beos backend startup actions */
-		beos_backend_startup();
-#endif
 		free(bn);
-
 		proc_exit(BackendRun(port));
 	}
 #endif   /* EXEC_BACKEND */
@@ -2466,10 +2409,6 @@ BackendStartup(Port *port)
 		/* in parent, fork failed */
 		int			save_errno = errno;
 
-#ifdef __BEOS__
-		/* Specific beos backend startup actions */
-		beos_backend_startup_failed();
-#endif
 		free(bn);
 		errno = save_errno;
 		ereport(LOG,
@@ -2945,7 +2884,7 @@ internal_forkexec(int argc, char *argv[], Port *port)
 	argv[2] = tmpfilename;
 
 	/* Fire off execv in child */
-	if ((pid = fork()) == 0)
+	if ((pid = fork_process()) == 0)
 	{
 		if (execv(postgres_exec_path, argv) < 0)
 		{
@@ -3465,10 +3404,6 @@ StartChildProcess(int xlop)
 	int			ac = 0;
 	char		xlbuf[32];
 
-#ifdef LINUX_PROFILE
-	struct itimerval prof_itimer;
-#endif
-
 	/*
 	 * Set up command-line arguments for subprocess
 	 */
@@ -3488,41 +3423,13 @@ StartChildProcess(int xlop)
 	av[ac] = NULL;
 	Assert(ac < lengthof(av));
 
-	/*
-	 * Flush stdio channels (see comments in BackendStartup)
-	 */
-	fflush(stdout);
-	fflush(stderr);
-
 #ifdef EXEC_BACKEND
-
 	pid = postmaster_forkexec(ac, av);
-
 #else							/* !EXEC_BACKEND */
-
-#ifdef LINUX_PROFILE
-	/* see comments in BackendStartup */
-	getitimer(ITIMER_PROF, &prof_itimer);
-#endif
-
-#ifdef __BEOS__
-	/* Specific beos actions before backend startup */
-	beos_before_backend_startup();
-#endif
-
-	pid = fork();
+	pid = fork_process();
 
 	if (pid == 0)				/* child */
 	{
-#ifdef LINUX_PROFILE
-		setitimer(ITIMER_PROF, &prof_itimer, NULL);
-#endif
-
-#ifdef __BEOS__
-		/* Specific beos actions after backend startup */
-		beos_backend_startup();
-#endif
-
 		IsUnderPostmaster = true;		/* we are a postmaster subprocess
 										 * now */
 
@@ -3546,11 +3453,6 @@ StartChildProcess(int xlop)
 	{
 		/* in parent, fork failed */
 		int			save_errno = errno;
-
-#ifdef __BEOS__
-		/* Specific beos actions before backend startup */
-		beos_backend_startup_failed();
-#endif
 		errno = save_errno;
 		switch (xlop)
 		{
diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c
index e057666370a..87951a6961c 100644
--- a/src/backend/postmaster/syslogger.c
+++ b/src/backend/postmaster/syslogger.c
@@ -18,7 +18,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/postmaster/syslogger.c,v 1.12 2005/01/01 20:44:16 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/postmaster/syslogger.c,v 1.13 2005/03/10 07:14:03 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -33,6 +33,7 @@
 
 #include "libpq/pqsignal.h"
 #include "miscadmin.h"
+#include "postmaster/fork_process.h"
 #include "postmaster/postmaster.h"
 #include "postmaster/syslogger.h"
 #include "pgtime.h"
@@ -451,28 +452,13 @@ SysLogger_Start(void)
 
 	pfree(filename);
 
-	/*
-	 * Now we can fork off the syslogger subprocess.
-	 */
-	fflush(stdout);
-	fflush(stderr);
-
-#ifdef __BEOS__
-	/* Specific beos actions before backend startup */
-	beos_before_backend_startup();
-#endif
-
 #ifdef EXEC_BACKEND
 	switch ((sysloggerPid = syslogger_forkexec()))
 #else
-	switch ((sysloggerPid = fork()))
+	switch ((sysloggerPid = fork_process()))
 #endif
 	{
 		case -1:
-#ifdef __BEOS__
-			/* Specific beos actions */
-			beos_backend_startup_failed();
-#endif
 			ereport(LOG,
 					(errmsg("could not fork system logger: %m")));
 			return 0;
@@ -480,10 +466,6 @@ SysLogger_Start(void)
 #ifndef EXEC_BACKEND
 		case 0:
 			/* in postmaster child ... */
-#ifdef __BEOS__
-			/* Specific beos actions after backend startup */
-			beos_backend_startup();
-#endif
 			/* Close the postmaster's sockets */
 			ClosePostmasterPorts(true);
 
diff --git a/src/include/postmaster/fork_process.h b/src/include/postmaster/fork_process.h
new file mode 100644
index 00000000000..945de366711
--- /dev/null
+++ b/src/include/postmaster/fork_process.h
@@ -0,0 +1,8 @@
+#ifndef FORK_PROCESS_H
+#define FORK_PROCESS_H
+
+#include "postgres.h"
+
+extern pid_t fork_process(void);
+
+#endif /* ! FORK_PROCESS_H */
-- 
GitLab