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   	
63   	    explicit child(pid_t & pid) : _child_handle(pid), _attached(false) {};
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);
76   	    child() {}
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  	
104  	    bool running()
105  	    {
106  	        std::error_code ec;
107  	        bool b = running(ec);
108  	        boost::process::detail::throw_error(ec, "running error");
109  	        return b;
110  	    }
111  	
112  	    void terminate()
113  	    {
114  	        std::error_code ec;
115  	        terminate(ec);
116  	        boost::process::detail::throw_error(ec, "terminate error");
117  	    }
118  	
119  	    void wait()
120  	    {
121  	        std::error_code ec;
122  	        wait(ec);
(1) Event fun_call_w_exception: Called function throws an exception of type "boost::process::process_error". [details]
123  	        boost::process::detail::throw_error(ec, "wait error");
124  	    }
125  	
126  	    template< class Rep, class Period >
127  	    bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
128  	    {
129  	        std::error_code ec;
130  	        bool b = wait_for(rel_time, ec);
131  	        boost::process::detail::throw_error(ec, "wait_for error");
132  	        return b;
133  	    }
134  	
135  	    template< class Clock, class Duration >
136  	    bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
137  	    {
138  	        std::error_code ec;
139  	        bool b = wait_until(timeout_time, ec);
140  	        boost::process::detail::throw_error(ec, "wait_until error");
141  	        return b;
142  	    }
143  	
144  	    bool running(std::error_code & ec) noexcept
145  	    {
146  	        if (valid() && !_exited())
147  	        {
148  	            int exit_code = 0;
149  	            auto res = boost::process::detail::api::is_running(_child_handle, exit_code, ec);
150  	            if (!res && !_exited())
151  	                _exit_status->store(exit_code);
152  	
153  	            return res;
154  	        }
155  	        return false;
156  	    }
157  	
158  	    void terminate(std::error_code & ec) noexcept
159  	    {
160  	        if (valid() && running(ec))
161  	            boost::process::detail::api::terminate(_child_handle, ec);
162  	
163  	        _terminated = true;
164  	    }
165  	
166  	    void wait(std::error_code & ec) noexcept
167  	    {
168  	        if (!_exited() && valid())
169  	        {
170  	            int exit_code = 0;
171  	            boost::process::detail::api::wait(_child_handle, exit_code, ec);
172  	            _exit_status->store(exit_code);
173  	        }
174  	    }
175  	
176  	    template< class Rep, class Period >
177  	    bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
178  	    {
179  	        return wait_until(std::chrono::steady_clock::now() + rel_time, ec);
180  	    }
181  	
182  	    template< class Clock, class Duration >
183  	    bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept
184  	    {
185  	        if (!_exited())
186  	        {
187  	            int exit_code = 0;
188  	            auto b = boost::process::detail::api::wait_until(_child_handle, exit_code, timeout_time, ec);
189  	            if (!b)
190  	                return false;
191  	            _exit_status->store(exit_code);
192  	        }
193  	        return true;
194  	    }
195  	
196  	
197  	    bool valid() const
198  	    {
199  	        return _child_handle.valid();
200  	    }
201  	    operator bool() const {return valid();}
202  	
203  	    bool in_group() const
204  	    {
205  	        return _child_handle.in_group();
206  	    }
207  	    bool in_group(std::error_code &ec) const noexcept
208  	    {
209  	        return _child_handle.in_group(ec);
210  	    }
211  	};
212  	
213  	
214  	
215  	}}
216  	#endif
217  	
218