execute.hpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. // Copyright (c) 2022 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_V2_EXECUTE_HPP
  6. #define BOOST_PROCESS_V2_EXECUTE_HPP
  7. #include <boost/process/v2/process.hpp>
  8. #if defined(BOOST_PROCESS_V2_STANDALONE)
  9. #include <asio/bind_cancellation_slot.hpp>
  10. #else
  11. #include <boost/asio/bind_cancellation_slot.hpp>
  12. #endif
  13. BOOST_PROCESS_V2_BEGIN_NAMESPACE
  14. /**
  15. * @brief Run a process and wait for it to complete.
  16. *
  17. * @tparam Executor The asio executor of the process handle
  18. * @param proc The process to be run.
  19. * @return int The exit code of the process
  20. * @exception system_error An error that might have occurred during the wait.
  21. */
  22. template<typename Executor>
  23. inline int execute(basic_process<Executor> proc)
  24. {
  25. return proc.wait();
  26. }
  27. /** \overload int execute(const basic_process<Executor> proc) */
  28. template<typename Executor>
  29. inline int execute(basic_process<Executor> proc, error_code & ec)
  30. {
  31. return proc.wait(ec);
  32. }
  33. namespace detail
  34. {
  35. template<typename Executor>
  36. struct execute_op
  37. {
  38. std::unique_ptr<basic_process<Executor>> proc;
  39. struct cancel
  40. {
  41. using cancellation_type = net::cancellation_type;
  42. basic_process<Executor> * proc;
  43. cancel(basic_process<Executor> * proc) : proc(proc) {}
  44. void operator()(cancellation_type tp)
  45. {
  46. error_code ign;
  47. if ((tp & cancellation_type::total) != cancellation_type::none)
  48. proc->interrupt(ign);
  49. else if ((tp & cancellation_type::partial) != cancellation_type::none)
  50. proc->request_exit(ign);
  51. else if ((tp & cancellation_type::terminal) != cancellation_type::none)
  52. proc->terminate(ign);
  53. }
  54. };
  55. template<typename Self>
  56. void operator()(Self && self)
  57. {
  58. self.reset_cancellation_state(net::enable_total_cancellation());
  59. net::cancellation_slot s = self.get_cancellation_state().slot();
  60. if (s.is_connected())
  61. s.emplace<cancel>(proc.get());
  62. auto pro_ = proc.get();
  63. pro_->async_wait(
  64. net::bind_cancellation_slot(
  65. net::cancellation_slot(),
  66. std::move(self)));
  67. }
  68. template<typename Self>
  69. void operator()(Self && self, error_code ec, int res)
  70. {
  71. self.get_cancellation_state().slot().clear();
  72. self.complete(ec, res);
  73. }
  74. };
  75. }
  76. /// Execute a process asynchronously
  77. /** This function asynchronously for a process to complete.
  78. *
  79. * Cancelling the execution will signal the child process to exit
  80. * with the following interpretations:
  81. *
  82. * - cancellation_type::total -> interrupt
  83. * - cancellation_type::partial -> request_exit
  84. * - cancellation_type::terminal -> terminate
  85. *
  86. * It is to note that `async_execute` will us the lowest selected cancellation
  87. * type. A subprocess might ignore anything not terminal.
  88. */
  89. template<typename Executor = net::any_io_executor,
  90. BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void (error_code, int))
  91. WaitHandler = net::default_completion_token_t<Executor>>
  92. inline
  93. auto async_execute(basic_process<Executor> proc,
  94. WaitHandler && handler = net::default_completion_token_t<Executor>())
  95. -> decltype(net::async_compose<WaitHandler, void(error_code, int)>(
  96. detail::execute_op<Executor>{nullptr}, handler, std::declval<Executor>()))
  97. {
  98. std::unique_ptr<basic_process<Executor>> pro_(new basic_process<Executor>(std::move(proc)));
  99. auto exec = pro_->get_executor();
  100. return net::async_compose<WaitHandler, void(error_code, int)>(
  101. detail::execute_op<Executor>{std::move(pro_)}, handler, exec);
  102. }
  103. BOOST_PROCESS_V2_END_NAMESPACE
  104. #endif //BOOST_PROCESS_V2_EXECUTE_HPP