diff options
Diffstat (limited to 'src/backend/postmaster')
-rw-r--r-- | src/backend/postmaster/autovacuum.c | 13 | ||||
-rw-r--r-- | src/backend/postmaster/bgwriter.c | 14 | ||||
-rw-r--r-- | src/backend/postmaster/pgarch.c | 27 | ||||
-rw-r--r-- | src/backend/postmaster/pgstat.c | 13 | ||||
-rw-r--r-- | src/backend/postmaster/postmaster.c | 116 | ||||
-rw-r--r-- | src/backend/postmaster/syslogger.c | 13 |
6 files changed, 156 insertions, 40 deletions
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 11552c94644..8a44f7fa57e 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.28 2006/11/05 22:42:09 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.29 2006/11/21 20:59:52 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -244,6 +244,17 @@ AutoVacMain(int argc, char *argv[]) SetProcessingMode(InitProcessing); /* + * If possible, make this process a group leader, so that the postmaster + * can signal any child processes too. (autovacuum probably never has + * any child processes, but for consistency we make all postmaster + * child processes do this.) + */ +#ifdef HAVE_SETSID + if (setsid() < 0) + elog(FATAL, "setsid() failed: %m"); +#endif + + /* * Set up signal handlers. We operate on databases much like a regular * backend, so we use the same signal handling. See equivalent code in * tcop/postgres.c. diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c index f2cb3ff68de..5aa378ae70d 100644 --- a/src/backend/postmaster/bgwriter.c +++ b/src/backend/postmaster/bgwriter.c @@ -37,7 +37,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/postmaster/bgwriter.c,v 1.30 2006/11/21 00:49:55 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/bgwriter.c,v 1.31 2006/11/21 20:59:52 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -45,6 +45,7 @@ #include <signal.h> #include <time.h> +#include <unistd.h> #include "access/xlog_internal.h" #include "libpq/pqsignal.h" @@ -171,6 +172,17 @@ BackgroundWriterMain(void) am_bg_writer = true; /* + * If possible, make this process a group leader, so that the postmaster + * can signal any child processes too. (bgwriter probably never has + * any child processes, but for consistency we make all postmaster + * child processes do this.) + */ +#ifdef HAVE_SETSID + if (setsid() < 0) + elog(FATAL, "setsid() failed: %m"); +#endif + + /* * Properly accept or ignore signals the postmaster might send us * * Note: we deliberately ignore SIGTERM, because during a standard Unix diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c index a40bf47b3aa..ba8a396c2e5 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.26 2006/11/10 22:32:20 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/pgarch.c,v 1.27 2006/11/21 20:59:52 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -29,6 +29,7 @@ #include <signal.h> #include <time.h> #include <sys/time.h> +#include <sys/wait.h> #include <unistd.h> #include "access/xlog_internal.h" @@ -223,6 +224,15 @@ PgArchiverMain(int argc, char *argv[]) MyProcPid = getpid(); /* reset MyProcPid */ /* + * If possible, make this process a group leader, so that the postmaster + * can signal any child processes too. + */ +#ifdef HAVE_SETSID + if (setsid() < 0) + elog(FATAL, "setsid() failed: %m"); +#endif + + /* * Ignore all signals usually bound to some action in the postmaster, * except for SIGHUP, SIGUSR1 and SIGQUIT. */ @@ -456,9 +466,22 @@ pgarch_archiveXlog(char *xlog) rc = system(xlogarchcmd); if (rc != 0) { - ereport(LOG, + /* + * If either the shell itself, or a called command, died on a signal, + * abort the archiver. We do this because system() ignores SIGINT and + * SIGQUIT while waiting; so a signal is very likely something that + * should have interrupted us too. If we overreact it's no big deal, + * the postmaster will just start the archiver again. + * + * Per the Single Unix Spec, shells report exit status > 128 when + * a called command died on a signal. + */ + bool signaled = WIFSIGNALED(rc) || WEXITSTATUS(rc) > 128; + + ereport(signaled ? FATAL : LOG, (errmsg("archive command \"%s\" failed: return code %d", xlogarchcmd, rc))); + return false; } ereport(LOG, diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index db4a57b0171..19a694caf30 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -13,7 +13,7 @@ * * Copyright (c) 2001-2006, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.139 2006/10/04 00:29:56 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.140 2006/11/21 20:59:52 tgl Exp $ * ---------- */ #include "postgres.h" @@ -1614,6 +1614,17 @@ PgstatCollectorMain(int argc, char *argv[]) MyProcPid = getpid(); /* reset MyProcPid */ /* + * If possible, make this process a group leader, so that the postmaster + * can signal any child processes too. (pgstat probably never has + * any child processes, but for consistency we make all postmaster + * child processes do this.) + */ +#ifdef HAVE_SETSID + if (setsid() < 0) + elog(FATAL, "setsid() failed: %m"); +#endif + + /* * Ignore all signals usually bound to some action in the postmaster, * except SIGQUIT and SIGALRM. */ diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 9d7b6065f46..07b5a9d8545 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.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 */ @@ -2416,6 +2417,43 @@ LogChildExit(int lev, const char *procname, int pid, int 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) */ static void @@ -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)) diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c index 23ff158fc61..3968018382f 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.28 2006/07/16 20:17:04 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/syslogger.c,v 1.29 2006/11/21 20:59:52 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -183,6 +183,17 @@ SysLoggerMain(int argc, char *argv[]) #endif /* + * If possible, make this process a group leader, so that the postmaster + * can signal any child processes too. (syslogger probably never has + * any child processes, but for consistency we make all postmaster + * child processes do this.) + */ +#ifdef HAVE_SETSID + if (setsid() < 0) + elog(FATAL, "setsid() failed: %m"); +#endif + + /* * Properly accept or ignore signals the postmaster might send us * * Note: we ignore all termination signals, and instead exit only when all |