async_system.hpp 4.4 KB

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