child_decl.hpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. // Copyright (c) 2006, 2007 Julio M. Merino Vidal
  2. // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
  3. // Copyright (c) 2009 Boris Schaeling
  4. // Copyright (c) 2010 Felipe Tanus, Boris Schaeling
  5. // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
  6. // Copyright (c) 2016 Klemens D. Morgenstern
  7. //
  8. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  9. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  10. /**
  11. * \file boost/process/child.hpp
  12. *
  13. * Defines a child process class.
  14. */
  15. #ifndef BOOST_PROCESS_CHILD_DECL_HPP
  16. #define BOOST_PROCESS_CHILD_DECL_HPP
  17. #include <boost/process/detail/config.hpp>
  18. #include <chrono>
  19. #include <memory>
  20. #include <boost/none.hpp>
  21. #include <atomic>
  22. #if defined(BOOST_POSIX_API)
  23. #include <boost/process/detail/posix/child_handle.hpp>
  24. #include <boost/process/detail/posix/terminate.hpp>
  25. #include <boost/process/detail/posix/wait_for_exit.hpp>
  26. #include <boost/process/detail/posix/is_running.hpp>
  27. #elif defined(BOOST_WINDOWS_API)
  28. #include <boost/process/detail/windows/child_handle.hpp>
  29. #include <boost/process/detail/windows/terminate.hpp>
  30. #include <boost/process/detail/windows/wait_for_exit.hpp>
  31. #include <boost/process/detail/windows/is_running.hpp>
  32. #endif
  33. namespace boost {
  34. namespace process {
  35. using ::boost::process::detail::api::pid_t;
  36. class child
  37. {
  38. ::boost::process::detail::api::child_handle _child_handle;
  39. std::shared_ptr<std::atomic<int>> _exit_status = std::make_shared<std::atomic<int>>(::boost::process::detail::api::still_active);
  40. bool _attached = true;
  41. bool _terminated = false;
  42. bool _exited()
  43. {
  44. return _terminated || !::boost::process::detail::api::is_running(_exit_status->load());
  45. };
  46. public:
  47. typedef ::boost::process::detail::api::child_handle child_handle;
  48. typedef child_handle::process_handle_t native_handle_t;
  49. explicit child(child_handle &&ch, std::shared_ptr<std::atomic<int>> &ptr) : _child_handle(std::move(ch)), _exit_status(ptr) {}
  50. explicit child(child_handle &&ch, const std::shared_ptr<std::atomic<int>> &ptr) : _child_handle(std::move(ch)), _exit_status(ptr) {}
  51. explicit child(child_handle &&ch) : _child_handle(std::move(ch)) {}
  52. explicit child(pid_t & pid) : _child_handle(pid), _attached(false) {};
  53. child(const child&) = delete;
  54. child(child && lhs) noexcept
  55. : _child_handle(std::move(lhs._child_handle)),
  56. _exit_status(std::move(lhs._exit_status)),
  57. _attached (lhs._attached),
  58. _terminated (lhs._terminated)
  59. {
  60. lhs._attached = false;
  61. }
  62. template<typename ...Args>
  63. explicit child(Args&&...args);
  64. child() {}
  65. child& operator=(const child&) = delete;
  66. child& operator=(child && lhs)
  67. {
  68. _child_handle= std::move(lhs._child_handle);
  69. _exit_status = std::move(lhs._exit_status);
  70. _attached = lhs._attached;
  71. _terminated = lhs._terminated;
  72. lhs._attached = false;
  73. return *this;
  74. };
  75. void detach() {_attached = false; }
  76. void join() {wait();}
  77. bool joinable() { return _attached;}
  78. ~child()
  79. {
  80. std::error_code ec;
  81. if (_attached && !_exited() && running(ec))
  82. terminate(ec);
  83. }
  84. native_handle_t native_handle() const { return _child_handle.process_handle(); }
  85. int exit_code() const {return ::boost::process::detail::api::eval_exit_status(_exit_status->load());}
  86. pid_t id() const {return _child_handle.id(); }
  87. int native_exit_code() const {return _exit_status->load();}
  88. bool running()
  89. {
  90. std::error_code ec;
  91. bool b = running(ec);
  92. boost::process::detail::throw_error(ec, "running error");
  93. return b;
  94. }
  95. void terminate()
  96. {
  97. std::error_code ec;
  98. terminate(ec);
  99. boost::process::detail::throw_error(ec, "terminate error");
  100. }
  101. void wait()
  102. {
  103. std::error_code ec;
  104. wait(ec);
  105. boost::process::detail::throw_error(ec, "wait error");
  106. }
  107. template< class Rep, class Period >
  108. bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
  109. {
  110. std::error_code ec;
  111. bool b = wait_for(rel_time, ec);
  112. boost::process::detail::throw_error(ec, "wait_for error");
  113. return b;
  114. }
  115. template< class Clock, class Duration >
  116. bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
  117. {
  118. std::error_code ec;
  119. bool b = wait_until(timeout_time, ec);
  120. boost::process::detail::throw_error(ec, "wait_until error");
  121. return b;
  122. }
  123. bool running(std::error_code & ec) noexcept
  124. {
  125. ec.clear();
  126. if (valid() && !_exited() && !ec)
  127. {
  128. int exit_code = 0;
  129. auto res = boost::process::detail::api::is_running(_child_handle, exit_code, ec);
  130. if (!ec && !res && !_exited())
  131. _exit_status->store(exit_code);
  132. return res;
  133. }
  134. return false;
  135. }
  136. void terminate(std::error_code & ec) noexcept
  137. {
  138. if (valid() && running(ec) && !ec)
  139. boost::process::detail::api::terminate(_child_handle, ec);
  140. if (!ec)
  141. _terminated = true;
  142. }
  143. void wait(std::error_code & ec) noexcept
  144. {
  145. if (!_exited() && valid())
  146. {
  147. int exit_code = 0;
  148. boost::process::detail::api::wait(_child_handle, exit_code, ec);
  149. if (!ec)
  150. _exit_status->store(exit_code);
  151. }
  152. }
  153. template< class Rep, class Period >
  154. bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
  155. {
  156. return wait_until(std::chrono::steady_clock::now() + rel_time, ec);
  157. }
  158. template< class Clock, class Duration >
  159. bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept
  160. {
  161. if (!_exited())
  162. {
  163. int exit_code = 0;
  164. auto b = boost::process::detail::api::wait_until(_child_handle, exit_code, timeout_time, ec);
  165. if (!b || ec)
  166. return false;
  167. _exit_status->store(exit_code);
  168. }
  169. return true;
  170. }
  171. bool valid() const
  172. {
  173. return _child_handle.valid();
  174. }
  175. operator bool() const {return valid();}
  176. bool in_group() const
  177. {
  178. return _child_handle.in_group();
  179. }
  180. bool in_group(std::error_code &ec) const noexcept
  181. {
  182. return _child_handle.in_group(ec);
  183. }
  184. };
  185. }}
  186. #endif