static volatile int do_rotate = 0;
static volatile int do_shutdown = 0;
static volatile int shutdown_status = 0;
+static volatile int do_handle_stopped_child = 0;
static int RotateSignal = -1;
static int ReconfigureSignal = -1;
{
public:
+#if KILL_PARENT_OPT
+ SignalEngine(): parentKillNotified(false) {
+ parentPid = getppid();
+ }
+#endif
+
virtual int checkEvents(int timeout);
private:
}
void doShutdown(time_t wait);
+ void handleStoppedChild();
+
+#if KILL_PARENT_OPT
+ bool parentKillNotified;
+ pid_t parentPid;
+#endif
};
int
doShutdown(do_shutdown > 0 ? (int) Config.shutdownLifetime : 0);
do_shutdown = 0;
}
- BroadcastSignalIfAny(DebugSignal);
- BroadcastSignalIfAny(RotateSignal);
- BroadcastSignalIfAny(ReconfigureSignal);
- BroadcastSignalIfAny(ShutdownSignal);
-
+ if (do_handle_stopped_child) {
+ do_handle_stopped_child = 0;
+ handleStoppedChild();
+ }
PROF_stop(SignalEngine_checkEvents);
return EVENT_IDLE;
}
debugs(1, DBG_IMPORTANT, "Preparing for shutdown after " << statCounter.client_http.requests << " requests");
debugs(1, DBG_IMPORTANT, "Waiting " << wait << " seconds for active connections to finish");
- shutting_down = 1;
+#if KILL_PARENT_OPT
+ if (!IamMasterProcess() && !parentKillNotified && ShutdownSignal > 0 && parentPid > 1) {
+ debugs(1, DBG_IMPORTANT, "Killing master process, pid " << parentPid);
+ if (kill(parentPid, ShutdownSignal) < 0)
+ debugs(1, DBG_IMPORTANT, "kill " << parentPid << ": " << xstrerror());
+ parentKillNotified = true;
+ }
+#endif
-#if USE_WIN32_SERVICE
- WIN32_svcstatusupdate(SERVICE_STOP_PENDING, (wait + 1) * 1000);
+ if (shutting_down) {
+#if !KILL_PARENT_OPT
+ // Already a shutdown signal has received and shutdown is in progress.
+ // Shutdown as soon as possible.
+ wait = 0;
#endif
+ } else {
+ shutting_down = 1;
- /* run the closure code which can be shared with reconfigure */
- serverConnectionsClose();
+ /* run the closure code which can be shared with reconfigure */
+ serverConnectionsClose();
#if USE_AUTH
- /* detach the auth components (only do this on full shutdown) */
- Auth::Scheme::FreeAll();
+ /* detach the auth components (only do this on full shutdown) */
+ Auth::Scheme::FreeAll();
+#endif
+
+ RunRegisteredHere(RegisteredRunner::startShutdown);
+ }
+
+#if USE_WIN32_SERVICE
+ WIN32_svcstatusupdate(SERVICE_STOP_PENDING, (wait + 1) * 1000);
#endif
- RunRegisteredHere(RegisteredRunner::startShutdown);
eventAdd("SquidShutdown", &StopEventLoop, this, (double) (wait + 1), 1, false);
}
+void
+SignalEngine::handleStoppedChild()
+{
+#if !_SQUID_WINDOWS_
+ PidStatus status;
+ pid_t pid;
+
+ do {
+ pid = WaitForAnyPid(status, WNOHANG);
+
+#if HAVE_SIGACTION
+
+ } while (pid > 0);
+
+#else
+
+ } while (pid > 0 || (pid < 0 && errno == EINTR));
+#endif
+#endif
+}
+
static void
usage(void)
{
#endif
}
+/// Shutdown signal handler for master process
+void
+master_shutdown(int sig)
+{
+ do_shutdown = 1;
+ ShutdownSignal = sig;
+
+#if !_SQUID_WINDOWS_
+#if !HAVE_SIGACTION
+ signal(sig, master_shutdown);
+#endif
+#endif
+
+}
+
void
shut_down(int sig)
{
#endif
#if !_SQUID_WINDOWS_
- const pid_t ppid = getppid();
-
- if (!IamMasterProcess() && ppid > 1) {
- // notify master that we are shutting down
- if (kill(ppid, SIGUSR1) < 0)
- debugs(1, DBG_IMPORTANT, "Failed to send SIGUSR1 to master process,"
- " pid " << ppid << ": " << xstrerror());
- }
-
-#if KILL_PARENT_OPT
- if (!IamMasterProcess() && ppid > 1) {
- debugs(1, DBG_IMPORTANT, "Killing master process, pid " << ppid);
-
- if (kill(ppid, sig) < 0)
- debugs(1, DBG_IMPORTANT, "kill " << ppid << ": " << xstrerror());
- }
-#endif /* KILL_PARENT_OPT */
-
-#if SA_RESETHAND == 0
- signal(SIGTERM, SIG_DFL);
+#if !HAVE_SIGACTION
+ signal(sig, shut_down);
+#endif
+#endif
+}
- signal(SIGINT, SIG_DFL);
+void
+sig_child(int sig)
+{
+ do_handle_stopped_child = 1;
+#if !_SQUID_WINDOWS_
+#if !HAVE_SIGACTION
+ signal(sig, sig_child);
#endif
#endif
}
eventDelete(start_announce, NULL);
}
- writePidFile(); /* write PID file */
+ if (!InDaemonMode())
+ writePidFile(); /* write PID file */
reconfiguring = 0;
}
if (Config.chroot_dir)
no_suid();
- if (!configured_once)
+ if (!configured_once && !InDaemonMode())
writePidFile(); /* write PID file */
#if defined(_SQUID_LINUX_THREADS_)
squid_signal(SIGHUP, reconfigure, SA_RESTART);
- squid_signal(SIGTERM, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
+ squid_signal(SIGTERM, shut_down, SA_RESTART);
- squid_signal(SIGINT, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
+ squid_signal(SIGINT, shut_down, SA_RESTART);
#ifdef SIGTTIN
- squid_signal(SIGTTIN, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
+ squid_signal(SIGTTIN, shut_down, SA_RESTART);
#endif
RunRegisteredHere(RegisteredRunner::useConfig);
enter_suid();
- if (!opt_no_daemon && Config.workers > 0)
+ if (InDaemonMode() && IamMasterProcess()) {
watch_child(argv);
+ // NOTREACHED
+ }
if (opt_create_swap_dirs) {
/* chroot if configured to run inside chroot */
_exit(-1);
} else {
do {
-#if _SQUID_NEXT_
- union wait status;
- rpid = wait4(cpid, &status, 0, NULL);
-#else
-
- int status;
- rpid = waitpid(cpid, &status, 0);
-#endif
-
+ PidStatus status;
+ rpid = WaitForOnePid(cpid, status, 0);
} while (rpid != cpid);
}
}
}
static void
-watch_child(char *argv[])
+masterCheckAndBroadcastSignals()
{
-#if !_SQUID_WINDOWS_
- char *prog;
-#if _SQUID_NEXT_
+ if (do_reconfigure)
+ ; // TODO: hot-reconfiguration of the number of kids and PID file location
+ if (do_shutdown)
+ shutting_down = 1;
- union wait status;
-#else
+ BroadcastSignalIfAny(DebugSignal);
+ BroadcastSignalIfAny(RotateSignal);
+ BroadcastSignalIfAny(ReconfigureSignal);
+ BroadcastSignalIfAny(ShutdownSignal);
+}
- int status;
-#endif
+static inline bool
+masterSignaled()
+{
+ return (DebugSignal > 0 || RotateSignal > 0 || ReconfigureSignal > 0 || ShutdownSignal > 0);
+}
+static void
+watch_child(char *argv[])
+{
+#if !_SQUID_WINDOWS_
+ char *prog;
+ PidStatus status;
pid_t pid;
#ifdef TIOCNOTTY
int nullfd;
- if (!IamMasterProcess())
- return;
-
openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
if ((pid = fork()) < 0)
dup2(nullfd, 2);
}
- // handle shutdown notifications from kids
- squid_signal(SIGUSR1, sig_shutdown, SA_RESTART);
+ writePidFile();
+
+#if defined(_SQUID_LINUX_THREADS_)
+ squid_signal(SIGQUIT, rotate_logs, 0);
+ squid_signal(SIGTRAP, sigusr2_handle, 0);
+#else
+ squid_signal(SIGUSR1, rotate_logs, 0);
+ squid_signal(SIGUSR2, sigusr2_handle, 0);
+#endif
+
+ squid_signal(SIGHUP, reconfigure, 0);
+
+ squid_signal(SIGTERM, master_shutdown, 0);
+ squid_signal(SIGINT, master_shutdown, 0);
+#ifdef SIGTTIN
+ squid_signal(SIGTTIN, master_shutdown, 0);
+#endif
if (Config.workers > 128) {
syslog(LOG_ALERT, "Suspiciously high workers value: %d",
// keep [re]starting kids until it is time to quit
for (;;) {
- mainStartScript(argv[0]);
-
+ bool mainStartScriptCalled = false;
// start each kid that needs to be [re]started; once
- for (int i = TheKids.count() - 1; i >= 0; --i) {
+ for (int i = TheKids.count() - 1; i >= 0 && !shutting_down; --i) {
Kid& kid = TheKids.get(i);
if (!kid.shouldRestart())
continue;
+ if (!mainStartScriptCalled) {
+ mainStartScript(argv[0]);
+ mainStartScriptCalled = true;
+ }
+
if ((pid = fork()) == 0) {
/* child */
openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
/* parent */
openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
- squid_signal(SIGINT, SIG_IGN, SA_RESTART);
-
-#if _SQUID_NEXT_
-
- pid = wait3(&status, 0, NULL);
-
-#else
-
- pid = waitpid(-1, &status, 0);
-
-#endif
- // Loop to collect all stopped kids before we go to sleep below.
- do {
- Kid* kid = TheKids.find(pid);
- if (kid) {
- kid->stop(status);
- if (kid->calledExit()) {
- syslog(LOG_NOTICE,
- "Squid Parent: %s process %d exited with status %d",
- kid->name().termedBuf(),
- kid->getPid(), kid->exitStatus());
- } else if (kid->signaled()) {
- syslog(LOG_NOTICE,
- "Squid Parent: %s process %d exited due to signal %d with status %d",
- kid->name().termedBuf(),
- kid->getPid(), kid->termSignal(), kid->exitStatus());
- } else {
- syslog(LOG_NOTICE, "Squid Parent: %s process %d exited",
- kid->name().termedBuf(), kid->getPid());
- }
- if (kid->hopeless()) {
- syslog(LOG_NOTICE, "Squid Parent: %s process %d will not"
- " be restarted due to repeated, frequent failures",
- kid->name().termedBuf(), kid->getPid());
- }
+ // If Squid received a signal while checking for dying kids (below) or
+ // starting new kids (above), then do a fast check for a new dying kid
+ // (WaitForAnyPid with the WNOHANG option) and continue to forward
+ // signals to kids. Otherwise, wait for a kid to die or for a signal
+ // to abort the blocking WaitForAnyPid() call.
+ // With the WNOHANG option, we could check whether WaitForAnyPid() was
+ // aborted by a dying kid or a signal, but it is not required: The
+ // next do/while loop will check again for any dying kids.
+ int waitFlag = 0;
+ if (masterSignaled())
+ waitFlag = WNOHANG;
+ pid = WaitForAnyPid(status, waitFlag);
+
+ // check for a stopped kid
+ Kid* kid = pid > 0 ? TheKids.find(pid) : NULL;
+ if (kid) {
+ kid->stop(status);
+ if (kid->calledExit()) {
+ syslog(LOG_NOTICE,
+ "Squid Parent: %s process %d exited with status %d",
+ kid->name().termedBuf(),
+ kid->getPid(), kid->exitStatus());
+ } else if (kid->signaled()) {
+ syslog(LOG_NOTICE,
+ "Squid Parent: %s process %d exited due to signal %d with status %d",
+ kid->name().termedBuf(),
+ kid->getPid(), kid->termSignal(), kid->exitStatus());
} else {
- syslog(LOG_NOTICE, "Squid Parent: unknown child process %d exited", pid);
+ syslog(LOG_NOTICE, "Squid Parent: %s process %d exited",
+ kid->name().termedBuf(), kid->getPid());
}
-#if _SQUID_NEXT_
- } while ((pid = wait3(&status, WNOHANG, NULL)) > 0);
-#else
+ if (kid->hopeless()) {
+ syslog(LOG_NOTICE, "Squid Parent: %s process %d will not"
+ " be restarted due to repeated, frequent failures",
+ kid->name().termedBuf(), kid->getPid());
+ }
+ } else if (pid > 0){
+ syslog(LOG_NOTICE, "Squid Parent: unknown child process %d exited", pid);
}
- while ((pid = waitpid(-1, &status, WNOHANG)) > 0);
-#endif
if (!TheKids.someRunning() && !TheKids.shouldRestartSome()) {
leave_suid();
RunRegisteredHere(RegisteredRunner::finishShutdown);
enter_suid();
+ removePidFile();
if (TheKids.someSignaled(SIGINT) || TheKids.someSignaled(SIGTERM)) {
syslog(LOG_ALERT, "Exiting due to unexpected forced shutdown");
exit(1);
exit(0);
}
- squid_signal(SIGINT, SIG_DFL, SA_RESTART);
- sleep(3);
+ masterCheckAndBroadcastSignals();
}
/* NOTREACHED */
memClean();
- if (IamPrimaryProcess()) {
- if (Config.pidFilename && strcmp(Config.pidFilename, "none") != 0) {
- enter_suid();
- safeunlink(Config.pidFilename, 0);
- leave_suid();
- }
+ if (!InDaemonMode()) {
+ removePidFile();
}
debugs(1, DBG_IMPORTANT, "Squid Cache (Version " << version_string << "): Exiting normally.");