12 #include <boost/asio/read_until.hpp>
13 #include <boost/process/args.hpp>
17 namespace bp = boost::process;
20 : m_io_ctx(ctx), m_args(std::move(args)), m_stdout{ctx}, m_stderr{ctx} {
21 if (m_args.size() < 1) {
22 throw std::invalid_argument(
"No arguments provided");
24 m_args[0] = bp::search_path(m_args[0]).native();
32 assert(!m_proc.valid());
46 bp::std_out > m_stdout.pipe,
47 bp::std_err > m_stderr.pipe,
49 bp::on_exit = [
this](
int exit,
const std::error_code& ec_in) {
53 m_result = {exit, ec_in};
57 AsyncReadStream(m_stdout);
58 AsyncReadStream(m_stderr);
59 return m_promise.get_future();
62 std::error_code AsyncProcess::Abort() noexcept {
64 return std::make_error_code(std::errc::no_such_process);
72 std::optional<pid_t> AsyncProcess::GetPid() const noexcept {
79 std::error_code AsyncProcess::Signal(
int sig) noexcept {
81 return std::make_error_code(std::errc::no_such_process);
84 pid_t
id = m_proc.id();
85 int err = kill(
id, sig);
86 return std::make_error_code(
static_cast<std::errc
>(err));
89 bool AsyncProcess::IsRunning() const noexcept {
93 return m_proc.valid() && !m_result.has_value();
96 void AsyncProcess::AsyncReadStream(AsyncProcess::Pipe& pipe) {
98 boost::asio::async_read_until(pipe.pipe,
101 [
this, &pipe](
const boost::system::error_code& ec, std::size_t) {
109 std::istream is(&pipe.buffer);
110 std::string remaining(pipe.buffer.size(),
'\0');
111 is.read(remaining.data(), remaining.size());
112 pipe.signal(m_pid, remaining);
123 std::istream is(&pipe.buffer);
125 std::getline(is, line);
128 line.push_back(
'\n');
129 pipe.signal(m_pid, line);
131 AsyncReadStream(pipe);
135 void AsyncProcess::CheckCompleted() {
137 if (!m_result.has_value() || m_stdout.pipe.is_open() || m_stderr.pipe.is_open()) {
142 m_promise.set_exception(std::system_error(m_result->ec));
144 m_promise.set_value(m_result->exit_code);