Merge pull request #9518 from Icinga/9481

StartUnixWorker(): watch forked child via waitpid(), not SIGCHLD handler
This commit is contained in:
Julian Brost 2022-10-10 14:36:52 +02:00 committed by GitHub
commit 9be02e3f04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -324,22 +324,11 @@ int RunWorker(const std::vector<std::string>& configs, bool closeConsoleLog = fa
} }
#ifndef _WIN32 #ifndef _WIN32
/**
* The possible states of a seamless worker being started by StartUnixWorker().
*/
enum class UnixWorkerState : uint_fast8_t
{
Pending,
LoadedConfig,
Failed
};
// The signals to block temporarily in StartUnixWorker(). // The signals to block temporarily in StartUnixWorker().
static const sigset_t l_UnixWorkerSignals = ([]() -> sigset_t { static const sigset_t l_UnixWorkerSignals = ([]() -> sigset_t {
sigset_t s; sigset_t s;
(void)sigemptyset(&s); (void)sigemptyset(&s);
(void)sigaddset(&s, SIGCHLD);
(void)sigaddset(&s, SIGUSR1); (void)sigaddset(&s, SIGUSR1);
(void)sigaddset(&s, SIGUSR2); (void)sigaddset(&s, SIGUSR2);
(void)sigaddset(&s, SIGINT); (void)sigaddset(&s, SIGINT);
@ -353,7 +342,7 @@ static const sigset_t l_UnixWorkerSignals = ([]() -> sigset_t {
static Atomic<pid_t> l_CurrentlyStartingUnixWorkerPid (-1); static Atomic<pid_t> l_CurrentlyStartingUnixWorkerPid (-1);
// The state of the seamless worker currently being started by StartUnixWorker() // The state of the seamless worker currently being started by StartUnixWorker()
static Atomic<UnixWorkerState> l_CurrentlyStartingUnixWorkerState (UnixWorkerState::Pending); static Atomic<bool> l_CurrentlyStartingUnixWorkerReady (false);
// The last temination signal we received // The last temination signal we received
static Atomic<int> l_TermSignal (-1); static Atomic<int> l_TermSignal (-1);
@ -375,17 +364,10 @@ static void UmbrellaSignalHandler(int num, siginfo_t *info, void*)
l_RequestedReopenLogs.store(true); l_RequestedReopenLogs.store(true);
break; break;
case SIGUSR2: case SIGUSR2:
if (l_CurrentlyStartingUnixWorkerState.load() == UnixWorkerState::Pending if (!l_CurrentlyStartingUnixWorkerReady.load()
&& (info->si_pid == 0 || info->si_pid == l_CurrentlyStartingUnixWorkerPid.load()) ) { && (info->si_pid == 0 || info->si_pid == l_CurrentlyStartingUnixWorkerPid.load()) ) {
// The seamless worker currently being started by StartUnixWorker() successfully loaded its config // The seamless worker currently being started by StartUnixWorker() successfully loaded its config
l_CurrentlyStartingUnixWorkerState.store(UnixWorkerState::LoadedConfig); l_CurrentlyStartingUnixWorkerReady.store(true);
}
break;
case SIGCHLD:
if (l_CurrentlyStartingUnixWorkerState.load() == UnixWorkerState::Pending
&& (info->si_pid == 0 || info->si_pid == l_CurrentlyStartingUnixWorkerPid.load()) ) {
// The seamless worker currently being started by StartUnixWorker() failed
l_CurrentlyStartingUnixWorkerState.store(UnixWorkerState::Failed);
} }
break; break;
case SIGINT: case SIGINT:
@ -483,7 +465,7 @@ static pid_t StartUnixWorker(const std::vector<std::string>& configs, bool close
} }
/* Block the signal handlers we'd like to change in the child process until we changed them. /* Block the signal handlers we'd like to change in the child process until we changed them.
* Block SIGUSR2 and SIGCHLD handlers until we've set l_CurrentlyStartingUnixWorkerPid. * Block SIGUSR2 handler until we've set l_CurrentlyStartingUnixWorkerPid.
*/ */
(void)sigprocmask(SIG_BLOCK, &l_UnixWorkerSignals, nullptr); (void)sigprocmask(SIG_BLOCK, &l_UnixWorkerSignals, nullptr);
@ -513,7 +495,6 @@ static pid_t StartUnixWorker(const std::vector<std::string>& configs, bool close
sa.sa_handler = SIG_DFL; sa.sa_handler = SIG_DFL;
(void)sigaction(SIGCHLD, &sa, nullptr);
(void)sigaction(SIGUSR1, &sa, nullptr); (void)sigaction(SIGUSR1, &sa, nullptr);
(void)sigaction(SIGHUP, &sa, nullptr); (void)sigaction(SIGHUP, &sa, nullptr);
} }
@ -570,33 +551,26 @@ static pid_t StartUnixWorker(const std::vector<std::string>& configs, bool close
NotifyWatchdog(); NotifyWatchdog();
#endif /* HAVE_SYSTEMD */ #endif /* HAVE_SYSTEMD */
switch (l_CurrentlyStartingUnixWorkerState.load()) { if (waitpid(pid, nullptr, WNOHANG) > 0) {
case UnixWorkerState::LoadedConfig: Log(LogNotice, "cli")
Log(LogNotice, "cli") << "Worker process couldn't load its config";
<< "Worker process successfully loaded its config";
break;
case UnixWorkerState::Failed:
Log(LogNotice, "cli")
<< "Worker process couldn't load its config";
while (waitpid(pid, nullptr, 0) == -1 && errno == EINTR) { pid = -2;
#ifdef HAVE_SYSTEMD break;
NotifyWatchdog();
#endif /* HAVE_SYSTEMD */
}
pid = -2;
break;
default:
Utility::Sleep(0.2);
continue;
} }
break; if (l_CurrentlyStartingUnixWorkerReady.load()) {
Log(LogNotice, "cli")
<< "Worker process successfully loaded its config";
break;
}
Utility::Sleep(0.2);
} }
// Reset flags for the next time // Reset flags for the next time
l_CurrentlyStartingUnixWorkerPid.store(-1); l_CurrentlyStartingUnixWorkerPid.store(-1);
l_CurrentlyStartingUnixWorkerState.store(UnixWorkerState::Pending); l_CurrentlyStartingUnixWorkerReady.store(false);
try { try {
Application::InitializeBase(); Application::InitializeBase();
@ -734,7 +708,6 @@ int DaemonCommand::Run(const po::variables_map& vm, const std::vector<std::strin
sa.sa_sigaction = &UmbrellaSignalHandler; sa.sa_sigaction = &UmbrellaSignalHandler;
sa.sa_flags = SA_NOCLDSTOP | SA_RESTART | SA_SIGINFO; sa.sa_flags = SA_NOCLDSTOP | SA_RESTART | SA_SIGINFO;
(void)sigaction(SIGCHLD, &sa, nullptr);
(void)sigaction(SIGUSR1, &sa, nullptr); (void)sigaction(SIGUSR1, &sa, nullptr);
(void)sigaction(SIGUSR2, &sa, nullptr); (void)sigaction(SIGUSR2, &sa, nullptr);
(void)sigaction(SIGINT, &sa, nullptr); (void)sigaction(SIGINT, &sa, nullptr);