diff options
Diffstat (limited to 'boost/process/detail/posix/wait_for_exit.hpp')
-rw-r--r-- | boost/process/detail/posix/wait_for_exit.hpp | 66 |
1 files changed, 50 insertions, 16 deletions
diff --git a/boost/process/detail/posix/wait_for_exit.hpp b/boost/process/detail/posix/wait_for_exit.hpp index 5eadc9725c..376e480251 100644 --- a/boost/process/detail/posix/wait_for_exit.hpp +++ b/boost/process/detail/posix/wait_for_exit.hpp @@ -54,11 +54,35 @@ inline bool wait_until( const std::chrono::time_point<Clock, Duration>& time_out, std::error_code & ec) noexcept { - ::sigset_t sigset; - sigemptyset(&sigset); - sigaddset(&sigset, SIGCHLD); + //I need to set the signal, because it might be ignore / default, in which case sigwait might not work. + + using _signal_t = void(*)(int); + static thread_local _signal_t sigchld_handler = SIG_DFL; + + struct signal_interceptor_t + { + static void handler_func(int val) + { + if ((sigchld_handler != SIG_DFL) && (sigchld_handler != SIG_IGN)) + sigchld_handler(val); + } + signal_interceptor_t() { sigchld_handler = ::signal(SIGCHLD, &handler_func); } + ~signal_interceptor_t() { ::signal(SIGCHLD, sigchld_handler); sigchld_handler = SIG_DFL;} + + } signal_interceptor{}; + + if (sigemptyset(&sigset) != 0) + { + ec = get_last_error(); + return false; + } + if (sigaddset(&sigset, SIGCHLD) != 0) + { + ec = get_last_error(); + return false; + } auto get_timespec = [](const Duration & dur) @@ -69,8 +93,8 @@ inline bool wait_until( return ts; }; - pid_t ret; - int status; + int ret; + int status{0}; struct ::sigaction old_sig; if (-1 == ::sigaction(SIGCHLD, nullptr, &old_sig)) @@ -80,6 +104,7 @@ inline bool wait_until( } bool timed_out; + #if defined(BOOST_POSIX_HAS_SIGTIMEDWAIT) do { @@ -113,9 +138,16 @@ inline bool wait_until( { auto ts = get_timespec(time_out - Clock::now()); ::timespec rem; - ::nanosleep(&ts, &rem); - while (rem.tv_sec > 0 || rem.tv_nsec > 0) - ::nanosleep(&rem, &rem); + while (ts.tv_sec > 0 || ts.tv_nsec > 0) + { + if (::nanosleep(&ts, &rem) != 0) + { + auto err = errno; + if ((err == EINVAL) || (err == EFAULT)) + break; + } + ts = get_timespec(time_out - Clock::now()); + } ::exit(0); } @@ -125,7 +157,7 @@ inline bool wait_until( ~child_cleaner_t() { int res; - ::kill(pid, -15); + ::kill(pid, SIGKILL); ::waitpid(pid, &res, WNOHANG); } }; @@ -133,19 +165,21 @@ inline bool wait_until( do { - int ret_sig = 0; + int sig_{0}; if ((::waitpid(timeout_pid, &status, WNOHANG) != 0) - && (WIFEXITED(status) || WIFSIGNALED(status))) - ret_sig = ::sigwait(&sigset, nullptr); - errno = 0; + && (WIFEXITED(status) || WIFSIGNALED(status))) - ret = ::waitpid(p.pid, &status, WNOHANG); + return false; - if ((ret_sig == SIGCHLD) && + ret = ::sigwait(&sigset, &sig_); + errno = 0; + + if ((sig_ == SIGCHLD) && (old_sig.sa_handler != SIG_DFL) && (old_sig.sa_handler != SIG_IGN)) old_sig.sa_handler(ret); - if (ret <= 0) + ret = ::waitpid(p.pid, &status, WNOHANG); + if (ret == 0) // == > is running { timed_out = Clock::now() >= time_out; if (timed_out) |