mirror of
https://github.com/boostorg/process.git
synced 2026-01-19 04:22:15 +00:00
committed by
Klemens Morgenstern
parent
f5c83eb9c5
commit
31d6b5c9f8
@@ -100,9 +100,10 @@ struct basic_process_handle
|
||||
// Check if the process handle is referring to an existing process.
|
||||
bool is_open() const;
|
||||
|
||||
// Asynchronously wait for the process to exit and deliver the native exit-code in the completion handler.
|
||||
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, native_exit_code_type))
|
||||
// Asynchronously wait for the process to exit and assign the native exit-code to the reference.
|
||||
// The exit_status can indicate that a process has already be waited for, e.g. when terminate is called.
|
||||
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code))
|
||||
WaitHandler = net::default_completion_token_t<executor_type>>
|
||||
auto async_wait(WaitHandler &&handler = net::default_completion_token_t<executor_type>());
|
||||
auto async_wait(native_exit_code_type &exit_status, WaitHandler &&handler = net::default_completion_token_t<executor_type>());
|
||||
};
|
||||
----
|
||||
@@ -286,24 +286,21 @@ struct basic_process_handle_fd
|
||||
{
|
||||
net::posix::basic_descriptor<Executor> &descriptor;
|
||||
pid_type pid_;
|
||||
|
||||
native_exit_code_type & exit_code;
|
||||
template<typename Self>
|
||||
void operator()(Self &&self)
|
||||
{
|
||||
self.reset_cancellation_state(asio::enable_total_cancellation());
|
||||
error_code ec;
|
||||
native_exit_code_type exit_code{};
|
||||
int wait_res = -1;
|
||||
if (pid_ <= 0) // error, complete early
|
||||
ec = net::error::bad_descriptor;
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, net::error::bad_descriptor);
|
||||
else if (process_is_running(exit_code))
|
||||
{
|
||||
wait_res = ::waitpid(pid_, &exit_code, WNOHANG);
|
||||
if (wait_res == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
|
||||
if (!ec && (wait_res == 0))
|
||||
{
|
||||
descriptor.async_wait(net::posix::descriptor_base::wait_read, std::move(self));
|
||||
@@ -313,38 +310,39 @@ struct basic_process_handle_fd
|
||||
struct completer
|
||||
{
|
||||
error_code ec;
|
||||
native_exit_code_type code;
|
||||
typename std::decay<Self>::type self;
|
||||
|
||||
void operator()()
|
||||
{
|
||||
self.complete(ec, code);
|
||||
self.complete(ec);
|
||||
}
|
||||
};
|
||||
net::post(descriptor.get_executor(), completer{ec, exit_code, std::move(self)});
|
||||
net::dispatch(
|
||||
net::get_associated_immediate_executor(self, descriptor.get_executor()),
|
||||
completer{ec, std::move(self)});
|
||||
|
||||
}
|
||||
|
||||
template<typename Self>
|
||||
void operator()(Self &&self, error_code ec, int = 0)
|
||||
{
|
||||
native_exit_code_type exit_code{};
|
||||
if (!ec)
|
||||
if (!ec && process_is_running(exit_code))
|
||||
if (::waitpid(pid_, &exit_code, 0) == -1)
|
||||
ec = get_last_error();
|
||||
std::move(self).complete(ec, exit_code);
|
||||
std::move(self).complete(ec);
|
||||
}
|
||||
};
|
||||
public:
|
||||
|
||||
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, native_exit_code_type))
|
||||
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code))
|
||||
WaitHandler = net::default_completion_token_t<executor_type>>
|
||||
auto async_wait(WaitHandler &&handler = net::default_completion_token_t<executor_type>())
|
||||
-> decltype(net::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
|
||||
async_wait_op_{descriptor_, pid_}, handler, descriptor_))
|
||||
auto async_wait(native_exit_code_type & exit_code,
|
||||
WaitHandler &&handler = net::default_completion_token_t<executor_type>())
|
||||
-> decltype(net::async_compose<WaitHandler, void(error_code)>(
|
||||
async_wait_op_{descriptor_, pid_, exit_code}, handler, descriptor_))
|
||||
{
|
||||
return net::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
|
||||
async_wait_op_{descriptor_, pid_}, handler, descriptor_);
|
||||
return net::async_compose<WaitHandler, void(error_code)>(
|
||||
async_wait_op_{descriptor_, pid_, exit_code}, handler, descriptor_);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -332,6 +332,7 @@ struct basic_process_handle_fd_or_signal
|
||||
int dummy;
|
||||
#endif
|
||||
pid_type pid_;
|
||||
native_exit_code_type & exit_code;
|
||||
bool needs_post = true;
|
||||
|
||||
template<typename Self>
|
||||
@@ -344,11 +345,10 @@ struct basic_process_handle_fd_or_signal
|
||||
template<typename Self>
|
||||
void operator()(Self &&self, error_code ec, int = 0)
|
||||
{
|
||||
native_exit_code_type exit_code{};
|
||||
int wait_res = -1;
|
||||
if (pid_ <= 0) // error, complete early
|
||||
ec = net::error::bad_descriptor;
|
||||
else
|
||||
else if (process_is_running(exit_code))
|
||||
{
|
||||
wait_res = ::waitpid(pid_, &exit_code, WNOHANG);
|
||||
if (wait_res == -1)
|
||||
@@ -391,18 +391,19 @@ struct basic_process_handle_fd_or_signal
|
||||
template<typename Self>
|
||||
void operator()(Self &&self, native_exit_code_type code, error_code ec)
|
||||
{
|
||||
self.complete(ec, code);
|
||||
self.complete(ec);
|
||||
}
|
||||
};
|
||||
public:
|
||||
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, int))
|
||||
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code))
|
||||
WaitHandler = net::default_completion_token_t<executor_type>>
|
||||
auto async_wait(WaitHandler &&handler = net::default_completion_token_t<executor_type>())
|
||||
-> decltype(net::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
|
||||
async_wait_op_{descriptor_, signal_set_, pid_}, handler, descriptor_))
|
||||
auto async_wait(native_exit_code_type & exit_code,
|
||||
WaitHandler &&handler = net::default_completion_token_t<executor_type>())
|
||||
-> decltype(net::async_compose<WaitHandler, void(error_code)>(
|
||||
async_wait_op_{descriptor_, signal_set_, pid_, exit_code}, handler, descriptor_))
|
||||
{
|
||||
return net::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
|
||||
async_wait_op_{descriptor_, signal_set_, pid_}, handler, descriptor_);
|
||||
return net::async_compose<WaitHandler, void(error_code)>(
|
||||
async_wait_op_{descriptor_, signal_set_, pid_, exit_code}, handler, descriptor_);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -308,7 +308,8 @@ struct basic_process_handle_signal
|
||||
|
||||
net::basic_signal_set<Executor> &handle;
|
||||
pid_type pid_;
|
||||
|
||||
native_exit_code_type & exit_code;
|
||||
|
||||
template<typename Self>
|
||||
void operator()(Self &&self)
|
||||
{
|
||||
@@ -326,12 +327,11 @@ struct basic_process_handle_signal
|
||||
== net::cancellation_type::none)
|
||||
ec.clear();
|
||||
|
||||
native_exit_code_type exit_code = -1;
|
||||
int wait_res = -1;
|
||||
|
||||
if (pid_ <= 0) // error, complete early
|
||||
ec = net::error::bad_descriptor;
|
||||
else if (!ec)
|
||||
else if (!ec && process_is_running(exit_code))
|
||||
{
|
||||
wait_res = ::waitpid(pid_, &exit_code, WNOHANG);
|
||||
if (wait_res == -1)
|
||||
@@ -345,7 +345,7 @@ struct basic_process_handle_signal
|
||||
}
|
||||
|
||||
const auto exec = self.get_executor();
|
||||
net::dispatch(exec, net::append(std::move(self), exit_code, ec));
|
||||
net::dispatch(exec, net::append(std::move(self), ec));
|
||||
}
|
||||
#else
|
||||
signal_set_dummy_ dummy_;
|
||||
@@ -360,20 +360,21 @@ struct basic_process_handle_signal
|
||||
}
|
||||
#endif
|
||||
template<typename Self>
|
||||
void operator()(Self &&self, native_exit_code_type code, error_code ec)
|
||||
void operator()(Self &&self, error_code ec)
|
||||
{
|
||||
self.complete(ec, code);
|
||||
self.complete(ec);
|
||||
}
|
||||
};
|
||||
public:
|
||||
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, int))
|
||||
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code))
|
||||
WaitHandler = net::default_completion_token_t<executor_type>>
|
||||
auto async_wait(WaitHandler &&handler = net::default_completion_token_t<executor_type>())
|
||||
-> decltype(net::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
|
||||
async_wait_op_{signal_set_, pid_}, handler, signal_set_))
|
||||
auto async_wait(native_exit_code_type & exit_code,
|
||||
WaitHandler &&handler = net::default_completion_token_t<executor_type>())
|
||||
-> decltype(net::async_compose<WaitHandler, void(error_code)>(
|
||||
async_wait_op_{signal_set_, pid_, exit_code}, handler, signal_set_))
|
||||
{
|
||||
return net::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
|
||||
async_wait_op_{signal_set_, pid_}, handler, signal_set_);
|
||||
return net::async_compose<WaitHandler, void(error_code)>(
|
||||
async_wait_op_{signal_set_, pid_, exit_code}, handler, signal_set_);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -275,7 +275,7 @@ struct basic_process_handle_win
|
||||
struct async_wait_op_
|
||||
{
|
||||
handle_type &handle;
|
||||
|
||||
native_exit_code_type & exit_code;
|
||||
template<typename Self>
|
||||
void operator()(Self &&self)
|
||||
{
|
||||
@@ -296,24 +296,24 @@ struct basic_process_handle_win
|
||||
template<typename Self>
|
||||
void operator()(Self &&self, error_code ec)
|
||||
{
|
||||
native_exit_code_type exit_code{};
|
||||
if (ec == asio::error::operation_aborted && !self.get_cancellation_state().cancelled())
|
||||
return handle.async_wait(std::move(self));
|
||||
|
||||
if (!ec)
|
||||
if (!ec && process_is_running(exit_code)) // exit_code could be set by another call to wait.
|
||||
detail::get_exit_code_(handle.native_handle(), exit_code, ec);
|
||||
std::move(self).complete(ec, exit_code);
|
||||
std::move(self).complete(ec);
|
||||
}
|
||||
};
|
||||
public:
|
||||
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, native_exit_code_type))
|
||||
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code))
|
||||
WaitHandler = net::default_completion_token_t<executor_type>>
|
||||
auto async_wait(WaitHandler &&handler = net::default_completion_token_t<executor_type>())
|
||||
-> decltype(net::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
|
||||
async_wait_op_{handle_}, handler, handle_))
|
||||
auto async_wait(native_exit_code_type & exit_code,
|
||||
WaitHandler &&handler = net::default_completion_token_t<executor_type>())
|
||||
-> decltype(net::async_compose<WaitHandler, void(error_code)>(
|
||||
async_wait_op_{handle_, exit_code}, handler, handle_))
|
||||
{
|
||||
return net::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
|
||||
async_wait_op_{handle_}, handler, handle_
|
||||
return net::async_compose<WaitHandler, void(error_code)>(
|
||||
async_wait_op_{handle_, exit_code}, handler, handle_
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -20,10 +20,12 @@
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_STANDALONE)
|
||||
#include <asio/any_io_executor.hpp>
|
||||
#include <boost/asio/dispatch.hpp>
|
||||
#include <asio/post.hpp>
|
||||
#include <utility>
|
||||
#else
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
#include <boost/asio/dispatch.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/core/exchange.hpp>
|
||||
#endif
|
||||
@@ -359,23 +361,22 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
net::post(handle.get_executor(),
|
||||
completer{static_cast<int>(res), std::move(self)});
|
||||
net::dispatch(
|
||||
net::get_associated_immediate_executor(handle, handle.get_executor()),
|
||||
completer{static_cast<int>(res), std::move(self)});
|
||||
}
|
||||
else
|
||||
handle.async_wait(std::move(self));
|
||||
handle.async_wait(res, std::move(self));
|
||||
}
|
||||
|
||||
template<typename Self>
|
||||
void operator()(Self && self, error_code ec, native_exit_code_type code)
|
||||
void operator()(Self && self, error_code ec)
|
||||
{
|
||||
if (!ec && process_is_running(code))
|
||||
handle.async_wait(std::move(self));
|
||||
if (!ec && process_is_running(res))
|
||||
handle.async_wait(res, std::move(self));
|
||||
else
|
||||
{
|
||||
if (!ec)
|
||||
res = code;
|
||||
std::move(self).complete(ec, evaluate_exit_code(code));
|
||||
std::move(self).complete(ec, evaluate_exit_code(res));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -768,6 +768,26 @@ BOOST_AUTO_TEST_CASE(no_zombie)
|
||||
BOOST_CHECK_EQUAL(errno, ECHILD);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(async_terminate_code)
|
||||
{
|
||||
asio::io_context ctx;
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
const auto pth = bpv::filesystem::absolute(master_test_suite().argv[1]);
|
||||
|
||||
bpv::process proc(ctx, pth, {"sleep", "1000"});
|
||||
|
||||
proc.async_wait([&](boost::system::error_code ec, int code)
|
||||
{
|
||||
BOOST_CHECK_MESSAGE(!ec, ec.what());
|
||||
BOOST_CHECK_EQUAL(code, SIGKILL);
|
||||
BOOST_CHECK(!proc.running());
|
||||
});
|
||||
|
||||
asio::post(ctx, [&]{proc.terminate();});
|
||||
|
||||
ctx.run();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user