async_system.hpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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 asynchrounous 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 ExitHandler>
  36. struct async_system_handler : ::boost::process::detail::api::async_handler
  37. {
  38. boost::asio::io_context & ios;
  39. boost::asio::async_completion<
  40. ExitHandler, void(boost::system::error_code, int)> init;
  41. #if defined(BOOST_POSIX_API)
  42. bool errored = false;
  43. #endif
  44. template<typename ExitHandler_>
  45. async_system_handler(
  46. boost::asio::io_context & ios,
  47. ExitHandler_ && exit_handler) : ios(ios), init(exit_handler)
  48. {
  49. }
  50. template<typename Exec>
  51. void on_error(Exec&, const std::error_code & ec)
  52. {
  53. #if defined(BOOST_POSIX_API)
  54. errored = true;
  55. #endif
  56. auto & h = init.completion_handler;
  57. boost::asio::post(
  58. ios.get_executor(),
  59. [h, ec]() mutable
  60. {
  61. h(boost::system::error_code(ec.value(), boost::system::system_category()), -1);
  62. });
  63. }
  64. BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int))
  65. get_result()
  66. {
  67. return init.result.get();
  68. }
  69. template<typename Executor>
  70. std::function<void(int, const std::error_code&)> on_exit_handler(Executor&)
  71. {
  72. #if defined(BOOST_POSIX_API)
  73. if (errored)
  74. return [](int , const std::error_code &){};
  75. #endif
  76. auto & h = init.completion_handler;
  77. return [h](int exit_code, const std::error_code & ec) mutable
  78. {
  79. h(boost::system::error_code(ec.value(), boost::system::system_category()), exit_code);
  80. };
  81. }
  82. };
  83. template<typename ExitHandler>
  84. struct is_error_handler<async_system_handler<ExitHandler>> : std::true_type {};
  85. }
  86. /** This function provides an asynchronous interface to process launching.
  87. It uses the same properties and parameters as the other launching function,
  88. but is similar to the asynchronous functions in [boost.asio](http://www.boost.org/doc/libs/release/doc/html/boost_asio.html)
  89. It uses [asio::async_result](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/async_result.html) to determine
  90. the return value (from the second parameter, `exit_handler`).
  91. \param ios A reference to an [io_context](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference.html)
  92. \param exit_handler The exit-handler for the signature `void(boost::system::error_code, int)`
  93. \note This function does not allow custom error handling, since those are done through the `exit_handler`.
  94. */
  95. #if defined(BOOST_PROCESS_DOXYGEN)
  96. template<typename ExitHandler, typename ...Args>
  97. inline boost::process::detail::dummy
  98. async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args);
  99. #endif
  100. template<typename ExitHandler, typename ...Args>
  101. inline BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int))
  102. async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args)
  103. {
  104. detail::async_system_handler<ExitHandler> async_h{ios, std::forward<ExitHandler>(exit_handler)};
  105. typedef typename ::boost::process::detail::has_error_handler<boost::fusion::tuple<Args...>>::type
  106. has_err_handling;
  107. static_assert(!has_err_handling::value, "async_system cannot have custom error handling");
  108. child(ios, std::forward<Args>(args)..., async_h ).detach();
  109. return async_h.get_result();
  110. }
  111. }}
  112. #endif