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