*
*
* 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
*
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);
BgWriterPID = StartBackgroundWriter();
/* If shutdown is pending, set it going */
if (Shutdown > NoShutdown && BgWriterPID != 0)
- kill(BgWriterPID, SIGUSR2);
+ signal_child(BgWriterPID, SIGUSR2);
}
/*
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 */
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 */
if (AutoVacPID != 0)
{
/* Use statement cancel to shut it down */
- kill(AutoVacPID, SIGINT);
+ signal_child(AutoVacPID, SIGINT);
break; /* let reaper() handle this */
}
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:
(errmsg("aborting any active transactions")));
SignalChildren(SIGTERM);
if (AutoVacPID != 0)
- kill(AutoVacPID, SIGTERM);
+ signal_child(AutoVacPID, SIGTERM);
/* reaper() does the rest */
}
break;
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:
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);
* (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)
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:
(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));
}
}
}
(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 */
(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 */
(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 */
(errmsg_internal("sending %s to process %d",
"SIGQUIT",
(int) PgStatPID)));
- kill(PgStatPID, SIGQUIT);
+ signal_child(PgStatPID, SIGQUIT);
}
/* We do NOT restart the syslogger */
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)
*/
ereport(DEBUG4,
(errmsg_internal("sending signal %d to process %d",
signal, (int) bp->pid)));
- kill(bp->pid, signal);
+ signal_child(bp->pid, signal);
}
}
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.
{
SignalChildren(SIGUSR1);
if (AutoVacPID != 0)
- kill(AutoVacPID, SIGUSR1);
+ signal_child(AutoVacPID, SIGUSR1);
}
}
* 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))