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