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