summaryrefslogtreecommitdiff
path: root/boost/process
diff options
context:
space:
mode:
authorDongHun Kwak <dh0128.kwak@samsung.com>2019-12-05 15:21:30 +0900
committerDongHun Kwak <dh0128.kwak@samsung.com>2019-12-05 15:21:30 +0900
commitd6a306e745acfee00e81ccaf3324a2a03516db41 (patch)
tree145a26368608982f40ebb0f4836185c44abb9ae4 /boost/process
parent5ce2ccf2f23c6d3de4c79f216f57ca6f2a18ed16 (diff)
downloadboost-d6a306e745acfee00e81ccaf3324a2a03516db41.tar.gz
boost-d6a306e745acfee00e81ccaf3324a2a03516db41.tar.bz2
boost-d6a306e745acfee00e81ccaf3324a2a03516db41.zip
Imported Upstream version 1.69.0upstream/1.69.0
Diffstat (limited to 'boost/process')
-rw-r--r--boost/process/detail/posix/executor.hpp22
-rw-r--r--boost/process/detail/posix/wait_for_exit.hpp32
-rw-r--r--boost/process/detail/posix/wait_group.hpp81
-rw-r--r--boost/process/detail/windows/executor.hpp2
-rw-r--r--boost/process/detail/windows/group_handle.hpp27
-rw-r--r--boost/process/detail/windows/job_workaround.hpp242
-rw-r--r--boost/process/detail/windows/wait_group.hpp73
-rw-r--r--boost/process/system.hpp2
8 files changed, 374 insertions, 107 deletions
diff --git a/boost/process/detail/posix/executor.hpp b/boost/process/detail/posix/executor.hpp
index b3781f2f04..1390a58ee6 100644
--- a/boost/process/detail/posix/executor.hpp
+++ b/boost/process/detail/posix/executor.hpp
@@ -45,7 +45,7 @@ inline int execvpe(const char* filename, char * const arg_list[], char* env[])
if (e != nullptr)
{
- std::vector<std::string> path;
+ std::vector<std::string> path;
boost::split(path, *e, boost::is_any_of(":"));
for (const std::string & pp : path)
@@ -85,7 +85,7 @@ struct on_error_t
template<typename T>
void operator()(T & t) const
{
- t.on_error(exec, error);
+ t.on_error(exec, error);
}
};
@@ -157,13 +157,13 @@ struct on_fork_success_t
};
template<typename Executor> on_setup_t <Executor> call_on_setup (Executor & exec) {return exec;}
-template<typename Executor> on_error_t <Executor> call_on_error (Executor & exec, const std::error_code & ec)
+template<typename Executor> on_error_t <Executor> call_on_error (Executor & exec, const std::error_code & ec)
{
return on_error_t<Executor> (exec, ec);
}
template<typename Executor> on_success_t<Executor> call_on_success(Executor & exec) {return exec;}
-template<typename Executor> on_fork_error_t <Executor> call_on_fork_error (Executor & exec, const std::error_code & ec)
+template<typename Executor> on_fork_error_t <Executor> call_on_fork_error (Executor & exec, const std::error_code & ec)
{
return on_fork_error_t<Executor> (exec, ec);
}
@@ -293,10 +293,14 @@ class executor
auto err = errno;
if ((err == EBADF) || (err == EPERM))//that should occur on success, therefore return.
return;
- //EAGAIN not yet forked, EINTR interrupted, i.e. try again
+ //EAGAIN not yet forked, EINTR interrupted, i.e. try again
else if ((err != EAGAIN ) && (err != EINTR))
+ {
+ ::close(source);
set_error(std::error_code(err, std::system_category()), "Error read pipe");
+ }
}
+ ::close(source);
set_error(ec, std::move(msg));
}
@@ -376,7 +380,10 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
}
if (::fcntl(p[1], F_SETFD, FD_CLOEXEC) == -1)
{
- set_error(::boost::process::detail::get_last_error(), "fcntl(2) failed");
+ auto err = ::boost::process::detail::get_last_error();
+ ::close(p[0]);
+ ::close(p[1]);
+ set_error(err, "fcntl(2) failed");
return child();
}
_ec.clear();
@@ -420,11 +427,8 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
child c(child_handle(pid), exit_status);
-
-
::close(p[1]);
_read_error(p[0]);
- ::close(p[0]);
if (_ec)
{
diff --git a/boost/process/detail/posix/wait_for_exit.hpp b/boost/process/detail/posix/wait_for_exit.hpp
index 9c40af1624..4e734322d2 100644
--- a/boost/process/detail/posix/wait_for_exit.hpp
+++ b/boost/process/detail/posix/wait_for_exit.hpp
@@ -28,7 +28,8 @@ inline void wait(const child_handle &p, int & exit_code, std::error_code &ec) no
{
ret = ::waitpid(p.pid, &status, 0);
}
- while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status) && !WIFSIGNALED(status)));
+ while (((ret == -1) && (errno == EINTR)) ||
+ (ret != -1 && !WIFEXITED(status) && !WIFSIGNALED(status)));
if (ret == -1)
ec = boost::process::detail::get_last_error();
@@ -53,14 +54,43 @@ 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);
+
+ auto get_timespec =
+ [](const Duration & dur)
+ {
+ ::timespec ts;
+ ts.tv_sec = std::chrono::duration_cast<std::chrono::seconds>(dur).count();
+ ts.tv_nsec = std::chrono::duration_cast<std::chrono::nanoseconds>(dur).count() % 1000000000;
+ return ts;
+ };
+
pid_t ret;
int status;
+ struct ::sigaction old_sig;
+ if (-1 == ::sigaction(SIGCHLD, nullptr, &old_sig))
+ {
+ ec = get_last_error();
+ return false;
+ }
+
bool timed_out;
do
{
+ auto ts = get_timespec(time_out - Clock::now());
+ auto ret_sig = ::sigtimedwait(&sigset, nullptr, &ts);
+ errno = 0;
ret = ::waitpid(p.pid, &status, WNOHANG);
+
+ if ((ret_sig == SIGCHLD) && (old_sig.sa_handler != SIG_DFL) && (old_sig.sa_handler != SIG_IGN))
+ old_sig.sa_handler(ret);
+
if (ret == 0)
{
timed_out = Clock::now() >= time_out;
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<Clock, Duration>& 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<std::chrono::seconds>(dur).count();
+ ts.tv_nsec = std::chrono::duration_cast<std::chrono::nanoseconds>(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 >
diff --git a/boost/process/detail/windows/executor.hpp b/boost/process/detail/windows/executor.hpp
index bc52cbb5fe..6321b619c7 100644
--- a/boost/process/detail/windows/executor.hpp
+++ b/boost/process/detail/windows/executor.hpp
@@ -84,7 +84,7 @@ struct startup_info_impl
void set_startup_info_ex()
{
startup_info.cb = sizeof(startup_info_ex_t);
- creation_flags = ::boost::winapi::EXTENDED_STARTUPINFO_PRESENT_;
+ creation_flags |= ::boost::winapi::EXTENDED_STARTUPINFO_PRESENT_;
}
};
diff --git a/boost/process/detail/windows/group_handle.hpp b/boost/process/detail/windows/group_handle.hpp
index 42b0a9280d..b3f7143c6d 100644
--- a/boost/process/detail/windows/group_handle.hpp
+++ b/boost/process/detail/windows/group_handle.hpp
@@ -84,22 +84,37 @@ inline void enable_break_away(::boost::winapi::HANDLE_ h, std::error_code & ec)
ec = get_last_error();
return;
}
+}
+inline void associate_completion_port(::boost::winapi::HANDLE_ job,
+ ::boost::winapi::HANDLE_ io_port)
+{
+ workaround::JOBOBJECT_ASSOCIATE_COMPLETION_PORT_ port;
+ port.CompletionKey = job;
+ port.CompletionPort = io_port;
+ if (!workaround::set_information_job_object(
+ job,
+ workaround::JobObjectAssociateCompletionPortInformation_,
+ static_cast<void*>(&port),
+ sizeof(port)))
+ throw_last_error("SetInformationJobObject() failed");
}
-
struct group_handle
{
::boost::winapi::HANDLE_ _job_object;
+ ::boost::winapi::HANDLE_ _io_port;
typedef ::boost::winapi::HANDLE_ handle_t;
handle_t handle() const { return _job_object; }
explicit group_handle(handle_t h) :
- _job_object(h)
+ _job_object(h),
+ _io_port(::CreateIoCompletionPort(::boost::winapi::INVALID_HANDLE_VALUE_, nullptr, 0, 1))
{
enable_break_away(_job_object);
+ associate_completion_port(_job_object, _io_port);
}
@@ -110,15 +125,21 @@ struct group_handle
~group_handle()
{
::boost::winapi::CloseHandle(_job_object);
+ ::boost::winapi::CloseHandle(_io_port);
}
group_handle(const group_handle & c) = delete;
- group_handle(group_handle && c) : _job_object(c._job_object)
+ group_handle(group_handle && c) : _job_object(c._job_object),
+ _io_port(c._io_port)
{
c._job_object = ::boost::winapi::invalid_handle_value;
+ c._io_port = ::boost::winapi::invalid_handle_value;
}
group_handle &operator=(const group_handle & c) = delete;
group_handle &operator=(group_handle && c)
{
+ ::boost::winapi::CloseHandle(_io_port);
+ _io_port = c._io_port;
+ c._io_port = ::boost::winapi::invalid_handle_value;
::boost::winapi::CloseHandle(_job_object);
_job_object = c._job_object;
diff --git a/boost/process/detail/windows/job_workaround.hpp b/boost/process/detail/windows/job_workaround.hpp
index 574e406609..3f15d1c195 100644
--- a/boost/process/detail/windows/job_workaround.hpp
+++ b/boost/process/detail/windows/job_workaround.hpp
@@ -9,68 +9,184 @@
#include <boost/winapi/config.hpp>
#include <boost/winapi/basic_types.hpp>
#include <boost/winapi/dll.hpp>
+#include <boost/winapi/overlapped.hpp>
+#if defined( BOOST_USE_WINDOWS_H )
+#include <windows.h>
+#else
+extern "C"
+{
+BOOST_SYMBOL_IMPORT ::boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC CreateIoCompletionPort(
+ ::boost::winapi::HANDLE_ FileHandle,
+ ::boost::winapi::HANDLE_ ExistingCompletionPort,
+ ::boost::winapi::ULONG_PTR_ CompletionKey,
+ ::boost::winapi::DWORD_ NumberOfConcurrentThreads
+);
+
+BOOST_SYMBOL_IMPORT ::boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC GetQueuedCompletionStatus(
+ ::boost::winapi::HANDLE_ CompletionPort,
+ ::boost::winapi::LPDWORD_ lpNumberOfBytes,
+ ::boost::winapi::ULONG_PTR_ *lpCompletionKey,
+ _OVERLAPPED **lpOverlapped,
+ ::boost::winapi::DWORD_ dwMilliseconds
+);
+
+}
+#endif
namespace boost { namespace process { namespace detail { namespace windows { namespace workaround {
+extern "C"
+{
+
+struct JOBOBJECT_ASSOCIATE_COMPLETION_PORT_
+{
+ ::boost::winapi::PVOID_ CompletionKey;
+ ::boost::winapi::HANDLE_ CompletionPort;
+};
+
+constexpr static int JOB_OBJECT_MSG_END_OF_JOB_TIME_ = 1;
+constexpr static int JOB_OBJECT_MSG_END_OF_PROCESS_TIME_ = 2;
+constexpr static int JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT_ = 3;
+constexpr static int JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO_ = 4;
+constexpr static int JOB_OBJECT_MSG_NEW_PROCESS_ = 6;
+constexpr static int JOB_OBJECT_MSG_EXIT_PROCESS_ = 7;
+constexpr static int JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS_ = 8;
+constexpr static int JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT_ = 9;
+constexpr static int JOB_OBJECT_MSG_JOB_MEMORY_LIMIT_ = 10;
+constexpr static int JOB_OBJECT_MSG_NOTIFICATION_LIMIT_ = 11;
+constexpr static int JOB_OBJECT_MSG_JOB_CYCLE_TIME_LIMIT_ = 12;
+constexpr static int JOB_OBJECT_MSG_SILO_TERMINATED_ = 13;
+
+}
+
+BOOST_FORCEINLINE ::boost::winapi::BOOL_ get_queued_completion_status(
+ ::boost::winapi::HANDLE_ CompletionPort,
+ ::boost::winapi::LPDWORD_ lpNumberOfBytes,
+ ::boost::winapi::ULONG_PTR_ *lpCompletionKey,
+ ::boost::winapi::LPOVERLAPPED_ *lpOverlapped,
+ ::boost::winapi::DWORD_ dwMilliseconds)
+{
+ return ::GetQueuedCompletionStatus(
+ CompletionPort,
+ lpNumberOfBytes,
+ lpCompletionKey,
+ reinterpret_cast<::_OVERLAPPED**>(lpOverlapped),
+ dwMilliseconds);
+}
+
+#if defined( BOOST_USE_WINDOWS_H )
+
+constexpr auto static JobObjectExtendedLimitInformation_ = ::JobObjectExtendedLimitInformation;
+constexpr auto static JobObjectAssociateCompletionPortInformation_ = ::JobObjectAssociateCompletionPortInformation;
+constexpr auto static JobObjectBasicAccountingInformation_ = ::JobObjectBasicAccountingInformation;
+
+using JOBOBJECT_BASIC_LIMIT_INFORMATION_ = ::JOBOBJECT_BASIC_LIMIT_INFORMATION;
+using JOBOBJECTINFOCLASS_ = ::JOBOBJECTINFOCLASS;
+using IO_COUNTERS_ = ::IO_COUNTERS;
+using JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ = ::JOBOBJECT_EXTENDED_LIMIT_INFORMATION;
+using JOBOBJECT_BASIC_ACCOUNTING_INFORMATION_ = ::JOBOBJECT_BASIC_ACCOUNTING_INFORMATION;
+
+inline ::boost::winapi::BOOL_ query_information_job_object(
+ ::boost::winapi::HANDLE_ hJob,
+ JOBOBJECTINFOCLASS_ JobObjectInfoClass,
+ void * lpJobObjectInfo,
+ ::boost::winapi::DWORD_ cbJobObjectInfoLength,
+ ::boost::winapi::DWORD_ *lpReturnLength)
+{
+ return ::QueryInformationJobObject(hJob, JobObjectInfoClass, lpJobObjectInfo, cbJobObjectInfoLength, lpReturnLength);
+}
+
+inline ::boost::winapi::BOOL_ set_information_job_object(
+ ::boost::winapi::HANDLE_ hJob,
+ JOBOBJECTINFOCLASS_ JobObjectInfoClass,
+ void * lpJobObjectInfo,
+ ::boost::winapi::DWORD_ cbJobObjectInfoLength)
+{
+ return ::SetInformationJobObject(hJob, JobObjectInfoClass, lpJobObjectInfo, cbJobObjectInfoLength);
+}
+
+
+#else
+
//this import workaround is to keep it a header-only library. and enums cannot be imported from the winapi.
extern "C"
{
-typedef enum _JOBOBJECTINFOCLASS_ {
- JobObjectBasicAccountingInformation_ = 1, JobObjectBasicLimitInformation_,
- JobObjectBasicProcessIdList_, JobObjectBasicUIRestrictions_,
- JobObjectSecurityLimitInformation_, JobObjectEndOfJobTimeInformation_,
- JobObjectAssociateCompletionPortInformation_, JobObjectBasicAndIoAccountingInformation_,
- JobObjectExtendedLimitInformation_, JobObjectJobSetInformation_,
- JobObjectGroupInformation_,
- JobObjectNotificationLimitInformation_,
- JobObjectLimitViolationInformation_,
- JobObjectGroupInformationEx_,
- JobObjectCpuRateControlInformation_,
- JobObjectCompletionFilter_,
- JobObjectCompletionCounter_,
- JobObjectReserved1Information_ = 18,
- JobObjectReserved2Information_,
- JobObjectReserved3Information_,
- JobObjectReserved4Information_,
- JobObjectReserved5Information_,
- JobObjectReserved6Information_,
- JobObjectReserved7Information_,
- JobObjectReserved8Information_,
- MaxJobObjectInfoClass_
- } JOBOBJECTINFOCLASS_;
-
-typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION_ {
- ::boost::winapi::LARGE_INTEGER_ PerProcessUserTimeLimit;
- ::boost::winapi::LARGE_INTEGER_ PerJobUserTimeLimit;
- ::boost::winapi::DWORD_ LimitFlags;
- ::boost::winapi::SIZE_T_ MinimumWorkingSetSize;
- ::boost::winapi::SIZE_T_ MaximumWorkingSetSize;
- ::boost::winapi::DWORD_ ActiveProcessLimit;
- ::boost::winapi::ULONG_PTR_ Affinity;
- ::boost::winapi::DWORD_ PriorityClass;
- ::boost::winapi::DWORD_ SchedulingClass;
+typedef enum _JOBOBJECTINFOCLASS_
+{
+ JobObjectBasicAccountingInformation_ = 1,
+ JobObjectBasicLimitInformation_,
+ JobObjectBasicProcessIdList_,
+ JobObjectBasicUIRestrictions_,
+ JobObjectSecurityLimitInformation_,
+ JobObjectEndOfJobTimeInformation_,
+ JobObjectAssociateCompletionPortInformation_,
+ JobObjectBasicAndIoAccountingInformation_,
+ JobObjectExtendedLimitInformation_,
+ JobObjectJobSetInformation_,
+ JobObjectGroupInformation_,
+ JobObjectNotificationLimitInformation_,
+ JobObjectLimitViolationInformation_,
+ JobObjectGroupInformationEx_,
+ JobObjectCpuRateControlInformation_,
+ JobObjectCompletionFilter_,
+ JobObjectCompletionCounter_,
+ JobObjectReserved1Information_ = 18,
+ JobObjectReserved2Information_,
+ JobObjectReserved3Information_,
+ JobObjectReserved4Information_,
+ JobObjectReserved5Information_,
+ JobObjectReserved6Information_,
+ JobObjectReserved7Information_,
+ JobObjectReserved8Information_,
+ MaxJobObjectInfoClass_
+} JOBOBJECTINFOCLASS_;
+
+typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION_
+{
+ ::boost::winapi::LARGE_INTEGER_ PerProcessUserTimeLimit;
+ ::boost::winapi::LARGE_INTEGER_ PerJobUserTimeLimit;
+ ::boost::winapi::DWORD_ LimitFlags;
+ ::boost::winapi::SIZE_T_ MinimumWorkingSetSize;
+ ::boost::winapi::SIZE_T_ MaximumWorkingSetSize;
+ ::boost::winapi::DWORD_ ActiveProcessLimit;
+ ::boost::winapi::ULONG_PTR_ Affinity;
+ ::boost::winapi::DWORD_ PriorityClass;
+ ::boost::winapi::DWORD_ SchedulingClass;
} JOBOBJECT_BASIC_LIMIT_INFORMATION_;
-typedef struct _IO_COUNTERS_ {
- ::boost::winapi::ULONGLONG_ ReadOperationCount;
- ::boost::winapi::ULONGLONG_ WriteOperationCount;
- ::boost::winapi::ULONGLONG_ OtherOperationCount;
- ::boost::winapi::ULONGLONG_ ReadTransferCount;
- ::boost::winapi::ULONGLONG_ WriteTransferCount;
- ::boost::winapi::ULONGLONG_ OtherTransferCount;
+typedef struct _JOBOBJECT_BASIC_ACCOUNTING_INFORMATION_ {
+ ::boost::winapi::LARGE_INTEGER_ TotalUserTime;
+ ::boost::winapi::LARGE_INTEGER_ TotalKernelTime;
+ ::boost::winapi::LARGE_INTEGER_ ThisPeriodTotalUserTime;
+ ::boost::winapi::LARGE_INTEGER_ ThisPeriodTotalKernelTime;
+ ::boost::winapi::DWORD_ TotalPageFaultCount;
+ ::boost::winapi::DWORD_ TotalProcesses;
+ ::boost::winapi::DWORD_ ActiveProcesses;
+ ::boost::winapi::DWORD_ TotalTerminatedProcesses;
+} JOBOBJECT_BASIC_ACCOUNTING_INFORMATION_;
+
+typedef struct _IO_COUNTERS_
+{
+ ::boost::winapi::ULONGLONG_ ReadOperationCount;
+ ::boost::winapi::ULONGLONG_ WriteOperationCount;
+ ::boost::winapi::ULONGLONG_ OtherOperationCount;
+ ::boost::winapi::ULONGLONG_ ReadTransferCount;
+ ::boost::winapi::ULONGLONG_ WriteTransferCount;
+ ::boost::winapi::ULONGLONG_ OtherTransferCount;
} IO_COUNTERS_;
-typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ {
- JOBOBJECT_BASIC_LIMIT_INFORMATION_ BasicLimitInformation;
- IO_COUNTERS_ IoInfo;
- ::boost::winapi::SIZE_T_ ProcessMemoryLimit;
- ::boost::winapi::SIZE_T_ JobMemoryLimit;
- ::boost::winapi::SIZE_T_ PeakProcessMemoryUsed;
- ::boost::winapi::SIZE_T_ PeakJobMemoryUsed;
+typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION_
+{
+ JOBOBJECT_BASIC_LIMIT_INFORMATION_ BasicLimitInformation;
+ IO_COUNTERS_ IoInfo;
+ ::boost::winapi::SIZE_T_ ProcessMemoryLimit;
+ ::boost::winapi::SIZE_T_ JobMemoryLimit;
+ ::boost::winapi::SIZE_T_ PeakProcessMemoryUsed;
+ ::boost::winapi::SIZE_T_ PeakJobMemoryUsed;
} JOBOBJECT_EXTENDED_LIMIT_INFORMATION_;
@@ -82,7 +198,7 @@ typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ {
_Out_opt_ LPDWORD lpReturnLength
);
*/
-typedef ::boost::winapi::BOOL_ (*query_information_job_object_p)(
+typedef ::boost::winapi::BOOL_ (BOOST_WINAPI_WINAPI_CC *query_information_job_object_p)(
::boost::winapi::HANDLE_,
JOBOBJECTINFOCLASS_,
void *,
@@ -93,14 +209,17 @@ typedef ::boost::winapi::BOOL_ (*query_information_job_object_p)(
inline ::boost::winapi::BOOL_ query_information_job_object(
::boost::winapi::HANDLE_ hJob,
JOBOBJECTINFOCLASS_ JobObjectInfoClass,
- void * lpJobObjectInfo,
+ void *lpJobObjectInfo,
::boost::winapi::DWORD_ cbJobObjectInfoLength,
::boost::winapi::DWORD_ *lpReturnLength)
{
- static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle(L"Kernel32.dll");
- static query_information_job_object_p f = reinterpret_cast<query_information_job_object_p>(::boost::winapi::get_proc_address(h, "QueryInformationJobObject"));
+ static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle(
+ L"Kernel32.dll");
+ static query_information_job_object_p f = reinterpret_cast<query_information_job_object_p>(::boost::winapi::get_proc_address(
+ h, "QueryInformationJobObject"));
- return (*f)(hJob, JobObjectInfoClass, lpJobObjectInfo, cbJobObjectInfoLength, lpReturnLength);
+ return (*f)(hJob, JobObjectInfoClass, lpJobObjectInfo,
+ cbJobObjectInfoLength, lpReturnLength);
}
/*BOOL WINAPI SetInformationJobObject(
@@ -110,7 +229,7 @@ inline ::boost::winapi::BOOL_ query_information_job_object(
_In_ DWORD cbJobObjectInfoLength
);*/
-typedef ::boost::winapi::BOOL_ (*set_information_job_object_p)(
+typedef ::boost::winapi::BOOL_ (BOOST_WINAPI_WINAPI_CC *set_information_job_object_p)(
::boost::winapi::HANDLE_,
JOBOBJECTINFOCLASS_,
void *,
@@ -121,19 +240,22 @@ typedef ::boost::winapi::BOOL_ (*set_information_job_object_p)(
inline ::boost::winapi::BOOL_ set_information_job_object(
::boost::winapi::HANDLE_ hJob,
JOBOBJECTINFOCLASS_ JobObjectInfoClass,
- void * lpJobObjectInfo,
+ void *lpJobObjectInfo,
::boost::winapi::DWORD_ cbJobObjectInfoLength)
{
- static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle(L"Kernel32.dll");
- static set_information_job_object_p f = reinterpret_cast<set_information_job_object_p>(::boost::winapi::get_proc_address(h, "SetInformationJobObject"));
+ static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle(
+ L"Kernel32.dll");
+ static set_information_job_object_p f = reinterpret_cast<set_information_job_object_p>(::boost::winapi::get_proc_address(
+ h, "SetInformationJobObject"));
- return (*f)(hJob, JobObjectInfoClass, lpJobObjectInfo, cbJobObjectInfoLength);
+ return (*f)(hJob, JobObjectInfoClass, lpJobObjectInfo,
+ cbJobObjectInfoLength);
}
+#endif
+
constexpr static ::boost::winapi::DWORD_ JOB_OBJECT_LIMIT_BREAKAWAY_OK_ = 0x00000800;
}}}}}
-
-
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_JOB_WORKAROUND_HPP_ */
diff --git a/boost/process/detail/windows/wait_group.hpp b/boost/process/detail/windows/wait_group.hpp
index 32a8cd8842..6dca466d83 100644
--- a/boost/process/detail/windows/wait_group.hpp
+++ b/boost/process/detail/windows/wait_group.hpp
@@ -7,6 +7,7 @@
#define BOOST_PROCESS_DETAIL_WINDOWS_WAIT_GROUP_HPP_
#include <boost/process/detail/config.hpp>
+#include <boost/process/detail/windows/group_handle.hpp>
#include <boost/winapi/jobs.hpp>
#include <boost/winapi/wait.hpp>
#include <chrono>
@@ -15,11 +16,61 @@ namespace boost { namespace process { namespace detail { namespace windows {
struct group_handle;
+
+inline bool wait_impl(const group_handle & p, std::error_code & ec, int wait_time)
+{
+ ::boost::winapi::DWORD_ completion_code;
+ ::boost::winapi::ULONG_PTR_ completion_key;
+ ::boost::winapi::LPOVERLAPPED_ overlapped;
+
+ auto start_time = std::chrono::system_clock::now();
+
+ while (workaround::get_queued_completion_status(
+ p._io_port, &completion_code,
+ &completion_key, &overlapped, wait_time))
+ {
+ if (reinterpret_cast<::boost::winapi::HANDLE_>(completion_key) == p._job_object &&
+ completion_code == workaround::JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO_)
+ {
+
+ //double check, could be a different handle from a child
+ workaround::JOBOBJECT_BASIC_ACCOUNTING_INFORMATION_ info;
+ if (!workaround::query_information_job_object(
+ p._job_object,
+ workaround::JobObjectBasicAccountingInformation_,
+ static_cast<void *>(&info),
+ sizeof(info), nullptr))
+ {
+ ec = get_last_error();
+ return false;
+ }
+ else if (info.ActiveProcesses == 0)
+ return false; //correct, nothing left.
+ }
+ //reduce the remaining wait time -> in case interrupted by something else
+ if (wait_time != ::boost::winapi::infinite)
+ {
+ auto now = std::chrono::system_clock::now();
+ auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
+ wait_time -= diff.count();
+ start_time = now;
+ if (wait_time <= 0)
+ return true; //timeout with other source
+ }
+
+ }
+
+ auto ec_ = get_last_error();
+ if (ec_.value() == ::boost::winapi::wait_timeout)
+ return true; //timeout
+
+ ec = ec_;
+ return false;
+}
+
inline void wait(const group_handle &p, std::error_code &ec)
{
- if (::boost::winapi::WaitForSingleObject(p.handle(),
- ::boost::winapi::infinite) == ::boost::winapi::wait_failed)
- ec = get_last_error();
+ wait_impl(p, ec, ::boost::winapi::infinite);
}
inline void wait(const group_handle &p)
@@ -39,16 +90,8 @@ inline bool wait_until(
std::chrono::duration_cast<std::chrono::milliseconds>(
timeout_time - Clock::now());
- ::boost::winapi::DWORD_ wait_code;
- wait_code = ::boost::winapi::WaitForSingleObject(p.handle(), ms.count());
-
- if (wait_code == ::boost::winapi::wait_failed)
- ec = get_last_error();
-
- else if (wait_code == ::boost::winapi::wait_timeout)
- return false; //
-
- return true;
+ auto timeout = wait_impl(p, ec, ms.count());
+ return !ec && !timeout;
}
template< class Clock, class Duration >
@@ -68,7 +111,9 @@ inline bool wait_for(
const std::chrono::duration<Rep, Period>& rel_time,
std::error_code &ec)
{
- return wait_until(p, std::chrono::steady_clock::now() + rel_time, ec);
+ auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time);
+ auto timeout = wait_impl(p, ec, ms.count());
+ return !ec && !timeout;
}
template< class Rep, class Period >
diff --git a/boost/process/system.hpp b/boost/process/system.hpp
index 5ed7633233..185edca0d2 100644
--- a/boost/process/system.hpp
+++ b/boost/process/system.hpp
@@ -85,6 +85,8 @@ inline int system_impl(
return -1;
ios.run();
+ if (c.running())
+ c.wait();
return c.exit_code();
}