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