summaryrefslogtreecommitdiff
path: root/src/shell_manager.cc
diff options
context:
space:
mode:
authorMaxime Coste <frrrwww@gmail.com>2015-06-09 20:28:24 +0100
committerMaxime Coste <frrrwww@gmail.com>2015-06-09 20:28:24 +0100
commite5852f68221c0193df4444ea71f23565ec84c8c9 (patch)
treec6f2cbba19889ccdd3486b59516b925896102289 /src/shell_manager.cc
parentb4329dd6431e47009ab0f16d05a98646d80ab9b6 (diff)
Fix race condition ShellManager::eval with SIGCHLD
Diffstat (limited to 'src/shell_manager.cc')
-rw-r--r--src/shell_manager.cc15
1 files changed, 13 insertions, 2 deletions
diff --git a/src/shell_manager.cc b/src/shell_manager.cc
index 3a64eef2..37221204 100644
--- a/src/shell_manager.cc
+++ b/src/shell_manager.cc
@@ -45,7 +45,6 @@ std::pair<String, int> ShellManager::eval(
String child_stdout, child_stderr;
int status = 0;
- bool terminated = false;
{
auto pipe_reader = [](String& output) {
return [&output](FDWatcher& watcher, EventMode) {
@@ -60,18 +59,30 @@ std::pair<String, int> ShellManager::eval(
FDWatcher stdout_watcher{read_pipe[0], pipe_reader(child_stdout)};
FDWatcher stderr_watcher{error_pipe[0], pipe_reader(child_stderr)};
+ // block SIGCHLD to make sure we wont receive it before
+ // our call to pselect, that will end up blocking indefinitly.
+ sigset_t mask, orig_mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &mask, &orig_mask);
+
+ // check for termination now that SIGCHLD is blocked
+ bool terminated = waitpid(pid, &status, WNOHANG);
+
while (not terminated or
((flags & Flags::WaitForStdout) and
(not stdout_watcher.closed() or
not stderr_watcher.closed())))
{
- EventManager::instance().handle_next_events(EventMode::Urgent);
+ EventManager::instance().handle_next_events(EventMode::Urgent, &orig_mask);
if (not terminated)
terminated = waitpid(pid, &status, WNOHANG);
}
stdout_watcher.close_fd();
stderr_watcher.close_fd();
+
+ sigprocmask(SIG_SETMASK, &orig_mask, nullptr);
}
if (not child_stderr.empty())