execute.hpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  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 = BOOST_PROCESS_V2_ASIO_NAMESPACE::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(BOOST_PROCESS_V2_ASIO_NAMESPACE::enable_total_cancellation());
  59. BOOST_PROCESS_V2_ASIO_NAMESPACE::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. BOOST_PROCESS_V2_ASIO_NAMESPACE::bind_cancellation_slot(
  65. BOOST_PROCESS_V2_ASIO_NAMESPACE::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 = BOOST_PROCESS_V2_ASIO_NAMESPACE::any_io_executor,
  90. BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void (error_code, int))
  91. WaitHandler BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
  92. inline
  93. BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (error_code, int))
  94. async_execute(basic_process<Executor> proc,
  95. WaitHandler && handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor))
  96. {
  97. std::unique_ptr<basic_process<Executor>> pro_(new basic_process<Executor>(std::move(proc)));
  98. auto exec = pro_->get_executor();
  99. return BOOST_PROCESS_V2_ASIO_NAMESPACE::async_compose<WaitHandler, void(error_code, int)>(
  100. detail::execute_op<Executor>{std::move(pro_)}, handler, exec);
  101. }
  102. BOOST_PROCESS_V2_END_NAMESPACE
  103. #endif //BOOST_PROCESS_V2_EXECUTE_HPP