async_system.hpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  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/async_system.hpp
  12. *
  13. * Defines the asynchronous version of the system function.
  14. */
  15. #ifndef BOOST_PROCESS_ASYNC_SYSTEM_HPP
  16. #define BOOST_PROCESS_ASYNC_SYSTEM_HPP
  17. #include <boost/process/detail/config.hpp>
  18. #include <boost/process/async.hpp>
  19. #include <boost/process/child.hpp>
  20. #include <boost/process/detail/async_handler.hpp>
  21. #include <boost/process/detail/execute_impl.hpp>
  22. #include <type_traits>
  23. #include <memory>
  24. #include <boost/asio/async_result.hpp>
  25. #include <boost/asio/post.hpp>
  26. #include <boost/system/error_code.hpp>
  27. #include <tuple>
  28. #if defined(BOOST_POSIX_API)
  29. #include <boost/process/posix.hpp>
  30. #endif
  31. namespace boost {
  32. namespace process {
  33. namespace detail
  34. {
  35. template<typename Handler>
  36. struct async_system_handler : ::boost::process::detail::api::async_handler
  37. {
  38. boost::asio::io_context & ios;
  39. Handler handler;
  40. #if defined(BOOST_POSIX_API)
  41. bool errored = false;
  42. #endif
  43. template<typename ExitHandler_>
  44. async_system_handler(
  45. boost::asio::io_context & ios,
  46. ExitHandler_ && exit_handler) : ios(ios), handler(std::forward<ExitHandler_>(exit_handler))
  47. {
  48. }
  49. template<typename Exec>
  50. void on_error(Exec&, const std::error_code & ec)
  51. {
  52. #if defined(BOOST_POSIX_API)
  53. errored = true;
  54. #endif
  55. auto h = std::make_shared<Handler>(std::move(handler));
  56. boost::asio::post(
  57. ios.get_executor(),
  58. [h, ec]() mutable
  59. {
  60. (*h)(boost::system::error_code(ec.value(), boost::system::system_category()), -1);
  61. });
  62. }
  63. template<typename Executor>
  64. std::function<void(int, const std::error_code&)> on_exit_handler(Executor&)
  65. {
  66. #if defined(BOOST_POSIX_API)
  67. if (errored)
  68. return [](int , const std::error_code &){};
  69. #endif
  70. auto h = std::make_shared<Handler>(std::move(handler));
  71. return [h](int exit_code, const std::error_code & ec) mutable
  72. {
  73. (*h)(boost::system::error_code(ec.value(), boost::system::system_category()), exit_code);
  74. };
  75. }
  76. };
  77. template<typename ExitHandler>
  78. struct is_error_handler<async_system_handler<ExitHandler>> : std::true_type {};
  79. }
  80. /** This function provides an asynchronous interface to process launching.
  81. It uses the same properties and parameters as the other launching function,
  82. but is similar to the asynchronous functions in [boost.asio](http://www.boost.org/doc/libs/release/doc/html/boost_asio.html)
  83. It uses [asio::async_result](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/async_result.html) to determine
  84. the return value (from the second parameter, `exit_handler`).
  85. \param ios A reference to an [io_context](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference.html)
  86. \param exit_handler The exit-handler for the signature `void(boost::system::error_code, int)`
  87. \note This function does not allow custom error handling, since those are done through the `exit_handler`.
  88. */
  89. #if defined(BOOST_PROCESS_DOXYGEN)
  90. template<typename ExitHandler, typename ...Args>
  91. inline boost::process::detail::dummy
  92. async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args);
  93. #endif
  94. namespace detail
  95. {
  96. struct async_system_init_op
  97. {
  98. template<typename Handler, typename ... Args>
  99. void operator()(Handler && handler, asio::io_context & ios, Args && ... args)
  100. {
  101. detail::async_system_handler<typename std::decay<Handler>::type> async_h{ios, std::forward<Handler>(handler)};
  102. child(ios, std::forward<Args>(args)..., async_h ).detach();
  103. }
  104. };
  105. }
  106. template<typename ExitHandler, typename ...Args>
  107. inline BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int))
  108. async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args)
  109. {
  110. typedef typename ::boost::process::detail::has_error_handler<boost::fusion::tuple<Args...>>::type
  111. has_err_handling;
  112. static_assert(!has_err_handling::value, "async_system cannot have custom error handling");
  113. return boost::asio::async_initiate<ExitHandler, void (boost::system::error_code, int)>(
  114. detail::async_system_init_op{}, exit_handler, ios, std::forward<Args>(args)...
  115. );
  116. }
  117. }}
  118. #endif