From e5852f68221c0193df4444ea71f23565ec84c8c9 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Tue, 9 Jun 2015 20:28:24 +0100 Subject: Fix race condition ShellManager::eval with SIGCHLD --- src/shell_manager.cc | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'src/shell_manager.cc') 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 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 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()) -- cgit v1.2.3