mirror of
https://github.com/boostorg/process.git
synced 2026-01-20 16:52:14 +00:00
Compare commits
1 Commits
issue/285b
...
issue/285
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ad4fd3ccf |
@@ -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
|
||||
|
||||
@@ -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;});
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
```
|
||||
|
||||
@@ -114,6 +114,7 @@ The async version supports cancellation and will forward cancellation types as f
|
||||
if (!ec)
|
||||
sig.emit(asio::cancellation_type::terminal);
|
||||
});
|
||||
);
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
@@ -262,10 +262,7 @@ class executor
|
||||
return;
|
||||
//EAGAIN not yet forked, EINTR interrupted, i.e. try again
|
||||
else if ((err != EAGAIN ) && (err != EINTR))
|
||||
{
|
||||
set_error(std::error_code(err, std::system_category()), "Error read pipe");
|
||||
return;
|
||||
}
|
||||
set_error(std::error_code(err, std::system_category()), "Error read pipe");
|
||||
}
|
||||
set_error(ec, std::move(msg));
|
||||
}
|
||||
@@ -327,9 +324,6 @@ public:
|
||||
|
||||
void set_error(const std::error_code &ec, const char* msg)
|
||||
{
|
||||
if (pid != 0 && pid != -1) // reap-zombie
|
||||
::waitpid(pid, nullptr, 0);
|
||||
|
||||
internal_error_handle(ec, msg, has_error_handler(), has_ignore_error(), shall_use_vfork());
|
||||
}
|
||||
void set_error(const std::error_code &ec, const std::string &msg) {set_error(ec, msg.c_str());};
|
||||
@@ -451,6 +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, 0);
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
return child();
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -85,7 +85,7 @@ struct basic_process_handle_win
|
||||
|
||||
template<typename Executor1>
|
||||
basic_process_handle_win(basic_process_handle_win<Executor1> && handle)
|
||||
: pid_(handle.pid_), handle_(std::move(handle.handle_))
|
||||
: pid_(handle.pid_), handle_(handle.handle_.get_executor())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -1757,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 &);
|
||||
|
||||
@@ -1888,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>
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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(50)};
|
||||
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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user