mirror of
https://github.com/boostorg/process.git
synced 2026-01-20 04:42:24 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2d13f424f | ||
|
|
02a9ec0961 | ||
|
|
ee82377179 | ||
|
|
0eb7764d3a | ||
|
|
b98a2bdf86 | ||
|
|
3c1c2a80a2 | ||
|
|
965726bf4f | ||
|
|
179894ccd4 | ||
|
|
3a97b48265 | ||
|
|
1f1e8c67da | ||
|
|
4a703df4c9 |
@@ -26,8 +26,6 @@
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
@@ -98,7 +96,7 @@ template<typename Launcher, typename Init>
|
||||
inline auto invoke_on_error(Launcher & launcher, const filesystem::path &executable,
|
||||
const char * const * (&cmd_line),
|
||||
const error_code & ec, Init && init, derived && )
|
||||
-> decltype(init.on_error(launcher, executable, cmd_line, ec))
|
||||
-> decltype(init.on_error(launcher, ec, executable, cmd_line, ec))
|
||||
{
|
||||
init.on_error(launcher, executable, cmd_line, ec);
|
||||
}
|
||||
@@ -162,7 +160,7 @@ template<typename Launcher, typename Init>
|
||||
inline auto invoke_on_fork_error(Launcher & launcher, const filesystem::path &executable,
|
||||
const char * const * (&cmd_line),
|
||||
const error_code & ec, Init && init, derived && )
|
||||
-> decltype(init.on_fork_error(launcher, executable, cmd_line, ec))
|
||||
-> decltype(init.on_fork_error(launcher, ec, executable, cmd_line, ec))
|
||||
{
|
||||
init.on_fork_error(launcher, executable, cmd_line, ec);
|
||||
}
|
||||
@@ -184,6 +182,41 @@ inline void on_fork_error(Launcher & launcher, const filesystem::path &executabl
|
||||
on_fork_error(launcher, executable, cmd_line, ec, inits...);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename Launcher, typename Init>
|
||||
inline void invoke_on_fork_success(Launcher & /*launcher*/, const filesystem::path &/*executable*/,
|
||||
const char * const * (&/*cmd_line*/),
|
||||
Init && /*init*/, base && )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<typename Launcher, typename Init>
|
||||
inline auto invoke_on_fork_success(Launcher & launcher, const filesystem::path &executable,
|
||||
const char * const * (&cmd_line),
|
||||
Init && init, derived && )
|
||||
-> decltype(init.on_fork_success(launcher, executable, cmd_line))
|
||||
{
|
||||
init.on_fork_success(launcher, executable, cmd_line);
|
||||
}
|
||||
|
||||
template<typename Launcher>
|
||||
inline void on_fork_success(Launcher & /*launcher*/, const filesystem::path &/*executable*/,
|
||||
const char * const * (&/*cmd_line*/))
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Launcher, typename Init1, typename ... Inits>
|
||||
inline void on_fork_success(Launcher & launcher, const filesystem::path &executable,
|
||||
const char * const * (&cmd_line),
|
||||
Init1 && init1, Inits && ... inits)
|
||||
{
|
||||
invoke_on_fork_success(launcher, executable, cmd_line, init1, derived{});
|
||||
on_fork_success(launcher, executable, cmd_line, inits...);
|
||||
}
|
||||
|
||||
|
||||
template<typename Launcher, typename Init>
|
||||
inline error_code invoke_on_exec_setup(Launcher & /*launcher*/, const filesystem::path &/*executable*/,
|
||||
const char * const * (&/*cmd_line*/),
|
||||
@@ -233,7 +266,7 @@ template<typename Launcher, typename Init>
|
||||
inline auto invoke_on_exec_error(Launcher & launcher, const filesystem::path &executable,
|
||||
const char * const * (&cmd_line),
|
||||
const error_code & ec, Init && init, derived && )
|
||||
-> decltype(init.on_exec_error(launcher, executable, cmd_line, ec))
|
||||
-> decltype(init.on_exec_error(launcher, ec, executable, cmd_line, ec))
|
||||
{
|
||||
init.on_exec_error(launcher, executable, cmd_line, ec);
|
||||
}
|
||||
@@ -407,7 +440,6 @@ struct default_launcher
|
||||
if (ec)
|
||||
{
|
||||
detail::on_error(*this, executable, argv, ec, inits...);
|
||||
do { ::waitpid(pid, nullptr, 0); } while (errno == EINTR);
|
||||
return basic_process<Executor>{exec};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +124,6 @@ struct fork_and_forget_launcher : default_launcher
|
||||
if (ec)
|
||||
{
|
||||
detail::on_error(*this, executable, argv, ec, inits...);
|
||||
do { ::waitpid(pid, nullptr, 0); } while (errno == EINTR);
|
||||
return basic_process<Executor>{exec};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,7 +161,6 @@ struct pdfork_launcher : default_launcher
|
||||
if (ec)
|
||||
{
|
||||
detail::on_error(*this, executable, argv, ec, inits...);
|
||||
do { ::waitpid(pid, nullptr, 0); } while (errno == EINTR);
|
||||
return basic_process<Executor>{exec};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +121,6 @@ struct vfork_launcher : default_launcher
|
||||
if (ec)
|
||||
{
|
||||
detail::on_error(*this, executable, argv, ec, inits...);
|
||||
do { ::waitpid(pid, nullptr, 0); } while (errno == EINTR);
|
||||
return basic_process<Executor>{exec};
|
||||
}
|
||||
|
||||
|
||||
@@ -166,31 +166,6 @@ struct process_io_binding
|
||||
}
|
||||
|
||||
process_io_binding() = default;
|
||||
process_io_binding(const process_io_binding &) = delete;
|
||||
process_io_binding & operator=(const process_io_binding &) = delete;
|
||||
|
||||
process_io_binding(process_io_binding && other) noexcept
|
||||
: fd(other.fd), fd_needs_closing(other.fd), ec(other.ec)
|
||||
{
|
||||
other.fd = target;
|
||||
other.fd_needs_closing = false;
|
||||
other.ec = {};
|
||||
}
|
||||
|
||||
process_io_binding & operator=(process_io_binding && other) noexcept
|
||||
{
|
||||
if (fd_needs_closing)
|
||||
::close(fd);
|
||||
|
||||
fd = other.fd;
|
||||
fd_needs_closing = other.fd_needs_closing;
|
||||
ec = other.ec;
|
||||
|
||||
other.fd = target;
|
||||
other.fd_needs_closing = false;
|
||||
other.ec = {};
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
process_io_binding(Stream && str, decltype(std::declval<Stream>().native_handle()) * = nullptr)
|
||||
|
||||
@@ -97,7 +97,7 @@ inline void invoke_on_error(Launcher & /*launcher*/, const filesystem::path &/*e
|
||||
template<typename Launcher, typename Init>
|
||||
inline auto invoke_on_error(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line,
|
||||
const error_code & ec, Init && init, derived && )
|
||||
-> decltype(init.on_error(launcher, executable, cmd_line, ec))
|
||||
-> decltype(init.on_error(launcher, ec, executable, cmd_line, ec))
|
||||
{
|
||||
init.on_error(launcher, executable, cmd_line, ec);
|
||||
}
|
||||
|
||||
@@ -178,8 +178,6 @@ pid_type parent_pid(pid_type pid, error_code & ec)
|
||||
std::vector<pid_type> child_pids(pid_type pid, error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
#if defined(PROC_PPID_ONLY)
|
||||
|
||||
vec.resize(proc_listpids(PROC_PPID_ONLY, (uint32_t)pid, nullptr, 0) / sizeof(pid_type));
|
||||
const auto sz = proc_listpids(PROC_PPID_ONLY, (uint32_t)pid, &vec[0], sizeof(pid_type) * vec.size());
|
||||
if (sz < 0)
|
||||
@@ -188,9 +186,6 @@ std::vector<pid_type> child_pids(pid_type pid, error_code & ec)
|
||||
return {};
|
||||
}
|
||||
vec.resize(sz);
|
||||
#else
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOTSUP, system_category());
|
||||
#endif
|
||||
return vec;
|
||||
}
|
||||
|
||||
|
||||
@@ -110,10 +110,10 @@ BOOST_AUTO_TEST_CASE(test_cwd_exe)
|
||||
boost::asio::io_context ctx;
|
||||
bp2::process proc(ctx, pth, {"sleep", "10000"},
|
||||
bp2::process_start_dir{tmp});
|
||||
auto tt = bp2::ext::cwd(proc.handle());
|
||||
|
||||
|
||||
BOOST_CHECK_MESSAGE(bp2::filesystem::equivalent(tmp, tt), tmp << " == " << tt);
|
||||
auto tt = bp2::ext::cwd(proc.handle()).string();
|
||||
if (tt.back() == '\\')
|
||||
tt.pop_back();
|
||||
BOOST_CHECK_EQUAL(tt, tmp);
|
||||
bp2::error_code ec;
|
||||
bp2::filesystem::remove(tmp, ec);
|
||||
}
|
||||
|
||||
@@ -30,11 +30,9 @@
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/asio/connect_pipe.hpp>
|
||||
#include <boost/asio/cancel_after.hpp>
|
||||
#include <boost/asio/detached.hpp>
|
||||
#include <boost/asio/error.hpp>
|
||||
#include <boost/asio/readable_pipe.hpp>
|
||||
#include <boost/asio/read.hpp>
|
||||
#include <boost/asio/streambuf.hpp>
|
||||
@@ -330,74 +328,6 @@ BOOST_AUTO_TEST_CASE(echo_file)
|
||||
BOOST_CHECK_MESSAGE(proc.exit_code() == 0, proc.exit_code());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(stdio_creates_complementary_pipes)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
const auto pth = master_test_suite().argv[1];
|
||||
|
||||
asio::io_context ctx;
|
||||
|
||||
asio::readable_pipe rp{ctx};
|
||||
asio::writable_pipe wp{ctx};
|
||||
// Pipes intentionally not connected. `process_stdio` will create pipes
|
||||
// complementing both of these and retains ownership of those pipes.
|
||||
|
||||
bpv::process proc(ctx, pth, {"echo"}, bpv::process_stdio{/*.in=*/wp, /*.out=*/rp, /*.err=*/nullptr});
|
||||
|
||||
asio::write(wp, asio::buffer("foo", 3));
|
||||
asio::write(wp, asio::buffer("bar", 3));
|
||||
wp.close();
|
||||
|
||||
bpv::error_code ec;
|
||||
std::string out;
|
||||
auto sz = asio::read(rp, asio::dynamic_buffer(out), ec);
|
||||
while (ec == asio::error::interrupted)
|
||||
sz += asio::read(rp, asio::dynamic_buffer(out), ec);
|
||||
BOOST_CHECK_EQUAL(sz, 6u);
|
||||
BOOST_CHECK_MESSAGE((ec == asio::error::broken_pipe) || (ec == asio::error::eof), ec.message());
|
||||
BOOST_CHECK_EQUAL(out, "foobar");
|
||||
|
||||
proc.wait();
|
||||
BOOST_CHECK(proc.exit_code() == 0);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(stdio_move_semantics)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
const auto pth = master_test_suite().argv[1];
|
||||
|
||||
asio::io_context ctx;
|
||||
|
||||
asio::readable_pipe rp{ctx};
|
||||
asio::writable_pipe wp{ctx};
|
||||
|
||||
auto make_stdio = [&]() -> bpv::process_stdio {
|
||||
bpv::process_stdio stdio{};
|
||||
stdio.in = wp;
|
||||
stdio.out = rp;
|
||||
stdio.err = nullptr;
|
||||
// intentionally pessimizing move, preventing NRVO
|
||||
return std::move(stdio);
|
||||
};
|
||||
bpv::process proc(ctx, pth, {"echo"}, make_stdio());
|
||||
|
||||
bpv::error_code ec;
|
||||
asio::write(wp, asio::buffer("foobar", 6), ec);
|
||||
BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
wp.close();
|
||||
|
||||
std::string out;
|
||||
auto sz = asio::read(rp, asio::dynamic_buffer(out), ec);
|
||||
while (ec == asio::error::interrupted)
|
||||
sz += asio::read(rp, asio::dynamic_buffer(out), ec);
|
||||
BOOST_CHECK_EQUAL(sz, 6u);
|
||||
BOOST_CHECK_MESSAGE((ec == asio::error::broken_pipe) || (ec == asio::error::eof), ec.message());
|
||||
BOOST_CHECK_EQUAL(out, "foobar");
|
||||
|
||||
proc.wait();
|
||||
BOOST_CHECK(proc.exit_code() == 0);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(print_same_cwd)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
@@ -734,42 +664,6 @@ BOOST_AUTO_TEST_CASE(async_cancel_wait)
|
||||
ctx.run();
|
||||
}
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
|
||||
struct capture_pid
|
||||
{
|
||||
pid_t &pid;
|
||||
template<typename Launcher>
|
||||
void on_error(Launcher &launcher, const bpv::filesystem::path& executable,
|
||||
const char * const * (&/*cmd_line*/), const bpv::error_code & ec)
|
||||
{
|
||||
BOOST_REQUIRE(!bpv::filesystem::exists(executable));
|
||||
this->pid = launcher.pid;
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_CASE(no_zombie)
|
||||
{
|
||||
asio::io_context ctx;
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
const auto pth = bpv::filesystem::absolute(master_test_suite().argv[1]);
|
||||
|
||||
pid_t res{-1};
|
||||
|
||||
|
||||
boost::system::error_code ec;
|
||||
bpv::default_process_launcher()(ctx, ec, "/send/more/cops", std::vector<std::string>{}, capture_pid{res});
|
||||
BOOST_CHECK(ec == boost::system::errc::no_such_file_or_directory);
|
||||
|
||||
BOOST_REQUIRE(res != -1);
|
||||
BOOST_CHECK(res != 0);
|
||||
auto r = waitpid(res, nullptr, 0);
|
||||
BOOST_CHECK(r < 0);
|
||||
BOOST_CHECK_EQUAL(errno, ECHILD);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user