mirror of
https://github.com/postgres/postgres.git
synced 2025-07-14 08:21:07 +03:00
On systems that have setsid(2) (which should be just about everything except
Windows), arrange for each postmaster child process to be its own process group leader, and deliver signals SIGINT, SIGTERM, SIGQUIT to the whole process group not only the direct child process. This provides saner behavior for archive and recovery scripts; in particular, it's possible to shut down a warm-standby recovery server using "pg_ctl stop -m immediate", since delivery of SIGQUIT to the startup subprocess will result in killing the waiting recovery_command. Also, this makes Query Cancel and statement_timeout apply to scripts being run from backends via system(). (There is no support in the core backend for that, but it's widely done using untrusted PLs.) Per gripe from Stephen Harris and subsequent discussion.
This commit is contained in:
@ -37,7 +37,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.502 2006/11/21 00:49:55 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.503 2006/11/21 20:59:52 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
*
|
||||
@ -268,6 +268,7 @@ static void report_fork_failure_to_client(Port *port, int errnum);
|
||||
static enum CAC_state canAcceptConnections(void);
|
||||
static long PostmasterRandom(void);
|
||||
static void RandomSalt(char *cryptSalt, char *md5Salt);
|
||||
static void signal_child(pid_t pid, int signal);
|
||||
static void SignalChildren(int signal);
|
||||
static int CountChildren(void);
|
||||
static bool CreateOptsFile(int argc, char *argv[], char *fullprogname);
|
||||
@ -1229,7 +1230,7 @@ ServerLoop(void)
|
||||
BgWriterPID = StartBackgroundWriter();
|
||||
/* If shutdown is pending, set it going */
|
||||
if (Shutdown > NoShutdown && BgWriterPID != 0)
|
||||
kill(BgWriterPID, SIGUSR2);
|
||||
signal_child(BgWriterPID, SIGUSR2);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1639,7 +1640,7 @@ processCancelRequest(Port *port, void *pkt)
|
||||
ereport(DEBUG2,
|
||||
(errmsg_internal("processing cancel request: sending SIGINT to process %d",
|
||||
backendPID)));
|
||||
kill(bp->pid, SIGINT);
|
||||
signal_child(bp->pid, SIGINT);
|
||||
}
|
||||
else
|
||||
/* Right PID, wrong key: no way, Jose */
|
||||
@ -1813,13 +1814,13 @@ SIGHUP_handler(SIGNAL_ARGS)
|
||||
ProcessConfigFile(PGC_SIGHUP);
|
||||
SignalChildren(SIGHUP);
|
||||
if (BgWriterPID != 0)
|
||||
kill(BgWriterPID, SIGHUP);
|
||||
signal_child(BgWriterPID, SIGHUP);
|
||||
if (AutoVacPID != 0)
|
||||
kill(AutoVacPID, SIGHUP);
|
||||
signal_child(AutoVacPID, SIGHUP);
|
||||
if (PgArchPID != 0)
|
||||
kill(PgArchPID, SIGHUP);
|
||||
signal_child(PgArchPID, SIGHUP);
|
||||
if (SysLoggerPID != 0)
|
||||
kill(SysLoggerPID, SIGHUP);
|
||||
signal_child(SysLoggerPID, SIGHUP);
|
||||
/* PgStatPID does not currently need SIGHUP */
|
||||
|
||||
/* Reload authentication config files too */
|
||||
@ -1873,7 +1874,7 @@ pmdie(SIGNAL_ARGS)
|
||||
if (AutoVacPID != 0)
|
||||
{
|
||||
/* Use statement cancel to shut it down */
|
||||
kill(AutoVacPID, SIGINT);
|
||||
signal_child(AutoVacPID, SIGINT);
|
||||
break; /* let reaper() handle this */
|
||||
}
|
||||
|
||||
@ -1890,13 +1891,13 @@ pmdie(SIGNAL_ARGS)
|
||||
BgWriterPID = StartBackgroundWriter();
|
||||
/* And tell it to shut down */
|
||||
if (BgWriterPID != 0)
|
||||
kill(BgWriterPID, SIGUSR2);
|
||||
signal_child(BgWriterPID, SIGUSR2);
|
||||
/* Tell pgarch to shut down too; nothing left for it to do */
|
||||
if (PgArchPID != 0)
|
||||
kill(PgArchPID, SIGQUIT);
|
||||
signal_child(PgArchPID, SIGQUIT);
|
||||
/* Tell pgstat to shut down too; nothing left for it to do */
|
||||
if (PgStatPID != 0)
|
||||
kill(PgStatPID, SIGQUIT);
|
||||
signal_child(PgStatPID, SIGQUIT);
|
||||
break;
|
||||
|
||||
case SIGINT:
|
||||
@ -1921,7 +1922,7 @@ pmdie(SIGNAL_ARGS)
|
||||
(errmsg("aborting any active transactions")));
|
||||
SignalChildren(SIGTERM);
|
||||
if (AutoVacPID != 0)
|
||||
kill(AutoVacPID, SIGTERM);
|
||||
signal_child(AutoVacPID, SIGTERM);
|
||||
/* reaper() does the rest */
|
||||
}
|
||||
break;
|
||||
@ -1940,13 +1941,13 @@ pmdie(SIGNAL_ARGS)
|
||||
BgWriterPID = StartBackgroundWriter();
|
||||
/* And tell it to shut down */
|
||||
if (BgWriterPID != 0)
|
||||
kill(BgWriterPID, SIGUSR2);
|
||||
signal_child(BgWriterPID, SIGUSR2);
|
||||
/* Tell pgarch to shut down too; nothing left for it to do */
|
||||
if (PgArchPID != 0)
|
||||
kill(PgArchPID, SIGQUIT);
|
||||
signal_child(PgArchPID, SIGQUIT);
|
||||
/* Tell pgstat to shut down too; nothing left for it to do */
|
||||
if (PgStatPID != 0)
|
||||
kill(PgStatPID, SIGQUIT);
|
||||
signal_child(PgStatPID, SIGQUIT);
|
||||
break;
|
||||
|
||||
case SIGQUIT:
|
||||
@ -1960,15 +1961,15 @@ pmdie(SIGNAL_ARGS)
|
||||
ereport(LOG,
|
||||
(errmsg("received immediate shutdown request")));
|
||||
if (StartupPID != 0)
|
||||
kill(StartupPID, SIGQUIT);
|
||||
signal_child(StartupPID, SIGQUIT);
|
||||
if (BgWriterPID != 0)
|
||||
kill(BgWriterPID, SIGQUIT);
|
||||
signal_child(BgWriterPID, SIGQUIT);
|
||||
if (AutoVacPID != 0)
|
||||
kill(AutoVacPID, SIGQUIT);
|
||||
signal_child(AutoVacPID, SIGQUIT);
|
||||
if (PgArchPID != 0)
|
||||
kill(PgArchPID, SIGQUIT);
|
||||
signal_child(PgArchPID, SIGQUIT);
|
||||
if (PgStatPID != 0)
|
||||
kill(PgStatPID, SIGQUIT);
|
||||
signal_child(PgStatPID, SIGQUIT);
|
||||
if (DLGetHead(BackendList))
|
||||
SignalChildren(SIGQUIT);
|
||||
ExitPostmaster(0);
|
||||
@ -2065,7 +2066,7 @@ reaper(SIGNAL_ARGS)
|
||||
* (We could, but don't, try to start autovacuum here.)
|
||||
*/
|
||||
if (Shutdown > NoShutdown && BgWriterPID != 0)
|
||||
kill(BgWriterPID, SIGUSR2);
|
||||
signal_child(BgWriterPID, SIGUSR2);
|
||||
else if (Shutdown == NoShutdown)
|
||||
{
|
||||
if (XLogArchivingActive() && PgArchPID == 0)
|
||||
@ -2207,13 +2208,13 @@ reaper(SIGNAL_ARGS)
|
||||
BgWriterPID = StartBackgroundWriter();
|
||||
/* And tell it to shut down */
|
||||
if (BgWriterPID != 0)
|
||||
kill(BgWriterPID, SIGUSR2);
|
||||
signal_child(BgWriterPID, SIGUSR2);
|
||||
/* Tell pgarch to shut down too; nothing left for it to do */
|
||||
if (PgArchPID != 0)
|
||||
kill(PgArchPID, SIGQUIT);
|
||||
signal_child(PgArchPID, SIGQUIT);
|
||||
/* Tell pgstat to shut down too; nothing left for it to do */
|
||||
if (PgStatPID != 0)
|
||||
kill(PgStatPID, SIGQUIT);
|
||||
signal_child(PgStatPID, SIGQUIT);
|
||||
}
|
||||
|
||||
reaper_done:
|
||||
@ -2324,7 +2325,7 @@ HandleChildCrash(int pid, int exitstatus, const char *procname)
|
||||
(errmsg_internal("sending %s to process %d",
|
||||
(SendStop ? "SIGSTOP" : "SIGQUIT"),
|
||||
(int) bp->pid)));
|
||||
kill(bp->pid, (SendStop ? SIGSTOP : SIGQUIT));
|
||||
signal_child(bp->pid, (SendStop ? SIGSTOP : SIGQUIT));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2338,7 +2339,7 @@ HandleChildCrash(int pid, int exitstatus, const char *procname)
|
||||
(errmsg_internal("sending %s to process %d",
|
||||
(SendStop ? "SIGSTOP" : "SIGQUIT"),
|
||||
(int) BgWriterPID)));
|
||||
kill(BgWriterPID, (SendStop ? SIGSTOP : SIGQUIT));
|
||||
signal_child(BgWriterPID, (SendStop ? SIGSTOP : SIGQUIT));
|
||||
}
|
||||
|
||||
/* Take care of the autovacuum daemon too */
|
||||
@ -2350,7 +2351,7 @@ HandleChildCrash(int pid, int exitstatus, const char *procname)
|
||||
(errmsg_internal("sending %s to process %d",
|
||||
(SendStop ? "SIGSTOP" : "SIGQUIT"),
|
||||
(int) AutoVacPID)));
|
||||
kill(AutoVacPID, (SendStop ? SIGSTOP : SIGQUIT));
|
||||
signal_child(AutoVacPID, (SendStop ? SIGSTOP : SIGQUIT));
|
||||
}
|
||||
|
||||
/* Force a power-cycle of the pgarch process too */
|
||||
@ -2361,7 +2362,7 @@ HandleChildCrash(int pid, int exitstatus, const char *procname)
|
||||
(errmsg_internal("sending %s to process %d",
|
||||
"SIGQUIT",
|
||||
(int) PgArchPID)));
|
||||
kill(PgArchPID, SIGQUIT);
|
||||
signal_child(PgArchPID, SIGQUIT);
|
||||
}
|
||||
|
||||
/* Force a power-cycle of the pgstat process too */
|
||||
@ -2372,7 +2373,7 @@ HandleChildCrash(int pid, int exitstatus, const char *procname)
|
||||
(errmsg_internal("sending %s to process %d",
|
||||
"SIGQUIT",
|
||||
(int) PgStatPID)));
|
||||
kill(PgStatPID, SIGQUIT);
|
||||
signal_child(PgStatPID, SIGQUIT);
|
||||
}
|
||||
|
||||
/* We do NOT restart the syslogger */
|
||||
@ -2415,6 +2416,43 @@ LogChildExit(int lev, const char *procname, int pid, int exitstatus)
|
||||
procname, pid, exitstatus)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a signal to a postmaster child process
|
||||
*
|
||||
* On systems that have setsid(), each child process sets itself up as a
|
||||
* process group leader. For signals that are generally interpreted in the
|
||||
* appropriate fashion, we signal the entire process group not just the
|
||||
* direct child process. This allows us to, for example, SIGQUIT a blocked
|
||||
* archive_recovery script, or SIGINT a script being run by a backend via
|
||||
* system().
|
||||
*
|
||||
* There is a race condition for recently-forked children: they might not
|
||||
* have executed setsid() yet. So we signal the child directly as well as
|
||||
* the group. We assume such a child will handle the signal before trying
|
||||
* to spawn any grandchild processes. We also assume that signaling the
|
||||
* child twice will not cause any problems.
|
||||
*/
|
||||
static void
|
||||
signal_child(pid_t pid, int signal)
|
||||
{
|
||||
if (kill(pid, signal) < 0)
|
||||
elog(DEBUG3, "kill(%ld,%d) failed: %m", (long) pid, signal);
|
||||
#ifdef HAVE_SETSID
|
||||
switch (signal)
|
||||
{
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
case SIGQUIT:
|
||||
case SIGSTOP:
|
||||
if (kill(-pid, signal) < 0)
|
||||
elog(DEBUG3, "kill(%ld,%d) failed: %m", (long) (-pid), signal);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a signal to all backend children (but NOT special children)
|
||||
*/
|
||||
@ -2430,7 +2468,7 @@ SignalChildren(int signal)
|
||||
ereport(DEBUG4,
|
||||
(errmsg_internal("sending signal %d to process %d",
|
||||
signal, (int) bp->pid)));
|
||||
kill(bp->pid, signal);
|
||||
signal_child(bp->pid, signal);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2641,7 +2679,17 @@ BackendInitialize(Port *port)
|
||||
whereToSendOutput = DestRemote; /* now safe to ereport to client */
|
||||
|
||||
/*
|
||||
* We arrange for a simple exit(0) if we receive SIGTERM or SIGQUIT during
|
||||
* If possible, make this process a group leader, so that the postmaster
|
||||
* can signal any child processes too. (We do this now on the off chance
|
||||
* that something might spawn a child process during authentication.)
|
||||
*/
|
||||
#ifdef HAVE_SETSID
|
||||
if (setsid() < 0)
|
||||
elog(FATAL, "setsid() failed: %m");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We arrange for a simple exit(1) if we receive SIGTERM or SIGQUIT during
|
||||
* any client authentication related communication. Otherwise the
|
||||
* postmaster cannot shutdown the database FAST or IMMED cleanly if a
|
||||
* buggy client blocks a backend during authentication.
|
||||
@ -3413,7 +3461,7 @@ sigusr1_handler(SIGNAL_ARGS)
|
||||
{
|
||||
SignalChildren(SIGUSR1);
|
||||
if (AutoVacPID != 0)
|
||||
kill(AutoVacPID, SIGUSR1);
|
||||
signal_child(AutoVacPID, SIGUSR1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3424,14 +3472,14 @@ sigusr1_handler(SIGNAL_ARGS)
|
||||
* Send SIGUSR1 to archiver process, to wake it up and begin archiving
|
||||
* next transaction log file.
|
||||
*/
|
||||
kill(PgArchPID, SIGUSR1);
|
||||
signal_child(PgArchPID, SIGUSR1);
|
||||
}
|
||||
|
||||
if (CheckPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE) &&
|
||||
SysLoggerPID != 0)
|
||||
{
|
||||
/* Tell syslogger to rotate logfile */
|
||||
kill(SysLoggerPID, SIGUSR1);
|
||||
signal_child(SysLoggerPID, SIGUSR1);
|
||||
}
|
||||
|
||||
if (CheckPostmasterSignal(PMSIGNAL_START_AUTOVAC))
|
||||
|
Reference in New Issue
Block a user