diff options
Diffstat (limited to 'boost/process/detail/posix/wait_group.hpp')
-rw-r--r-- | boost/process/detail/posix/wait_group.hpp | 115 |
1 files changed, 50 insertions, 65 deletions
diff --git a/boost/process/detail/posix/wait_group.hpp b/boost/process/detail/posix/wait_group.hpp index 9dc2498031..d12cce1064 100644 --- a/boost/process/detail/posix/wait_group.hpp +++ b/boost/process/detail/posix/wait_group.hpp @@ -59,15 +59,14 @@ inline bool wait_until( std::error_code & ec) noexcept { - ::sigset_t sigset; ::siginfo_t siginfo; - sigemptyset(&sigset); - sigaddset(&sigset, SIGCHLD); - + bool timed_out = false; + int ret; - auto get_timespec = - [](const Duration & dur) +#if defined(BOOST_POSIX_HAS_SIGTIMEDWAIT) + auto get_timespec = + +[](const Duration & dur) { ::timespec ts; ts.tv_sec = std::chrono::duration_cast<std::chrono::seconds>(dur).count(); @@ -75,9 +74,18 @@ inline bool wait_until( return ts; }; + ::sigset_t sigset; - bool timed_out = false; - int ret; + if (sigemptyset(&sigset) != 0) + { + ec = get_last_error(); + return false; + } + if (sigaddset(&sigset, SIGCHLD) != 0) + { + ec = get_last_error(); + return false; + } struct ::sigaction old_sig; if (-1 == ::sigaction(SIGCHLD, nullptr, &old_sig)) @@ -86,7 +94,6 @@ inline bool wait_until( return false; } -#if defined(BOOST_POSIX_HAS_SIGTIMEDWAIT) do { auto ts = get_timespec(time_out - Clock::now()); @@ -98,80 +105,58 @@ inline bool wait_until( ret = ::waitpid(-p.grp, &siginfo.si_status, 0); //so in case it exited, we wanna reap it first if (ret == -1) { - ec = get_last_error(); - return false; + if ((errno == ECHILD) || (errno == ESRCH)) + { + ec.clear(); + return true; + } + else + { + ec = get_last_error(); + return false; + } } - //check if we're done + //check if we're done -> ret = ::waitid(P_PGID, p.grp, &siginfo, WEXITED | WNOHANG); + } + while (((ret != -1) || ((errno != ECHILD) && (errno != ESRCH))) && !(timed_out = (Clock::now() > time_out))); - } - while (((ret != -1) || (errno != ECHILD)) && !(timed_out = (Clock::now() > time_out))); -#else - //if we do not have sigtimedwait, we fork off a child process to get the signal in time - pid_t timeout_pid = ::fork(); - if (timeout_pid == -1) + if (errno != ECHILD) { ec = boost::process::detail::get_last_error(); - return true; + return !timed_out; } - else if (timeout_pid == 0) + else { - auto ts = get_timespec(time_out - Clock::now()); - ::setpgid(0, p.grp); - ::nanosleep(&ts, nullptr); - ::exit(0); + ec.clear(); + return true; //even if timed out, there are no child proccessess left } - struct child_cleaner_t - { - pid_t pid; - ~child_cleaner_t() - { - int res; - ::kill(pid, -15); - ::waitpid(pid, &res, WNOHANG); - } - }; - child_cleaner_t child_cleaner{timeout_pid}; +#else + ::timespec sleep_interval; + sleep_interval.tv_sec = 0; + sleep_interval.tv_nsec = 1000000; - do - { - int ret_sig = 0; - int status; - if ((::waitpid(timeout_pid, &status, WNOHANG) != 0) - && (WIFEXITED(status) || WIFSIGNALED(status))) - ret = ::sigwait(&sigset, nullptr); - 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 + while (!(timed_out = (Clock::now() > time_out))) + { + ret = ::waitid(P_PGID, p.grp, &siginfo, WEXITED | WSTOPPED | WNOHANG); if (ret == -1) { - ec = get_last_error(); + if ((errno == ECHILD) || (errno == ESRCH)) + { + ec.clear(); + return true; + } + ec = boost::process::detail::get_last_error(); return false; } - - //check if we're done - ret = ::waitid(P_PGID, p.grp, &siginfo, WEXITED | WNOHANG); - + //we can wait, because unlike in the wait_for_exit, we have no race condition regarding eh exit code. + ::nanosleep(&sleep_interval, nullptr); } - while (((ret != -1) || (errno != ECHILD)) && !(timed_out = (Clock::now() > time_out))); - + return !timed_out; #endif - - 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 - } - } template< class Clock, class Duration > |