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.
This commit is contained in:
parent
759602af64
commit
246f7bf555
|
@ -7,6 +7,9 @@
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
|
extern sig_atomic_t is_inserting_pid;
|
||||||
|
extern std::list<pid_t> reap;
|
||||||
|
|
||||||
namespace waybar::util::command {
|
namespace waybar::util::command {
|
||||||
|
|
||||||
struct res {
|
struct res {
|
||||||
|
@ -32,10 +35,11 @@ inline std::string read(FILE* fp) {
|
||||||
|
|
||||||
inline int close(FILE* fp, pid_t pid) {
|
inline int close(FILE* fp, pid_t pid) {
|
||||||
int stat = -1;
|
int stat = -1;
|
||||||
|
pid_t ret;
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
do {
|
do {
|
||||||
waitpid(pid, &stat, WCONTINUED | WUNTRACED);
|
ret = waitpid(pid, &stat, WCONTINUED | WUNTRACED);
|
||||||
|
|
||||||
if (WIFEXITED(stat)) {
|
if (WIFEXITED(stat)) {
|
||||||
spdlog::debug("Cmd exited with code {}", WEXITSTATUS(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));
|
spdlog::debug("Cmd stopped by {}", WSTOPSIG(stat));
|
||||||
} else if (WIFCONTINUED(stat)) {
|
} else if (WIFCONTINUED(stat)) {
|
||||||
spdlog::debug("Cmd continued");
|
spdlog::debug("Cmd continued");
|
||||||
|
} else if (ret == -1) {
|
||||||
|
spdlog::debug("waitpid failed: {}", strerror(errno));
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -111,7 +117,9 @@ inline int32_t forkExec(const std::string& cmd) {
|
||||||
execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
|
execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
|
||||||
exit(0);
|
exit(0);
|
||||||
} else {
|
} else {
|
||||||
signal(SIGCHLD, SIG_IGN);
|
is_inserting_pid = true;
|
||||||
|
reap.push_back(pid);
|
||||||
|
is_inserting_pid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pid;
|
return pid;
|
||||||
|
|
26
src/main.cpp
26
src/main.cpp
|
@ -1,7 +1,32 @@
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
|
#include <list>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
#include "client.hpp"
|
#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[]) {
|
int main(int argc, char* argv[]) {
|
||||||
try {
|
try {
|
||||||
auto client = waybar::Client::inst();
|
auto client = waybar::Client::inst();
|
||||||
|
@ -18,6 +43,7 @@ int main(int argc, char* argv[]) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
installSigChldHandler();
|
||||||
|
|
||||||
auto ret = client->main(argc, argv);
|
auto ret = client->main(argc, argv);
|
||||||
delete client;
|
delete client;
|
||||||
|
|
Loading…
Reference in New Issue