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