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 
_exited()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;
child(child_handle && ch,std::shared_ptr<std::atomic<int>> & ptr)59     explicit child(child_handle &&ch, std::shared_ptr<std::atomic<int>> &ptr) : _child_handle(std::move(ch)), _exit_status(ptr) {}
child(child_handle && ch,const std::shared_ptr<std::atomic<int>> & ptr)60     explicit child(child_handle &&ch, const std::shared_ptr<std::atomic<int>> &ptr) : _child_handle(std::move(ch)), _exit_status(ptr) {}
child(child_handle && ch)61     explicit child(child_handle &&ch) : _child_handle(std::move(ch)) {}
62 
child(pid_t & pid)63     explicit child(pid_t & pid) : _child_handle(pid), _attached(false) {};
64     child(const child&) = delete;
child(child && lhs)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);
child()76     child() { } // Must be kept non defaulted for MSVC 14.1 & 14.2 #113
77     child& operator=(const child&) = delete;
operator =(child && lhs)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 
detach()88     void detach() {_attached = false; }
join()89     void join() {wait();}
joinable()90     bool joinable() { return _attached;}
91 
~child()92     ~child()
93     {
94         std::error_code ec;
95         if (_attached && !_exited() && running(ec))
96             terminate(ec);
97     }
native_handle() const98     native_handle_t native_handle() const { return _child_handle.process_handle(); }
99 
100 
exit_code() const101     int exit_code() const {return ::boost::process::detail::api::eval_exit_status(_exit_status->load());}
id() const102     pid_t id()      const {return _child_handle.id(); }
103 
native_exit_code() const104     int native_exit_code() const {return _exit_status->load();}
105 
running()106     bool running()
107     {
108         std::error_code ec;
109         bool b = running(ec);
110         boost::process::detail::throw_error(ec, "running error");
111         return b;
112     }
113 
terminate()114     void terminate()
115     {
116         std::error_code ec;
117         terminate(ec);
118         boost::process::detail::throw_error(ec, "terminate error");
119     }
120 
wait()121     void wait()
122     {
123         std::error_code ec;
124         wait(ec);
125         boost::process::detail::throw_error(ec, "wait error");
126     }
127 
128     template< class Rep, class Period >
wait_for(const std::chrono::duration<Rep,Period> & rel_time)129     bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
130     {
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;
135     }
136 
137     template< class Clock, class Duration >
wait_until(const std::chrono::time_point<Clock,Duration> & timeout_time)138     bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
139     {
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;
144     }
145 
running(std::error_code & ec)146     bool running(std::error_code & ec) noexcept
147     {
148         ec.clear();
149         if (valid() && !_exited() && !ec)
150         {
151             int exit_code = 0;
152             auto res = boost::process::detail::api::is_running(_child_handle, exit_code, ec);
153             if (!ec && !res && !_exited())
154                 _exit_status->store(exit_code);
155 
156             return res;
157         }
158         return false;
159     }
160 
terminate(std::error_code & ec)161     void terminate(std::error_code & ec) noexcept
162     {
163         if (valid() && running(ec) && !ec)
164             boost::process::detail::api::terminate(_child_handle, ec);
165 
166         if (!ec)
167             _terminated = true;
168     }
169 
wait(std::error_code & ec)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);
176             if (!ec)
177                 _exit_status->store(exit_code);
178         }
179     }
180 
181     template< class Rep, class Period >
wait_for(const std::chrono::duration<Rep,Period> & rel_time,std::error_code & ec)182     bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
183     {
184         return wait_until(std::chrono::steady_clock::now() + rel_time, ec);
185     }
186 
187     template< class Clock, class Duration >
wait_until(const std::chrono::time_point<Clock,Duration> & timeout_time,std::error_code & ec)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);
194             if (!b || ec)
195                 return false;
196             _exit_status->store(exit_code);
197         }
198         return true;
199     }
200 
201 
valid() const202     bool valid() const
203     {
204         return _child_handle.valid();
205     }
operator bool() const206     operator bool() const {return valid();}
207 
in_group() const208     bool in_group() const
209     {
210         return _child_handle.in_group();
211     }
in_group(std::error_code & ec) const212     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 
223