On 30/12/2018 21:59, Heikki Linnakangas wrote:
On 28/12/2018 22:13, Tom Lane wrote:
Heikki Linnakangas <hlinn...@iki.fi> writes:
Another idea would be to call setsid() in pg_ctl, after forking
postmaster, like in Paul's original patch. That solves 1. and 2. To
still do 3., add a signal handler for SIGINT in pg_ctl, which forwards
the SIGINT to the postmaster process. Thoughts on that?

That seems like a nice idea.

Here's a patch to implement that.

Forgot attachment, here it is.

- Heikki
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index 1d0b056dde0..cb7b88bc7df 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -103,12 +103,13 @@ static char backup_file[MAXPGPATH];
 static char promote_file[MAXPGPATH];
 static char logrotate_file[MAXPGPATH];
 
+static volatile pgpid_t postmasterPID = -1;
+
 #ifdef WIN32
 static DWORD pgctl_start_type = SERVICE_AUTO_START;
 static SERVICE_STATUS status;
 static SERVICE_STATUS_HANDLE hStatus = (SERVICE_STATUS_HANDLE) 0;
 static HANDLE shutdownHandles[2];
-static pid_t postmasterPID = -1;
 
 #define shutdownEvent	  shutdownHandles[0]
 #define postmasterProcess shutdownHandles[1]
@@ -471,6 +472,20 @@ start_postmaster(void)
 
 	/* fork succeeded, in child */
 
+	/*
+	 * If possible, detach the postmaster process from the launching process group
+	 * and make it a group leader, so that it doesn't get signaled along with the
+	 * current group that launched it.
+	 */
+#ifdef HAVE_SETSID
+	if (setsid() < 0)
+	{
+		write_stderr(_("%s: could not start server due to setsid() failure: %s\n"),
+					 progname, strerror(errno));
+		exit(1);
+	}
+#endif
+
 	/*
 	 * Since there might be quotes to handle here, it is easier simply to pass
 	 * everything to a shell to process them.  Use exec so that the postmaster
@@ -719,6 +734,30 @@ read_post_opts(void)
 	}
 }
 
+/*
+ * SIGINT signal handler used while waiting for postmaster to start up.
+ * Forwards the SIGINT to the postmaster process, asking it to shut down,
+ * before terminating pg_ctl itself. This way, if the user hits CTRL-C while
+ * waiting for the server to start up, the server launch is aborted.
+ */
+static void
+trap_sigint_during_startup(int sig)
+{
+	if (postmasterPID != -1)
+	{
+		if (kill(postmasterPID, SIGINT) != 0)
+			write_stderr(_("%s: could not send stop signal (PID: %ld): %s\n"),
+						 progname, (pgpid_t) postmasterPID, strerror(errno));
+	}
+
+	/*
+	 * Clear the signal handler, and send the signal again, to terminate the
+	 * process as normal.
+	 */
+	pqsignal(SIGINT, SIG_DFL);
+	raise(SIGINT);
+}
+
 static char *
 find_other_exec_or_die(const char *argv0, const char *target, const char *versionstr)
 {
@@ -827,6 +866,17 @@ do_start(void)
 
 	if (do_wait)
 	{
+		/*
+		 * If the user hits interrupts the startup (e.g. with CTRL-C), we'd
+		 * like to abort the server launch.  Install a signal handler that
+		 * will forward SIGINT to the postmaster process, while we wait.
+		 *
+		 * (We don't bother to reset the signal handler after the launch,
+		 * as we're about to exit, anyway.)
+		 */
+		postmasterPID = pm_pid;
+		pqsignal(SIGINT, trap_sigint_during_startup);
+
 		print_msg(_("waiting for server to start..."));
 
 		switch (wait_for_postmaster(pm_pid, false))

Reply via email to