wait_group.hpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. // Copyright (c) 2016 Klemens D. Morgenstern
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_PROCESS_DETAIL_WINDOWS_WAIT_GROUP_HPP_
  6. #define BOOST_PROCESS_DETAIL_WINDOWS_WAIT_GROUP_HPP_
  7. #include <boost/process/detail/config.hpp>
  8. #include <boost/process/detail/windows/group_handle.hpp>
  9. #include <boost/winapi/jobs.hpp>
  10. #include <boost/winapi/wait.hpp>
  11. #include <chrono>
  12. namespace boost { namespace process { namespace detail { namespace windows {
  13. struct group_handle;
  14. inline bool wait_impl(const group_handle & p, std::error_code & ec, std::chrono::system_clock::rep wait_time)
  15. {
  16. ::boost::winapi::DWORD_ completion_code;
  17. ::boost::winapi::ULONG_PTR_ completion_key;
  18. ::boost::winapi::LPOVERLAPPED_ overlapped;
  19. auto start_time = std::chrono::system_clock::now();
  20. while (workaround::get_queued_completion_status(
  21. p._io_port, &completion_code,
  22. &completion_key, &overlapped, static_cast<::boost::winapi::DWORD_>(wait_time)))
  23. {
  24. if (reinterpret_cast<::boost::winapi::HANDLE_>(completion_key) == p._job_object &&
  25. completion_code == workaround::JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO_)
  26. {
  27. //double check, could be a different handle from a child
  28. workaround::JOBOBJECT_BASIC_ACCOUNTING_INFORMATION_ info;
  29. if (!workaround::query_information_job_object(
  30. p._job_object,
  31. workaround::JobObjectBasicAccountingInformation_,
  32. static_cast<void *>(&info),
  33. sizeof(info), nullptr))
  34. {
  35. ec = get_last_error();
  36. return false;
  37. }
  38. else if (info.ActiveProcesses == 0)
  39. return false; //correct, nothing left.
  40. }
  41. //reduce the remaining wait time -> in case interrupted by something else
  42. if (wait_time != static_cast<int>(::boost::winapi::infinite))
  43. {
  44. auto now = std::chrono::system_clock::now();
  45. auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
  46. wait_time -= static_cast<std::chrono::system_clock::rep>(diff.count());
  47. start_time = now;
  48. if (wait_time <= 0)
  49. return true; //timeout with other source
  50. }
  51. }
  52. auto ec_ = get_last_error();
  53. if (ec_.value() == ::boost::winapi::wait_timeout)
  54. return true; //timeout
  55. ec = ec_;
  56. return false;
  57. }
  58. inline void wait(const group_handle &p, std::error_code &ec)
  59. {
  60. wait_impl(p, ec, ::boost::winapi::infinite);
  61. }
  62. inline void wait(const group_handle &p)
  63. {
  64. std::error_code ec;
  65. wait(p, ec);
  66. boost::process::detail::throw_error(ec, "wait error");
  67. }
  68. template< class Clock, class Duration >
  69. inline bool wait_until(
  70. const group_handle &p,
  71. const std::chrono::time_point<Clock, Duration>& timeout_time,
  72. std::error_code &ec)
  73. {
  74. std::chrono::milliseconds ms =
  75. std::chrono::duration_cast<std::chrono::milliseconds>(
  76. timeout_time - Clock::now());
  77. auto timeout = wait_impl(p, ec, ms.count());
  78. return !ec && !timeout;
  79. }
  80. template< class Clock, class Duration >
  81. inline bool wait_until(
  82. const group_handle &p,
  83. const std::chrono::time_point<Clock, Duration>& timeout_time)
  84. {
  85. std::error_code ec;
  86. bool b = wait_until(p, timeout_time, ec);
  87. boost::process::detail::throw_error(ec, "wait_until error");
  88. return b;
  89. }
  90. template< class Rep, class Period >
  91. inline bool wait_for(
  92. const group_handle &p,
  93. const std::chrono::duration<Rep, Period>& rel_time,
  94. std::error_code &ec)
  95. {
  96. auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time);
  97. auto timeout = wait_impl(p, ec, ms.count());
  98. return !ec && !timeout;
  99. }
  100. template< class Rep, class Period >
  101. inline bool wait_for(
  102. const group_handle &p,
  103. const std::chrono::duration<Rep, Period>& rel_time)
  104. {
  105. std::error_code ec;
  106. bool b = wait_for(p, rel_time, ec);
  107. boost::process::detail::throw_error(ec, "wait_for error");
  108. return b;
  109. }
  110. }}}}
  111. #endif /* BOOST_PROCESS_DETAIL_WINDOWS_WAIT_GROUP_HPP_ */