summaryrefslogtreecommitdiff
path: root/boost/process/detail/posix/wait_for_exit.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/process/detail/posix/wait_for_exit.hpp')
-rw-r--r--boost/process/detail/posix/wait_for_exit.hpp66
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)