]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
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/child.hpp | |
13 | * | |
14 | * Defines a child process class. | |
15 | */ | |
16 | ||
17 | #ifndef BOOST_PROCESS_CHILD_DECL_HPP | |
18 | #define BOOST_PROCESS_CHILD_DECL_HPP | |
19 | ||
20 | #include <boost/process/detail/config.hpp> | |
21 | #include <chrono> | |
22 | #include <memory> | |
23 | ||
24 | #include <boost/none.hpp> | |
25 | #include <atomic> | |
26 | ||
27 | #if defined(BOOST_POSIX_API) | |
28 | #include <boost/process/detail/posix/child_handle.hpp> | |
29 | #include <boost/process/detail/posix/terminate.hpp> | |
30 | #include <boost/process/detail/posix/wait_for_exit.hpp> | |
31 | #include <boost/process/detail/posix/is_running.hpp> | |
32 | #elif defined(BOOST_WINDOWS_API) | |
33 | #include <boost/process/detail/windows/child_handle.hpp> | |
34 | #include <boost/process/detail/windows/terminate.hpp> | |
35 | #include <boost/process/detail/windows/wait_for_exit.hpp> | |
36 | #include <boost/process/detail/windows/is_running.hpp> | |
37 | ||
38 | #endif | |
39 | namespace boost { | |
40 | ||
41 | namespace process { | |
42 | ||
43 | using ::boost::process::detail::api::pid_t; | |
44 | ||
45 | class child | |
46 | { | |
47 | ::boost::process::detail::api::child_handle _child_handle; | |
48 | std::shared_ptr<std::atomic<int>> _exit_status = std::make_shared<std::atomic<int>>(::boost::process::detail::api::still_active); | |
49 | bool _attached = true; | |
50 | bool _terminated = false; | |
51 | ||
52 | bool _exited() | |
53 | { | |
54 | return _terminated || !::boost::process::detail::api::is_running(_exit_status->load()); | |
55 | }; | |
56 | public: | |
57 | typedef ::boost::process::detail::api::child_handle child_handle; | |
58 | typedef child_handle::process_handle_t native_handle_t; | |
59 | explicit child(child_handle &&ch, std::shared_ptr<std::atomic<int>> &ptr) : _child_handle(std::move(ch)), _exit_status(ptr) {} | |
60 | explicit child(child_handle &&ch, const std::shared_ptr<std::atomic<int>> &ptr) : _child_handle(std::move(ch)), _exit_status(ptr) {} | |
61 | explicit child(child_handle &&ch) : _child_handle(std::move(ch)) {} | |
62 | ||
1e59de90 | 63 | explicit child(pid_t pid) : _child_handle(pid), _attached(false) {}; |
b32b8144 FG |
64 | child(const child&) = delete; |
65 | child(child && lhs) noexcept | |
66 | : _child_handle(std::move(lhs._child_handle)), | |
67 | _exit_status(std::move(lhs._exit_status)), | |
68 | _attached (lhs._attached), | |
69 | _terminated (lhs._terminated) | |
70 | { | |
71 | lhs._attached = false; | |
72 | } | |
73 | ||
74 | template<typename ...Args> | |
75 | explicit child(Args&&...args); | |
20effc67 | 76 | child() { } // Must be kept non defaulted for MSVC 14.1 & 14.2 #113 |
b32b8144 FG |
77 | child& operator=(const child&) = delete; |
78 | child& operator=(child && lhs) | |
79 | { | |
80 | _child_handle= std::move(lhs._child_handle); | |
81 | _exit_status = std::move(lhs._exit_status); | |
82 | _attached = lhs._attached; | |
83 | _terminated = lhs._terminated; | |
84 | lhs._attached = false; | |
85 | return *this; | |
86 | }; | |
87 | ||
88 | void detach() {_attached = false; } | |
89 | void join() {wait();} | |
90 | bool joinable() { return _attached;} | |
91 | ||
92 | ~child() | |
93 | { | |
94 | std::error_code ec; | |
95 | if (_attached && !_exited() && running(ec)) | |
96 | terminate(ec); | |
97 | } | |
98 | native_handle_t native_handle() const { return _child_handle.process_handle(); } | |
99 | ||
100 | ||
101 | int exit_code() const {return ::boost::process::detail::api::eval_exit_status(_exit_status->load());} | |
102 | pid_t id() const {return _child_handle.id(); } | |
103 | ||
92f5a8d4 TL |
104 | int native_exit_code() const {return _exit_status->load();} |
105 | ||
b32b8144 FG |
106 | bool running() |
107 | { | |
11fdf7f2 TL |
108 | std::error_code ec; |
109 | bool b = running(ec); | |
110 | boost::process::detail::throw_error(ec, "running error"); | |
111 | return b; | |
b32b8144 FG |
112 | } |
113 | ||
114 | void terminate() | |
115 | { | |
11fdf7f2 TL |
116 | std::error_code ec; |
117 | terminate(ec); | |
118 | boost::process::detail::throw_error(ec, "terminate error"); | |
b32b8144 FG |
119 | } |
120 | ||
121 | void wait() | |
122 | { | |
11fdf7f2 TL |
123 | std::error_code ec; |
124 | wait(ec); | |
125 | boost::process::detail::throw_error(ec, "wait error"); | |
b32b8144 FG |
126 | } |
127 | ||
128 | template< class Rep, class Period > | |
11fdf7f2 | 129 | bool wait_for (const std::chrono::duration<Rep, Period>& rel_time) |
b32b8144 | 130 | { |
11fdf7f2 TL |
131 | std::error_code ec; |
132 | bool b = wait_for(rel_time, ec); | |
133 | boost::process::detail::throw_error(ec, "wait_for error"); | |
134 | return b; | |
b32b8144 FG |
135 | } |
136 | ||
137 | template< class Clock, class Duration > | |
138 | bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time ) | |
139 | { | |
11fdf7f2 TL |
140 | std::error_code ec; |
141 | bool b = wait_until(timeout_time, ec); | |
142 | boost::process::detail::throw_error(ec, "wait_until error"); | |
143 | return b; | |
b32b8144 FG |
144 | } |
145 | ||
146 | bool running(std::error_code & ec) noexcept | |
147 | { | |
92f5a8d4 TL |
148 | ec.clear(); |
149 | if (valid() && !_exited() && !ec) | |
b32b8144 | 150 | { |
11fdf7f2 TL |
151 | int exit_code = 0; |
152 | auto res = boost::process::detail::api::is_running(_child_handle, exit_code, ec); | |
92f5a8d4 | 153 | if (!ec && !res && !_exited()) |
11fdf7f2 | 154 | _exit_status->store(exit_code); |
b32b8144 FG |
155 | |
156 | return res; | |
157 | } | |
158 | return false; | |
159 | } | |
160 | ||
161 | void terminate(std::error_code & ec) noexcept | |
162 | { | |
92f5a8d4 | 163 | if (valid() && running(ec) && !ec) |
b32b8144 FG |
164 | boost::process::detail::api::terminate(_child_handle, ec); |
165 | ||
92f5a8d4 TL |
166 | if (!ec) |
167 | _terminated = true; | |
b32b8144 FG |
168 | } |
169 | ||
170 | void wait(std::error_code & ec) noexcept | |
171 | { | |
172 | if (!_exited() && valid()) | |
173 | { | |
174 | int exit_code = 0; | |
175 | boost::process::detail::api::wait(_child_handle, exit_code, ec); | |
92f5a8d4 TL |
176 | if (!ec) |
177 | _exit_status->store(exit_code); | |
b32b8144 FG |
178 | } |
179 | } | |
180 | ||
181 | template< class Rep, class Period > | |
11fdf7f2 | 182 | bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept |
b32b8144 | 183 | { |
11fdf7f2 | 184 | return wait_until(std::chrono::steady_clock::now() + rel_time, ec); |
b32b8144 FG |
185 | } |
186 | ||
187 | template< class Clock, class Duration > | |
188 | bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept | |
189 | { | |
190 | if (!_exited()) | |
191 | { | |
192 | int exit_code = 0; | |
193 | auto b = boost::process::detail::api::wait_until(_child_handle, exit_code, timeout_time, ec); | |
92f5a8d4 | 194 | if (!b || ec) |
b32b8144 FG |
195 | return false; |
196 | _exit_status->store(exit_code); | |
197 | } | |
198 | return true; | |
199 | } | |
200 | ||
201 | ||
202 | bool valid() const | |
203 | { | |
204 | return _child_handle.valid(); | |
205 | } | |
206 | operator bool() const {return valid();} | |
207 | ||
208 | bool in_group() const | |
209 | { | |
210 | return _child_handle.in_group(); | |
211 | } | |
212 | bool in_group(std::error_code &ec) const noexcept | |
213 | { | |
214 | return _child_handle.in_group(ec); | |
215 | } | |
216 | }; | |
217 | ||
218 | ||
219 | ||
220 | }} | |
221 | #endif | |
222 |