From d6a306e745acfee00e81ccaf3324a2a03516db41 Mon Sep 17 00:00:00 2001 From: DongHun Kwak Date: Thu, 5 Dec 2019 15:21:30 +0900 Subject: Imported Upstream version 1.69.0 --- boost/process/detail/posix/wait_group.hpp | 81 +++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 19 deletions(-) (limited to 'boost/process/detail/posix/wait_group.hpp') diff --git a/boost/process/detail/posix/wait_group.hpp b/boost/process/detail/posix/wait_group.hpp index 024d9003b9..ff2fe6d30d 100644 --- a/boost/process/detail/posix/wait_group.hpp +++ b/boost/process/detail/posix/wait_group.hpp @@ -22,15 +22,23 @@ namespace boost { namespace process { namespace detail { namespace posix { inline void wait(const group_handle &p, std::error_code &ec) noexcept { pid_t ret; - int status; + siginfo_t status; do { - ret = ::waitpid(-p.grp, &status, 0); - } - while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status) && !WIFSIGNALED(status))); + ret = ::waitpid(-p.grp, &status.si_status, 0); + if (ret == -1) + { + ec = get_last_error(); + return; + } - if (ret == -1) + //ECHILD --> no child processes left. + ret = ::waitid(P_PGID, p.grp, &status, WEXITED | WNOHANG); + } + while ((ret != -1) || (errno != ECHILD)); + + if (errno != ECHILD) ec = boost::process::detail::get_last_error(); else ec.clear(); @@ -49,31 +57,66 @@ inline bool wait_until( const std::chrono::time_point& time_out, std::error_code & ec) noexcept { - pid_t ret; - int status; - bool timed_out; + ::sigset_t sigset; + ::siginfo_t siginfo; + + ::sigemptyset(&sigset); + ::sigaddset(&sigset, SIGCHLD); + + auto get_timespec = + [](const Duration & dur) + { + ::timespec ts; + ts.tv_sec = std::chrono::duration_cast(dur).count(); + ts.tv_nsec = std::chrono::duration_cast(dur).count() % 1000000000; + return ts; + }; + + + bool timed_out = false; + int ret; + + struct ::sigaction old_sig; + if (-1 == ::sigaction(SIGCHLD, nullptr, &old_sig)) + { + ec = get_last_error(); + return false; + } do { - ret = ::waitpid(-p.grp, &status, WNOHANG); - if (ret == 0) + auto ts = get_timespec(time_out - Clock::now()); + ret = ::sigtimedwait(&sigset, nullptr, &ts); + errno = 0; + if ((ret == SIGCHLD) && (old_sig.sa_handler != SIG_DFL) && (old_sig.sa_handler != SIG_IGN)) + old_sig.sa_handler(ret); + + ret = ::waitpid(-p.grp, &siginfo.si_status, 0); //so in case it exited, we wanna reap it first + if (ret == -1) { - timed_out = Clock::now() >= time_out; - if (timed_out) - return false; + ec = get_last_error(); + return false; } - } - while ((ret == 0) || - (((ret == -1) && errno == EINTR) || - ((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status)))); - if (ret == -1) + + //check if we're done + ret = ::waitid(P_PGID, p.grp, &siginfo, WEXITED | WNOHANG); + + } + while (((ret != -1) || (errno != ECHILD)) && !(timed_out = (Clock::now() > time_out))) ; + + if (errno != ECHILD) + { ec = boost::process::detail::get_last_error(); + return !timed_out; + } else + { ec.clear(); + return true; //even if timed out, there are no child proccessess left + } - return true; } template< class Clock, class Duration > -- cgit v1.2.3