Handle SIGCHLD for exec/forkExec

When forkExec is called it begins to ignore all SIGCHLD signals for
the rest of the progam's execution so that they are automatically
reaped. However, this means that subsequent waitpid calls in the exec
function will always fail. So instead handle SIGCHLD by reaping any
processes created by forkExec and ignoring all others so that they can be
handled directly by the exec function.
pull/778/head
excellentname 2020-07-21 12:36:48 +10:00
parent 759602af64
commit 246f7bf555
2 changed files with 36 additions and 2 deletions

View File

@ -7,6 +7,9 @@
#include <array>
extern sig_atomic_t is_inserting_pid;
extern std::list<pid_t> reap;
namespace waybar::util::command {
struct res {
@ -32,10 +35,11 @@ inline std::string read(FILE* fp) {
inline int close(FILE* fp, pid_t pid) {
int stat = -1;
pid_t ret;
fclose(fp);
do {
waitpid(pid, &stat, WCONTINUED | WUNTRACED);
ret = waitpid(pid, &stat, WCONTINUED | WUNTRACED);
if (WIFEXITED(stat)) {
spdlog::debug("Cmd exited with code {}", WEXITSTATUS(stat));
@ -45,6 +49,8 @@ inline int close(FILE* fp, pid_t pid) {
spdlog::debug("Cmd stopped by {}", WSTOPSIG(stat));
} else if (WIFCONTINUED(stat)) {
spdlog::debug("Cmd continued");
} else if (ret == -1) {
spdlog::debug("waitpid failed: {}", strerror(errno));
} else {
break;
}
@ -111,7 +117,9 @@ inline int32_t forkExec(const std::string& cmd) {
execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
exit(0);
} else {
signal(SIGCHLD, SIG_IGN);
is_inserting_pid = true;
reap.push_back(pid);
is_inserting_pid = false;
}
return pid;

View File

@ -1,7 +1,32 @@
#include <csignal>
#include <list>
#include <sys/types.h>
#include <sys/wait.h>
#include <spdlog/spdlog.h>
#include "client.hpp"
sig_atomic_t is_inserting_pid = false;
std::list<pid_t> reap;
static void handler(int sig) {
int saved_errno = errno;
if (!is_inserting_pid) {
for (auto it = reap.begin(); it != reap.end(); ++it) {
if (waitpid(*it, nullptr, WNOHANG) == *it) {
it = reap.erase(it);
}
}
}
errno = saved_errno;
}
inline void installSigChldHandler(void) {
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_handler = handler;
sigaction(SIGCHLD, &sa, nullptr);
}
int main(int argc, char* argv[]) {
try {
auto client = waybar::Client::inst();
@ -18,6 +43,7 @@ int main(int argc, char* argv[]) {
}
});
}
installSigChldHandler();
auto ret = client->main(argc, argv);
delete client;