]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
1 | // Copyright (c) 2016 Klemens D. Morgenstern |
2 | // | |
3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
5 | ||
92f5a8d4 TL |
6 | #ifndef BOOST_PROCESS_WINDOWS_IO_CONTEXT_REF_HPP_ |
7 | #define BOOST_PROCESS_WINDOWS_IO_CONTEXT_REF_HPP_ | |
b32b8144 FG |
8 | |
9 | #include <boost/process/detail/handler_base.hpp> | |
10 | #include <boost/process/detail/windows/async_handler.hpp> | |
1e59de90 | 11 | #include <boost/process/detail/windows/is_running.hpp> |
b32b8144 | 12 | #include <boost/asio/io_context.hpp> |
1e59de90 | 13 | #include <boost/asio/post.hpp> |
b32b8144 FG |
14 | #include <boost/asio/windows/object_handle.hpp> |
15 | #include <boost/winapi/process.hpp> | |
16 | #include <boost/winapi/handles.hpp> | |
17 | ||
18 | #include <boost/fusion/algorithm/iteration/for_each.hpp> | |
19 | #include <boost/fusion/algorithm/transformation/filter_if.hpp> | |
20 | #include <boost/fusion/algorithm/transformation/transform.hpp> | |
21 | #include <boost/fusion/view/transform_view.hpp> | |
22 | #include <boost/fusion/container/vector/convert.hpp> | |
23 | ||
24 | ||
25 | #include <functional> | |
26 | #include <type_traits> | |
27 | #include <memory> | |
28 | #include <atomic> | |
29 | #include <vector> | |
30 | ||
31 | #include <boost/type_index.hpp> | |
32 | ||
33 | namespace boost { namespace process { namespace detail { namespace windows { | |
34 | ||
35 | template<typename Executor> | |
36 | struct on_exit_handler_transformer | |
37 | { | |
38 | Executor & exec; | |
39 | on_exit_handler_transformer(Executor & exec) : exec(exec) {} | |
40 | template<typename Sig> | |
41 | struct result; | |
42 | ||
43 | template<typename T> | |
44 | struct result<on_exit_handler_transformer<Executor>(T&)> | |
45 | { | |
46 | typedef typename T::on_exit_handler_t type; | |
47 | }; | |
48 | ||
49 | template<typename T> | |
50 | auto operator()(T& t) const -> typename T::on_exit_handler_t | |
51 | { | |
52 | return t.on_exit_handler(exec); | |
53 | } | |
54 | }; | |
55 | ||
56 | template<typename Executor> | |
57 | struct async_handler_collector | |
58 | { | |
59 | Executor & exec; | |
60 | std::vector<std::function<void(int, const std::error_code & ec)>> &handlers; | |
61 | ||
62 | ||
63 | async_handler_collector(Executor & exec, | |
64 | std::vector<std::function<void(int, const std::error_code & ec)>> &handlers) | |
65 | : exec(exec), handlers(handlers) {} | |
66 | ||
67 | template<typename T> | |
68 | void operator()(T & t) const | |
69 | { | |
70 | handlers.push_back(t.on_exit_handler(exec)); | |
71 | } | |
72 | }; | |
73 | ||
74 | //Also set's up waiting for the exit, so it can close async stuff. | |
75 | struct io_context_ref : boost::process::detail::handler_base | |
76 | { | |
77 | ||
78 | io_context_ref(boost::asio::io_context & ios) | |
79 | : ios(ios) | |
80 | { | |
81 | } | |
82 | boost::asio::io_context &get() {return ios;}; | |
83 | ||
84 | template <class Executor> | |
85 | void on_success(Executor& exec) const | |
86 | { | |
87 | auto asyncs = boost::fusion::filter_if< | |
88 | is_async_handler< | |
89 | typename std::remove_reference< boost::mpl::_ > ::type | |
90 | >>(exec.seq); | |
91 | ||
92 | //ok, check if there are actually any. | |
93 | if (boost::fusion::empty(asyncs)) | |
94 | { | |
95 | return; | |
96 | } | |
97 | ||
98 | ::boost::winapi::PROCESS_INFORMATION_ & proc = exec.proc_info; | |
99 | auto this_proc = ::boost::winapi::GetCurrentProcess(); | |
100 | ||
101 | auto proc_in = proc.hProcess;; | |
102 | ::boost::winapi::HANDLE_ process_handle; | |
103 | ||
104 | if (!::boost::winapi::DuplicateHandle( | |
105 | this_proc, proc_in, this_proc, &process_handle, 0, | |
106 | static_cast<::boost::winapi::BOOL_>(true), | |
107 | ::boost::winapi::DUPLICATE_SAME_ACCESS_)) | |
108 | ||
109 | exec.set_error(::boost::process::detail::get_last_error(), | |
110 | "Duplicate Pipe Failed"); | |
111 | ||
112 | ||
113 | std::vector<std::function<void(int, const std::error_code & ec)>> funcs; | |
114 | funcs.reserve(boost::fusion::size(asyncs)); | |
115 | boost::fusion::for_each(asyncs, async_handler_collector<Executor>(exec, funcs)); | |
116 | ||
117 | wait_handler wh(std::move(funcs), ios, process_handle, exec.exit_status); | |
118 | ||
1e59de90 TL |
119 | ::boost::winapi::DWORD_ code; |
120 | if(::boost::winapi::GetExitCodeProcess(process_handle, &code) | |
121 | && code != still_active) | |
122 | { | |
123 | ::boost::asio::post(wh.handle->get_executor(), std::move(wh)); | |
124 | return; | |
125 | } | |
126 | ||
127 | ||
b32b8144 FG |
128 | auto handle_p = wh.handle.get(); |
129 | handle_p->async_wait(std::move(wh)); | |
130 | } | |
131 | ||
132 | ||
133 | struct wait_handler | |
134 | { | |
135 | std::vector<std::function<void(int, const std::error_code & ec)>> funcs; | |
136 | std::unique_ptr<boost::asio::windows::object_handle> handle; | |
137 | std::shared_ptr<std::atomic<int>> exit_status; | |
138 | wait_handler(const wait_handler & ) = delete; | |
139 | wait_handler(wait_handler && ) = default; | |
140 | wait_handler(std::vector<std::function<void(int, const std::error_code & ec)>> && funcs, | |
141 | boost::asio::io_context & ios, void * handle, | |
142 | const std::shared_ptr<std::atomic<int>> &exit_status) | |
143 | : funcs(std::move(funcs)), | |
1e59de90 TL |
144 | handle(new boost::asio::windows::object_handle( |
145 | asio::prefer(ios.get_executor(), asio::execution::outstanding_work.tracked), handle)), | |
b32b8144 FG |
146 | exit_status(exit_status) |
147 | { | |
148 | ||
149 | } | |
1e59de90 | 150 | void operator()(const boost::system::error_code & ec_in = {}) |
b32b8144 FG |
151 | { |
152 | std::error_code ec; | |
153 | if (ec_in) | |
154 | ec = std::error_code(ec_in.value(), std::system_category()); | |
155 | ||
156 | ::boost::winapi::DWORD_ code; | |
157 | ::boost::winapi::GetExitCodeProcess(handle->native_handle(), &code); | |
158 | exit_status->store(code); | |
159 | ||
160 | for (auto & func : funcs) | |
161 | func(code, ec); | |
162 | } | |
163 | ||
164 | }; | |
165 | ||
166 | private: | |
167 | boost::asio::io_context &ios; | |
168 | }; | |
169 | ||
170 | }}}} | |
171 | ||
92f5a8d4 | 172 | #endif /* BOOST_PROCESS_WINDOWS_IO_CONTEXT_REF_HPP_ */ |