2
0
mirror of https://github.com/boostorg/process.git synced 2026-01-20 04:42:24 +00:00

Compare commits

..

1 Commits

Author SHA1 Message Date
Klemens Morgenstern
3ad4fd3ccf zombie reap fix. 2023-08-14 18:00:55 +08:00
27 changed files with 121 additions and 271 deletions

View File

@@ -26,7 +26,9 @@ set B2_TARGETS=libs/!SELF!/test
cd !BOOST_ROOT!
call bootstrap.bat
b2 headers
b2 --debug-configuration variant=%VARIANT% cxxstd=%CXXSTD% define=%DEFINE% address-model=%ADDRESS_MODEL% toolset=%TOOLSET% --verbose-test libs/!SELF!/test libs/!SELF!/example -j3
b2 --debug-configuration variant=%VARIANT% cxxstd=%CXXSTD% define=%DEFINE% address-model=%ADDRESS_MODEL% toolset=%TOOLSET% --verbose-test libs/!SELF!/test -j3
b2 --debug-configuration variant=%VARIANT% cxxstd=%CXXSTD% define=%DEFINE% address-model=%ADDRESS_MODEL% toolset=%TOOLSET% --verbose-test libs/!SELF!/example -j3
) else if "%DRONE_JOB_BUILDTYPE%" == "standalone-windows" (
REM not used

View File

@@ -83,7 +83,7 @@ will be called on the respective events on process launching. The names are:
As an example:
```
child c("ls", on_setup([](){cout << "On Setup" << endl;}));
child c("ls", on_setup([](){cout << "On Setup" << endl;});
```

View File

@@ -348,7 +348,7 @@ and use the following code, the `gcc` process will still run afterwards:
```
bp::child c("make");
if (!c.child_wait_for(std::chrono::seconds(10))) //give it 10 seconds
if (!c.child_wait_for(std::chrono::seconds(10)) //give it 10 seconds
c.child_terminate(); //then terminate
```
@@ -357,7 +357,7 @@ So in order to also terminate `gcc` we can use a group.
```
bp::group g;
bp::child c("make", g);
if (!g.group_wait_for(std::chrono::seconds(10)))
if (!g.group_wait_for(std::chrono::seconds(10))
g.group_terminate();
c.child_wait(); //to avoid a zombie process & get the exit code

View File

@@ -20,8 +20,8 @@ To note is the `find_executable` functions, which searches in an environment for
std::unordered_map<environment::key, environment::value> my_env =
{
{"SECRET", "THIS_IS_A_TEST"},
{"PATH", {"/bin", "/usr/bin"}}
{"SECRET", "THIS_IS_A_TEST"}
{"PATH", {"/bin", "/usr/bin"}
};
auto other_exe = environment::find_executable("g++", my_env);
@@ -35,10 +35,10 @@ The subprocess environment assignment follows the same constraints:
asio::io_context ctx;
std::unordered_map<environment::key, environment::value> my_env =
{
{"SECRET", "THIS_IS_A_TEST"},
{"PATH", {"/bin", "/usr/bin"}}
{"SECRET", "THIS_IS_A_TEST"}
{"PATH", {"/bin", "/usr/bin"}
};
auto exe = find_executable("g++");
auto exe = find_executable("g++"), my_env);
process proc(ctx, exe, {"main.cpp"}, process_environment(my_env));
process pro2(ctx, exe, {"test.cpp"}, process_environment(my_env));
```

View File

@@ -114,6 +114,7 @@ The async version supports cancellation and will forward cancellation types as f
if (!ec)
sig.emit(asio::cancellation_type::terminal);
});
);
});
```

View File

@@ -445,7 +445,7 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
if (_ec)
{
//if an error occurred we need to reap the child process
::waitpid(this->pid, nullptr, WNOHANG);
::waitpid(this->pid, nullptr, 0);
boost::fusion::for_each(seq, call_on_error(*this, _ec));
return child();
}

View File

@@ -33,7 +33,7 @@ inline std::vector<native_handle_type> get_handles(std::error_code & ec)
else
ec.clear();
auto my_fd = dirfd(dir.get());
auto my_fd = ::dirfd(dir.get());
struct ::dirent * ent_p;
@@ -117,7 +117,7 @@ struct limit_handles_ : handler_base_ext
return;
}
auto my_fd = dirfd(dir);
auto my_fd = ::dirfd(dir);
struct ::dirent * ent_p;
while ((ent_p = readdir(dir)) != nullptr)

View File

@@ -14,25 +14,15 @@
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <unistd.h>
#include <array>
#include <boost/process/detail/used_handles.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
template<int p1, int p2>
struct pipe_out : handler_base_ext, ::boost::process::detail::uses_handles
struct pipe_out : handler_base_ext
{
int sink;
int source; //opposite end
std::array<int, 4> get_used_handles()
{
const auto pp1 = p1 != -1 ? p1 : p2;
const auto pp2 = p2 != -1 ? p2 : p1;
return {source, sink, pp1, pp2};
}
pipe_out(int sink, int source) : sink(sink), source(source) {}
template<typename T>

View File

@@ -65,7 +65,7 @@ inline auto native_environment_impl<Char>::get(const pointer_type id) -> string_
{
auto err = ::boost::winapi::GetLastError();
if (err == ::boost::winapi::ERROR_ENVVAR_NOT_FOUND_)//well, then we consider that an empty value
return string_type();
return "";
else
throw process_error(std::error_code(err, std::system_category()),
"GetEnvironmentVariable() failed");

View File

@@ -122,15 +122,13 @@ struct basic_pipebuf : std::basic_streambuf<CharT, Traits>
///Destructor -> writes the frest of the data
~basic_pipebuf()
try
{
if (basic_pipebuf::is_open())
basic_pipebuf::overflow(Traits::eof());
}
catch (process_error & )
{
try
{
if (basic_pipebuf::is_open())
basic_pipebuf::overflow(Traits::eof());
}
catch (process_error & )
{
}
}
///Move construct from a pipe.

View File

@@ -84,32 +84,22 @@ struct basic_process_handle_win
template<typename Executor1>
basic_process_handle_win(basic_process_handle_win<Executor1> && other)
: pid_(other.pid_), handle_(std::move(other.handle_))
basic_process_handle_win(basic_process_handle_win<Executor1> && handle)
: pid_(handle.pid_), handle_(handle.handle_.get_executor())
{
other.pid_ = static_cast<DWORD>(-1);
}
basic_process_handle_win(basic_process_handle_win && other)
: pid_(other.pid_), handle_(std::move(other.handle_))
basic_process_handle_win(basic_process_handle_win && handle)
: pid_(handle.id()), handle_(std::move(handle.handle_))
{
other.pid_ = static_cast<DWORD>(-1);
handle.pid_ = static_cast<DWORD>(-1);
}
basic_process_handle_win& operator=(basic_process_handle_win && other)
basic_process_handle_win& operator=(basic_process_handle_win && handle)
{
pid_ = other.pid_;
handle_ = std::move(other.handle_);
other.pid_ = static_cast<DWORD>(-1);
return *this;
}
template<typename Executor1>
basic_process_handle_win& operator=(basic_process_handle_win<Executor1> && other)
{
pid_ = other.pid_;
handle_ = std::move(other.handle_);
other.pid_ = static_cast<DWORD>(-1);
pid_ = handle.pid_;
handle_ = std::move(handle.handle_);
handle.pid_ = static_cast<DWORD>(-1);
return *this;
}

View File

@@ -13,13 +13,10 @@
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/cstring_ref.hpp>
#include <boost/process/v2/detail/utf8.hpp>
#include <boost/type_traits.hpp>
#include <functional>
#include <memory>
#include <numeric>
#include <vector>
#if !defined(GENERATING_DOCUMENTATION)
#if defined(BOOST_PROCESS_V2_WINDOWS)
@@ -1760,7 +1757,6 @@ struct process_environment
std::vector<environment::key_value_pair> env_buffer;
std::vector<wchar_t> unicode_env;
BOOST_PROCESS_V2_DECL
error_code on_setup(windows::default_launcher & launcher,
const filesystem::path &, const std::wstring &);
@@ -1891,6 +1887,7 @@ struct hash<BOOST_PROCESS_V2_NAMESPACE::environment::key_value_pair>
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
#include <boost/process/v2/impl/environment.ipp>
#include <boost/process/v2/detail/impl/environment.ipp>

View File

@@ -66,7 +66,7 @@ struct execute_op
template<typename Self>
void operator()(Self && self)
{
self.reset_cancellation_state(BOOST_PROCESS_V2_ASIO_NAMESPACE::enable_total_cancellation());
self.reset_cancellation_state();
BOOST_PROCESS_V2_ASIO_NAMESPACE::cancellation_slot s = self.get_cancellation_state().slot();
if (s.is_connected())
s.emplace<cancel>(proc.get());
@@ -110,7 +110,7 @@ async_execute(basic_process<Executor> proc,
WaitHandler && handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor))
{
std::unique_ptr<basic_process<Executor>> pro_(new basic_process<Executor>(std::move(proc)));
auto exec = pro_->get_executor();
auto exec = proc.get_executor();
return BOOST_PROCESS_V2_ASIO_NAMESPACE::async_compose<WaitHandler, void(error_code, int)>(
detail::execute_op<Executor>{std::move(pro_)}, handler, exec);
}

View File

@@ -72,11 +72,7 @@ typedef int native_exit_code_type;
namespace detail
{
constexpr native_exit_code_type still_active = 0x17f;
static_assert(WIFSTOPPED(still_active), "Expected still_active to indicate WIFSTOPPED");
static_assert(!WIFEXITED(still_active), "Expected still_active to not indicate WIFEXITED");
static_assert(!WIFSIGNALED(still_active), "Expected still_active to not indicate WIFSIGNALED");
static_assert(!WIFCONTINUED(still_active), "Expected still_active to not indicate WIFCONTINUED");
constexpr native_exit_code_type still_active = 0x7f;
}
inline bool process_is_running(int code)

View File

@@ -146,10 +146,7 @@ shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
};
std::unique_ptr<void, del> proc{detail::ext::open_process_with_debug_privilege(pid, ec)};
if (proc == nullptr)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return shell{};
}
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
else
return cmd(proc.get(), ec);

View File

@@ -112,19 +112,13 @@ filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code
filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
{
#if (defined(__linux__) || defined(__ANDROID__))
return filesystem::canonical(
filesystem::path("/proc") / std::to_string(pid) / "cwd", ec
);
#elif defined(__sun)
return fileystem::canonical(
filesystem::path("/proc") / std::to_string(pid) / "path/cwd", ec
);
#endif
filesystem::path("/proc") / std::to_string(pid) / "cwd", ec);
}
#elif defined(__FreeBSD__)
// FIXME: Add error handling.
filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
{
filesystem::path path;
@@ -138,7 +132,9 @@ filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code
filestat *fst = nullptr;
STAILQ_FOREACH(fst, head, next) {
if (fst->fs_uflags & PS_FST_UFLAG_CDIR)
{
path = filesystem::canonical(fst->fs_path, ec);
}
}
procstat_freefiles(proc_stat, head);
}
@@ -157,6 +153,7 @@ filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code
#elif defined(__DragonFly__)
// FIXME: Add error handling.
filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
{
filesystem::path path;
@@ -181,8 +178,7 @@ filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code
}
else
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
if (pclose(fp) == -1)
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
pclose(fp);
}
else
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)

View File

@@ -133,7 +133,7 @@ filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code
);
#elif defined(__sun)
return fileystem::canonical(
filesystem::path("/proc") / std::to_string(pid) / "path/a.out", ec
filesystem::path("/proc") / std::to_string(pid) / "path/a.out"
);
#endif
}

View File

@@ -9,8 +9,6 @@
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/throw_error.hpp>
#include <vector>
BOOST_PROCESS_V2_BEGIN_NAMESPACE
#if defined(GENERATING_DOCUMENTATION)

View File

@@ -101,7 +101,7 @@ void close_all(const std::vector<int> & whitelist, error_code & ec)
idx++)
{
const auto mine = whitelist[idx];
const auto next = whitelist[idx + 1];
const auto next = whitelist[idx];
if ((mine + 1) != next && (mine != next))
{
::close_range(mine + 1, next - 1, 0);
@@ -132,7 +132,7 @@ void close_all(const std::vector<int> & whitelist, error_code & ec)
idx++)
{
const auto mine = whitelist[idx];
const auto next = whitelist[idx + 1];
const auto next = whitelist[idx];
if ((mine + 1) != next && (mine != next))
{
::close_range(mine + 1, next - 1, CLOSE_RANGE_UNSHARE);

View File

@@ -31,19 +31,14 @@ struct process_creation_flags
const filesystem::path &,
const std::wstring &) const
{
launcher.creation_flags |= Flags;
launcher.startup_info.StartupInfo.dwFlags |= Flags;
return error_code {};
};
};
/// A flag to create a new process group. Necessary to allow interrupts for the subprocess.
constexpr static process_creation_flags<CREATE_NEW_PROCESS_GROUP> create_new_process_group;
constexpr static process_creation_flags<CREATE_BREAKAWAY_FROM_JOB> create_breakaway_from_job;
constexpr static process_creation_flags<CREATE_NEW_CONSOLE> create_new_console;
}
BOOST_PROCESS_V2_END_NAMESPACE

View File

@@ -21,7 +21,7 @@ process_standalone_test(pipe)
function(process_sub_launch_test name )
add_executable(boost_process_${name} ${name}.cpp)
target_link_libraries(boost_process_${name} Boost::process Boost::system Boost::filesystem Boost::scope_exit Boost::thread Boost::unit_test_framework)
target_link_libraries(boost_process_${name} Boost::process Boost::system Boost::filesystem Boost::thread Boost::unit_test_framework)
add_test(NAME boost_process_${name} COMMAND $<TARGET_FILE:boost_process_${name}> $<TARGET_FILE:boost_process_sub_launch> )
endfunction()

View File

@@ -16,11 +16,6 @@
#include <boost/process/filesystem.hpp>
#if !defined(BOOST_PROCESS_USE_STD_FS)
#include <boost/filesystem/directory.hpp>
#endif
#include <system_error>

View File

@@ -159,6 +159,7 @@ BOOST_AUTO_TEST_CASE(wenvironment)
#if defined(BOOST_PROCESS_V2_WINDOWS)
BOOST_CHECK_EQUAL(bpe::key(L"FOO"), bpe::key_view(L"Foo"));
BOOST_CHECK(bpe::key(L"FOO") == std::wstring(L"Foo"));
BOOST_CHECK_EQUAL(bpe::key_value_pair(L"Foo=BAR"), bpe::key_value_pair_view(L"FOO=BAR"));
BOOST_CHECK_EQUAL(bpe::key_value_pair(L"Foo=BAR"), bpe::key_value_pair(L"FOO=BAR"));
BOOST_CHECK_EQUAL(bpe::key_value_pair_view(L"Foo=BAR"), bpe::key_value_pair_view(L"FOO=BAR"));

View File

@@ -37,20 +37,15 @@ BOOST_AUTO_TEST_CASE(child_pid)
auto cs = bp2::child_pids(bp2::current_pid());
boost::asio::io_context ctx;
bp2::process proc(ctx, pth, {"loop"});
std::this_thread::sleep_for(std::chrono::milliseconds(200));
std::this_thread::sleep_for(std::chrono::milliseconds(100));
auto c2 = bp2::child_pids(bp2::current_pid());
BOOST_CHECK_LE(cs.size(), c2.size());
BOOST_CHECK_LT(cs.size(), c2.size());
BOOST_CHECK(std::find(cs.begin(), cs.end(), proc.id()) == cs.end());
if (!c2.empty())
BOOST_CHECK(std::find(c2.begin(), c2.end(), proc.id()) != c2.end());
boost::system::error_code ec;
proc.terminate(ec);
if (ec)
BOOST_CHECK(ec == boost::system::errc::permission_denied);
else
proc.wait();
BOOST_CHECK(std::find(c2.begin(), c2.end(), proc.id()) != c2.end());
proc.terminate();
proc.wait();
auto c3 = bp2::child_pids(bp2::current_pid());
BOOST_CHECK(std::find(c3.begin(), c3.end(), proc.id()) == c3.end());
BOOST_CHECK_LE(c3.size(), c2.size());
BOOST_CHECK_LT(c3.size(), c2.size());
}

View File

@@ -26,19 +26,12 @@
#include <boost/process/v2/stdio.hpp>
#include <boost/process/v2/bind_launcher.hpp>
#if defined(BOOST_PROCESS_V2_WINDOWS)
#include <boost/process/v2/windows/creation_flags.hpp>
#include <boost/process/v2/windows/show_window.hpp>
#endif
#include <boost/test/unit_test.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/connect_pipe.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/readable_pipe.hpp>
#include <boost/asio/read.hpp>
#include <boost/asio/streambuf.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/asio/write.hpp>
#include <boost/asio/writable_pipe.hpp>
@@ -48,6 +41,35 @@
namespace bpv = boost::process::v2;
namespace asio = boost::asio;
#if defined(BOOST_PROCESS_V2_WINDOWS)
bpv::filesystem::path shell()
{
return bpv::environment::find_executable("cmd");
}
bpv::filesystem::path closable()
{
return bpv::environment::find_executable("notepad");
}
bpv::filesystem::path interruptable()
{
return bpv::environment::find_executable("cmd");
}
#else
bpv::filesystem::path shell()
{
return bpv::environment::find_executable("sh");
}
bpv::filesystem::path closable()
{
return bpv::environment::find_executable("tee");
}
bpv::filesystem::path interruptable()
{
return bpv::environment::find_executable("tee");
}
#endif
BOOST_AUTO_TEST_SUITE(with_target);
@@ -65,6 +87,7 @@ BOOST_AUTO_TEST_CASE(exit_code_sync)
args[1] = "42";
auto proc = bpv::default_process_launcher()(ctx, pth, args);
BOOST_CHECK_EQUAL(proc.wait(), 42);
printf("42: %d\n", proc.native_exit_code());
BOOST_CHECK_EQUAL(bpv::process(ctx, pth, {"sleep", "100"}).wait(), 0);
BOOST_CHECK_EQUAL(bpv::execute(bpv::process(ctx, pth, {"sleep", "100"})), 0);
@@ -122,69 +145,52 @@ BOOST_AUTO_TEST_CASE(exit_code_async)
BOOST_AUTO_TEST_CASE(terminate)
{
asio::io_context ctx;
using boost::unit_test::framework::master_test_suite;
const auto pth = master_test_suite().argv[1];
bpv::process proc(ctx, pth, {"sleep", "10"});
auto sh = shell();
BOOST_CHECK_MESSAGE(!sh.empty(), sh);
bpv::process proc(ctx, sh, {});
proc.suspend();
proc.resume();
proc.terminate();
proc.wait();
BOOST_CHECK_NE(proc.exit_code(), 0);
}
BOOST_AUTO_TEST_CASE(request_exit)
{
asio::io_context ctx;
using boost::unit_test::framework::master_test_suite;
const auto pth = master_test_suite().argv[1];
auto sh = closable();
BOOST_CHECK_MESSAGE(!sh.empty(), sh);
asio::readable_pipe rp{ctx};
asio::writable_pipe wp{ctx};
asio::connect_pipe(rp, wp);
bpv::process proc(ctx, pth, {"sigterm"}
#if defined(BOOST_PROCESS_V2_WINDOWS)
, bpv::windows::show_window_minimized_not_active
, bpv::windows::create_new_console
bpv::process proc(ctx, sh, {}, bpv::process_stdio{rp}
#if defined(ASIO_WINDOWS)
, asio::windows::show_window_minimized_not_active
#endif
);
BOOST_CHECK(proc.running());
std::this_thread::sleep_for(std::chrono::milliseconds(250));
proc.request_exit();
proc.wait();
BOOST_CHECK_EQUAL(proc.exit_code() & ~SIGTERM, 0);
}
bool can_interrupt = true;
BOOST_AUTO_TEST_CASE(interrupt)
{
asio::io_context ctx;
using boost::unit_test::framework::master_test_suite;
const auto pth = master_test_suite().argv[1];
bpv::process proc(ctx, pth, {"sigint"}
#if defined(BOOST_PROCESS_V2_WINDOWS)
, bpv::windows::create_new_process_group
auto sh = interruptable();
BOOST_CHECK_MESSAGE(!sh.empty(), sh);
bpv::process proc(ctx, sh, {}
#if defined(ASIO_WINDOWS)
, asio::windows::create_new_process_group
#endif
);
std::this_thread::sleep_for(std::chrono::milliseconds(250));
bpv::error_code ec;
proc.interrupt(ec);
#if defined(BOOST_PROCESS_V2_WINDOWS)
// the interrupt only works on console applications, so it may not work depending on the environment.
if (ec.value() == ERROR_INVALID_FUNCTION)
{
can_interrupt = false;
return;
}
#endif
BOOST_CHECK_MESSAGE(!ec, ec.what());
proc.interrupt();
proc.wait();
BOOST_CHECK_EQUAL(proc.exit_code() & ~SIGTERM, 0);
}
void trim_end(std::string & str)
@@ -579,68 +585,5 @@ BOOST_AUTO_TEST_CASE(bind_launcher)
BOOST_CHECK_MESSAGE(proc.exit_code() == 0, proc.exit_code() << " from " << proc.native_exit_code());
}
BOOST_AUTO_TEST_CASE(async_interrupt)
{
if (!can_interrupt)
return;
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, {"sigint"}
#if defined(BOOST_PROCESS_V2_WINDOWS)
, bpv::windows::create_new_process_group
#endif
);
asio::steady_timer tim{ctx, std::chrono::milliseconds(200)};
asio::cancellation_signal sig;
bpv::async_execute(std::move(proc),
asio::bind_cancellation_slot(
sig.slot(),
[](boost::system::error_code ec, int res)
{
BOOST_CHECK(!ec);
BOOST_CHECK_EQUAL(
bpv::evaluate_exit_code(res) & ~SIGTERM, 0);
}));
tim.async_wait([&](bpv::error_code ec) { sig.emit(asio::cancellation_type::total); });
ctx.run();
}
BOOST_AUTO_TEST_CASE(async_request_exit)
{
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, {"sigterm"}
#if defined(BOOST_PROCESS_V2_WINDOWS)
, bpv::windows::show_window_minimized_not_active
, bpv::windows::create_new_console
#endif
);
asio::steady_timer tim{ctx, std::chrono::milliseconds(250)};
asio::cancellation_signal sig;
bpv::async_execute(std::move(proc),
asio::bind_cancellation_slot(
sig.slot(),
[](boost::system::error_code ec, int res)
{
BOOST_CHECK(!ec);
BOOST_CHECK_EQUAL(bpv::evaluate_exit_code(res) & ~SIGTERM, 0);
}));
tim.async_wait([&](bpv::error_code ec) { sig.emit(asio::cancellation_type::partial); });
ctx.run();
}
BOOST_AUTO_TEST_SUITE_END();

View File

@@ -1,7 +1,6 @@
#include <iostream>
#include <string>
#include <thread>
#include <boost/asio/steady_timer.hpp>
#include <boost/process/v2/environment.hpp>
extern char **environ;
@@ -72,71 +71,15 @@ int main(int argc, char * argv[])
GetStartupInfo(&si);
return static_cast<int>(si.wShowWindow);
}
#endif
else if (mode == "sigterm")
else if (mode == "creation-flags")
{
boost::asio::io_context ctx;
boost::asio::steady_timer tim{ctx, std::chrono::seconds(10)};
static boost::asio::steady_timer * tim_p = &tim;
#if defined(BOOST_PROCESS_V2_WINDOWS)
SetConsoleCtrlHandler(
[](DWORD kind)
{
if (kind == CTRL_CLOSE_EVENT)
{
// windows doesn't like us doing antyhing else
::exit(0);
if (tim_p != nullptr)
tim_p->cancel();
return TRUE;
}
else
return FALSE;
}, TRUE);
#else
signal(SIGTERM, [](int) { if (tim_p != nullptr) tim_p->cancel();});
#endif
boost::system::error_code ec;
tim.async_wait([&](boost::system::error_code ec_) { ec = ec_; });
ctx.run();
tim_p = nullptr;
return ec ? EXIT_SUCCESS : 32;
STARTUPINFO si;
GetStartupInfo(&si);
return static_cast<int>(si.dwFlags);
}
else if (mode == "sigint")
{
boost::asio::io_context ctx;
boost::asio::steady_timer tim{ctx, std::chrono::seconds(10)};
static boost::asio::steady_timer * tim_p = &tim;
#if defined(BOOST_PROCESS_V2_WINDOWS)
SetConsoleCtrlHandler(NULL, FALSE);
auto res = SetConsoleCtrlHandler(
[](DWORD kind)
{
if (kind == CTRL_C_EVENT)
{
if (tim_p != nullptr)
tim_p->cancel();
return TRUE;
}
else
return FALSE;
}, TRUE);
BOOST_ASSERT(res != FALSE);
#else
signal(SIGINT, [](int) { if (tim_p != nullptr) tim_p->cancel();});
#endif
boost::system::error_code ec;
tim.async_wait([&](boost::system::error_code ec_) { ec = ec_; });
ctx.run();
tim_p = nullptr;
return ec ? EXIT_SUCCESS : 33;
}
else
return 34;
return 0;
}

View File

@@ -50,6 +50,19 @@ BOOST_AUTO_TEST_CASE(show_window)
}
BOOST_AUTO_TEST_CASE(creation_flags)
{
using boost::unit_test::framework::master_test_suite;
const auto pth = master_test_suite().argv[1];
asio::io_context ctx;
bpv::process proc{ctx, pth, {"creation-flags"}};
BOOST_CHECK_EQUAL(proc.wait() & ~EXTENDED_STARTUPINFO_PRESENT, 0);
proc = bpv::process{ctx, master_test_suite().argv[1], {"creation-flags"}, bpv::windows::process_creation_flags<STARTF_TITLEISAPPID>()};
BOOST_CHECK(proc.running());
BOOST_CHECK_EQUAL(proc.wait() & ~EXTENDED_STARTUPINFO_PRESENT, STARTF_TITLEISAPPID);
}
BOOST_AUTO_TEST_CASE(as_user_launcher)
{