mirror of
https://github.com/boostorg/process.git
synced 2026-01-20 16:52:14 +00:00
Compare commits
46 Commits
boost-1.66
...
asio_no_de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6abce365c5 | ||
|
|
8e8d36772e | ||
|
|
ec04919825 | ||
|
|
6625999765 | ||
|
|
0d3688aca5 | ||
|
|
40be786c43 | ||
|
|
d4a0444223 | ||
|
|
f99cfe77f4 | ||
|
|
ed32531369 | ||
|
|
751af041cd | ||
|
|
a0ceebd59f | ||
|
|
b0b37f2ce6 | ||
|
|
cf1f904ae2 | ||
|
|
8aaf53d76d | ||
|
|
76c03ded89 | ||
|
|
e6fa19b4c5 | ||
|
|
92ee239891 | ||
|
|
c37e2a7524 | ||
|
|
a610fe74ff | ||
|
|
ea49952da2 | ||
|
|
a55946eb5d | ||
|
|
60302c0017 | ||
|
|
08eaf8b7a1 | ||
|
|
cc70ec9362 | ||
|
|
b58ecc7c9d | ||
|
|
668cbcdaf4 | ||
|
|
6d7cbd0989 | ||
|
|
0764f788a6 | ||
|
|
2b95dd7011 | ||
|
|
ae380c30ad | ||
|
|
d2265890bd | ||
|
|
831d49c1b3 | ||
|
|
6935c53510 | ||
|
|
f30d90a179 | ||
|
|
55cfcecfb8 | ||
|
|
233f46a2cb | ||
|
|
342554b3d8 | ||
|
|
7aa812a0e1 | ||
|
|
a411f06dc4 | ||
|
|
d085262076 | ||
|
|
0396740467 | ||
|
|
0fd7de9481 | ||
|
|
ba790dad0a | ||
|
|
f2e8776965 | ||
|
|
444d5eb702 | ||
|
|
3e12e989ab |
@@ -108,8 +108,6 @@ struct async_foo : __handler__, __require_io_service__
|
||||
}
|
||||
};
|
||||
```
|
||||
[caution All async_handlers use one signal(SIGCHLD) on posix, which is only guaranteed to work when all use the same `io_service`]
|
||||
|
||||
[note Inheriting [globalref boost::process::extend::require_io_service require_io_service] is necessary, so [funcref boost::process::system system] provides one.]
|
||||
|
||||
Additionally the handler can provide a function that is invoked when the child process exits. This is done through __async_handler__.
|
||||
@@ -135,6 +133,8 @@ struct async_bar : __handler, __async_handler__
|
||||
|
||||
[caution `on_exit_handler` does not default and is always required when [classref boost::process::extend::async_handler async_handler] is inherited. ]
|
||||
|
||||
[caution `on_exit_handler` uses `boost::asio::signal_set` to listen for SIGCHLD on posix. The application must not also register a signal handler for SIGCHLD using functions such as `signal()` or `sigaction()` (but using `boost::asio::signal_set` is fine). ]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:error Error handling]
|
||||
|
||||
@@ -104,8 +104,8 @@ This also includes to add a file suffix on windows, such as `.exe` or `.bat`.]
|
||||
|
||||
[section:launch_mode Launch functions]
|
||||
|
||||
Given that in our example used the [funcref boost::process::system system] function,
|
||||
our program will wait until the child process is completed. This maybe unwanted,
|
||||
Given that our example used the [funcref boost::process::system system] function,
|
||||
our program will wait until the child process is completed. This may be unwanted,
|
||||
especially since compiling can take a while.
|
||||
|
||||
In order to avoid that, boost.process provides several ways to launch a process.
|
||||
@@ -151,10 +151,10 @@ This can be avoided by calling __detach__ beforehand]
|
||||
|
||||
Until now, we have assumed that everything works out, but it is not impossible,
|
||||
that "g++" is not present. That will cause the launch of the process to fail.
|
||||
The default behaviour of all functions is to throw an
|
||||
The default behaviour of all functions is to throw a
|
||||
[@http://en.cppreference.com/w/cpp/error/system_error std::system_error] on failure.
|
||||
As with many other functions in this library, passing an [@http://en.cppreference.com/w/cpp/error/error_code std::error_code]
|
||||
will change the behaviour, so that instead of throwing an exception, the error will be a assigned to the error code.
|
||||
will change the behaviour, so that instead of throwing an exception, the error will be assigned to the error code.
|
||||
|
||||
```
|
||||
std::error_code ec;
|
||||
@@ -288,7 +288,6 @@ asio_async_read(ap, asio_buffer(buf),
|
||||
[](const boost::system::error_code &ec, std::size_t size){});
|
||||
|
||||
ios.run();
|
||||
c.wait();
|
||||
int result = c.exit_code();
|
||||
```
|
||||
|
||||
@@ -302,7 +301,6 @@ std::vector<char> buf;
|
||||
bp::child c(bp::search_path("g++"), "main.cpp", bp::std_out > asio_buffer(buf), ios);
|
||||
|
||||
ios.run();
|
||||
c.wait();
|
||||
int result = c.exit_code();
|
||||
```
|
||||
|
||||
|
||||
@@ -118,7 +118,9 @@ chlid c2("ls", on_exit=exit_code);
|
||||
|
||||
\note The handler is not invoked when the launch fails.
|
||||
\warning When used \ref ignore_error it might get invoked on error.
|
||||
\warning All `on_exit` use one signal(SIGCHLD) on posix, which is only guaranteed to work when all use the same `io_context`.
|
||||
\warning `on_exit` uses `boost::asio::signal_set` to listen for `SIGCHLD` on posix, and so has the
|
||||
same restrictions as that class (do not register a handler for `SIGCHLD` except by using
|
||||
`boost::asio::signal_set`).
|
||||
*/
|
||||
constexpr static ::boost::process::detail::on_exit_ on_exit{};
|
||||
#endif
|
||||
|
||||
@@ -103,72 +103,52 @@ public:
|
||||
|
||||
bool running()
|
||||
{
|
||||
if (valid() && !_exited())
|
||||
{
|
||||
int code = -1;
|
||||
auto res = boost::process::detail::api::is_running(_child_handle, code);
|
||||
if (!res && !_exited())
|
||||
_exit_status->store(code);
|
||||
|
||||
return res;
|
||||
}
|
||||
return false;
|
||||
std::error_code ec;
|
||||
bool b = running(ec);
|
||||
boost::process::detail::throw_error(ec, "running error");
|
||||
return b;
|
||||
}
|
||||
|
||||
void terminate()
|
||||
{
|
||||
if (valid() && running())
|
||||
boost::process::detail::api::terminate(_child_handle);
|
||||
|
||||
_terminated = true;
|
||||
std::error_code ec;
|
||||
terminate(ec);
|
||||
boost::process::detail::throw_error(ec, "terminate error");
|
||||
}
|
||||
|
||||
void wait()
|
||||
{
|
||||
if (!_exited() && valid())
|
||||
{
|
||||
int exit_code = 0;
|
||||
boost::process::detail::api::wait(_child_handle, exit_code);
|
||||
_exit_status->store(exit_code);
|
||||
}
|
||||
std::error_code ec;
|
||||
wait(ec);
|
||||
boost::process::detail::throw_error(ec, "wait error");
|
||||
}
|
||||
|
||||
template< class Rep, class Period >
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
if (!_exited())
|
||||
{
|
||||
int exit_code = 0;
|
||||
auto b = boost::process::detail::api::wait_for(_child_handle, exit_code, rel_time);
|
||||
if (!b)
|
||||
return false;
|
||||
_exit_status->store(exit_code);
|
||||
}
|
||||
return true;
|
||||
std::error_code ec;
|
||||
bool b = wait_for(rel_time, ec);
|
||||
boost::process::detail::throw_error(ec, "wait_for error");
|
||||
return b;
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
|
||||
{
|
||||
if (!_exited())
|
||||
{
|
||||
int exit_code = 0;
|
||||
auto b = boost::process::detail::api::wait_until(_child_handle, exit_code, timeout_time);
|
||||
if (!b)
|
||||
return false;
|
||||
_exit_status->store(exit_code);
|
||||
}
|
||||
return true;
|
||||
std::error_code ec;
|
||||
bool b = wait_until(timeout_time, ec);
|
||||
boost::process::detail::throw_error(ec, "wait_until error");
|
||||
return b;
|
||||
}
|
||||
|
||||
bool running(std::error_code & ec) noexcept
|
||||
{
|
||||
if (valid() && !_exited())
|
||||
{
|
||||
int code;
|
||||
auto res = boost::process::detail::api::is_running(_child_handle, code, ec);
|
||||
int exit_code = 0;
|
||||
auto res = boost::process::detail::api::is_running(_child_handle, exit_code, ec);
|
||||
if (!res && !_exited())
|
||||
_exit_status->store(code);
|
||||
_exit_status->store(exit_code);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -194,17 +174,9 @@ public:
|
||||
}
|
||||
|
||||
template< class Rep, class Period >
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
|
||||
{
|
||||
if (!_exited())
|
||||
{
|
||||
int exit_code = 0;
|
||||
auto b = boost::process::detail::api::wait_for(_child_handle, exit_code, rel_time, ec);
|
||||
if (!b)
|
||||
return false;
|
||||
_exit_status->store(exit_code);
|
||||
}
|
||||
return true;
|
||||
return wait_until(std::chrono::steady_clock::now() + rel_time, ec);
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
|
||||
@@ -82,6 +82,17 @@ inline void throw_last_error()
|
||||
throw process_error(get_last_error());
|
||||
}
|
||||
|
||||
inline void throw_error(const std::error_code& ec)
|
||||
{
|
||||
if (ec)
|
||||
throw process_error(ec);
|
||||
}
|
||||
|
||||
inline void throw_error(const std::error_code& ec, const char* msg)
|
||||
{
|
||||
if (ec)
|
||||
throw process_error(ec, msg);
|
||||
}
|
||||
|
||||
template<typename Char> constexpr Char null_char();
|
||||
template<> constexpr char null_char<char> (){return '\0';}
|
||||
|
||||
@@ -85,7 +85,9 @@ struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
if (::dup2(pipe->native_source(), STDIN_FILENO) == -1)
|
||||
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
::close(pipe->native_source());
|
||||
if (pipe->native_source() != STDIN_FILENO)
|
||||
::close(pipe->native_source());
|
||||
::close(pipe->native_sink());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -89,6 +89,8 @@ struct async_out_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
::close(pipe->native_sink());
|
||||
::close(pipe->native_source());
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -161,6 +163,7 @@ struct async_out_future : ::boost::process::detail::posix::handler_base_ext,
|
||||
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
::close(pipe->native_sink());
|
||||
::close(pipe->native_source());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -118,12 +118,8 @@ struct exe_cmd_init<char> : boost::process::detail::api::handler_base_ext
|
||||
else
|
||||
exec.exe = &exe.front();
|
||||
|
||||
|
||||
if (!args.empty())
|
||||
{
|
||||
cmd_impl = make_cmd();
|
||||
exec.cmd_line = cmd_impl.data();
|
||||
}
|
||||
cmd_impl = make_cmd();
|
||||
exec.cmd_line = cmd_impl.data();
|
||||
}
|
||||
static exe_cmd_init exe_args(std::string && exe, std::vector<std::string> && args) {return exe_cmd_init(std::move(exe), std::move(args));}
|
||||
static exe_cmd_init cmd (std::string && cmd)
|
||||
@@ -163,8 +159,10 @@ std::vector<char*> exe_cmd_init<char>::make_cmd()
|
||||
if (!exe.empty())
|
||||
vec.push_back(&exe.front());
|
||||
|
||||
for (auto & v : args)
|
||||
vec.push_back(&v.front());
|
||||
if (!args.empty()) {
|
||||
for (auto & v : args)
|
||||
vec.push_back(&v.front());
|
||||
}
|
||||
|
||||
vec.push_back(nullptr);
|
||||
|
||||
|
||||
@@ -6,14 +6,13 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_GROUP_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_GROUP_HPP_
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/posix/child_handle.hpp>
|
||||
#include <system_error>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
|
||||
struct group_handle
|
||||
{
|
||||
pid_t grp = -1;
|
||||
@@ -26,7 +25,6 @@ struct group_handle
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
group_handle() = default;
|
||||
|
||||
~group_handle() = default;
|
||||
@@ -38,7 +36,6 @@ struct group_handle
|
||||
group_handle &operator=(const group_handle & c) = delete;
|
||||
group_handle &operator=(group_handle && c)
|
||||
{
|
||||
|
||||
grp = c.grp;
|
||||
c.grp = -1;
|
||||
return *this;
|
||||
@@ -62,23 +59,14 @@ struct group_handle
|
||||
bool has(handle_t proc, std::error_code & ec) noexcept
|
||||
{
|
||||
return ::getpgid(proc) == grp;
|
||||
|
||||
}
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
return grp != -1;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inline void terminate(group_handle &p)
|
||||
{
|
||||
if (::killpg(p.grp, SIGKILL) == -1)
|
||||
boost::process::detail::throw_last_error("killpg(2) failed");
|
||||
p.grp = -1;
|
||||
}
|
||||
|
||||
inline void terminate(group_handle &p, std::error_code &ec) noexcept
|
||||
{
|
||||
if (::killpg(p.grp, SIGKILL) == -1)
|
||||
@@ -89,15 +77,18 @@ inline void terminate(group_handle &p, std::error_code &ec) noexcept
|
||||
p.grp = -1;
|
||||
}
|
||||
|
||||
inline void terminate(group_handle &p)
|
||||
{
|
||||
std::error_code ec;
|
||||
terminate(p, ec);
|
||||
boost::process::detail::throw_error(ec, "killpg(2) failed in terminate");
|
||||
}
|
||||
|
||||
inline bool in_group()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_ */
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
|
||||
#include <boost/process/detail/posix/sigchld_service.hpp>
|
||||
#include <boost/process/detail/posix/is_running.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
@@ -95,11 +96,11 @@ struct io_context_ref : handler_base_ext
|
||||
auto & es = exec.exit_status;
|
||||
|
||||
auto wh = [funcs, es](int val, const std::error_code & ec)
|
||||
{
|
||||
es->store(val);
|
||||
{
|
||||
es->store(val);
|
||||
for (auto & func : funcs)
|
||||
func(WEXITSTATUS(val), ec);
|
||||
};
|
||||
func(::boost::process::detail::posix::eval_exit_status(val), ec);
|
||||
};
|
||||
|
||||
sigchld_service.async_wait(exec.pid, std::move(wh));
|
||||
}
|
||||
|
||||
@@ -13,37 +13,22 @@
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
// Use the "stopped" state (WIFSTOPPED) to indicate "not terminated".
|
||||
// This bit arrangement of status codes is not guaranteed by POSIX, but (according to comments in
|
||||
// the glibc <bits/waitstatus.h> header) is the same across systems in practice.
|
||||
constexpr int still_active = 0x7F;
|
||||
static_assert(!WIFEXITED(still_active), "Internal Error");
|
||||
static_assert(!WIFEXITED(still_active) && !WIFSIGNALED(still_active), "Internal Error");
|
||||
|
||||
inline bool is_running(const child_handle &p, int & exit_code)
|
||||
inline bool is_running(int code)
|
||||
{
|
||||
int status;
|
||||
auto ret = ::waitpid(p.pid, &status, WNOHANG|WUNTRACED);
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
if (errno != ECHILD) //because it no child is running, than this one isn't either, obviously.
|
||||
::boost::process::detail::throw_last_error("is_running error");
|
||||
|
||||
return false;
|
||||
}
|
||||
else if (ret == 0)
|
||||
return true;
|
||||
else //exited
|
||||
{
|
||||
if (WIFEXITED(status))
|
||||
exit_code = status;
|
||||
return false;
|
||||
}
|
||||
return !WIFEXITED(code) && !WIFSIGNALED(code);
|
||||
}
|
||||
|
||||
inline bool is_running(const child_handle &p, int & exit_code, std::error_code &ec) noexcept
|
||||
{
|
||||
int status;
|
||||
auto ret = ::waitpid(p.pid, &status, WNOHANG|WUNTRACED);
|
||||
|
||||
auto ret = ::waitpid(p.pid, &status, WNOHANG);
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
if (errno != ECHILD) //because it no child is running, than this one isn't either, obviously.
|
||||
@@ -55,22 +40,36 @@ inline bool is_running(const child_handle &p, int & exit_code, std::error_code &
|
||||
else
|
||||
{
|
||||
ec.clear();
|
||||
|
||||
if (WIFEXITED(status))
|
||||
|
||||
if (!is_running(status))
|
||||
exit_code = status;
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool is_running(int code)
|
||||
inline bool is_running(const child_handle &p, int & exit_code)
|
||||
{
|
||||
return !WIFEXITED(code);
|
||||
std::error_code ec;
|
||||
bool b = is_running(p, exit_code, ec);
|
||||
boost::process::detail::throw_error(ec, "waitpid(2) failed in is_running");
|
||||
return b;
|
||||
}
|
||||
|
||||
inline int eval_exit_status(int code)
|
||||
{
|
||||
return WEXITSTATUS(code);
|
||||
if (WIFEXITED(code))
|
||||
{
|
||||
return WEXITSTATUS(code);
|
||||
}
|
||||
else if (WIFSIGNALED(code))
|
||||
{
|
||||
return WTERMSIG(code);
|
||||
}
|
||||
else
|
||||
{
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
@@ -27,7 +27,9 @@ inline boost::filesystem::path search_path(
|
||||
for (const boost::filesystem::path & pp : path)
|
||||
{
|
||||
auto p = pp / filename;
|
||||
if (!::access(p.c_str(), X_OK))
|
||||
boost::system::error_code ec;
|
||||
bool file = boost::filesystem::is_regular_file(p, ec);
|
||||
if (!ec && file && ::access(p.c_str(), X_OK) == 0)
|
||||
return p;
|
||||
}
|
||||
return "";
|
||||
|
||||
@@ -77,19 +77,28 @@ void sigchld_service::_handle_signal(const boost::system::error_code & ec)
|
||||
r.second(-1, ec_);
|
||||
return;
|
||||
}
|
||||
int status;
|
||||
int pid = ::waitpid(0, &status, WNOHANG);
|
||||
|
||||
auto itr = std::find_if(_receivers.begin(), _receivers.end(),
|
||||
[&pid](const std::pair<::pid_t, std::function<void(int, std::error_code)>> & p)
|
||||
{
|
||||
return p.first == pid;
|
||||
});
|
||||
if (itr != _receivers.cend())
|
||||
{
|
||||
_strand.get_io_context().wrap(itr->second)(status, ec_);
|
||||
_receivers.erase(itr);
|
||||
for (auto & r : _receivers) {
|
||||
int status;
|
||||
int pid = ::waitpid(r.first, &status, WNOHANG);
|
||||
if (pid < 0) {
|
||||
// error (eg: the process no longer exists)
|
||||
r.second(-1, get_last_error());
|
||||
r.first = 0; // mark for deletion
|
||||
} else if (pid == r.first) {
|
||||
r.second(status, ec_);
|
||||
r.first = 0; // mark for deletion
|
||||
}
|
||||
// otherwise the process is still around
|
||||
}
|
||||
|
||||
_receivers.erase(std::remove_if(_receivers.begin(), _receivers.end(),
|
||||
[](const std::pair<::pid_t, std::function<void(int, std::error_code)>> & p)
|
||||
{
|
||||
return p.first == 0;
|
||||
}),
|
||||
_receivers.end());
|
||||
|
||||
if (!_receivers.empty())
|
||||
{
|
||||
_signal_set.async_wait(
|
||||
|
||||
@@ -19,15 +19,6 @@
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
inline void terminate(const child_handle &p)
|
||||
{
|
||||
if (::kill(p.pid, SIGKILL) == -1)
|
||||
boost::process::detail::throw_last_error("kill(2) failed");
|
||||
int status;
|
||||
::waitpid(p.pid, &status, 0); //just to clean it up
|
||||
}
|
||||
|
||||
inline void terminate(const child_handle &p, std::error_code &ec) noexcept
|
||||
{
|
||||
if (::kill(p.pid, SIGKILL) == -1)
|
||||
@@ -39,6 +30,13 @@ inline void terminate(const child_handle &p, std::error_code &ec) noexcept
|
||||
::waitpid(p.pid, &status, 0); //just to clean it up
|
||||
}
|
||||
|
||||
inline void terminate(const child_handle &p)
|
||||
{
|
||||
std::error_code ec;
|
||||
terminate(p, ec);
|
||||
boost::process::detail::throw_error(ec, "kill(2) failed");
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,21 +19,6 @@
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
inline void wait(const child_handle &p, int & exit_code)
|
||||
{
|
||||
pid_t ret;
|
||||
int status;
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(p.pid, &status, 0);
|
||||
} while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status) && !WIFSIGNALED(status)));
|
||||
if (ret == -1)
|
||||
boost::process::detail::throw_last_error("waitpid(2) failed");
|
||||
if (WIFSIGNALED(status))
|
||||
throw process_error(std::error_code(), "process terminated due to receipt of a signal");
|
||||
exit_code = status;
|
||||
}
|
||||
|
||||
inline void wait(const child_handle &p, int & exit_code, std::error_code &ec) noexcept
|
||||
{
|
||||
pid_t ret;
|
||||
@@ -44,87 +29,6 @@ inline void wait(const child_handle &p, int & exit_code, std::error_code &ec) no
|
||||
ret = ::waitpid(p.pid, &status, 0);
|
||||
}
|
||||
while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status) && !WIFSIGNALED(status)));
|
||||
|
||||
if (ret == -1)
|
||||
ec = boost::process::detail::get_last_error();
|
||||
else
|
||||
{
|
||||
ec.clear();
|
||||
exit_code = status;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
const child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
|
||||
pid_t ret;
|
||||
int status;
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
auto time_out = start + rel_time;
|
||||
|
||||
bool timed_out;
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(p.pid, &status, WNOHANG);
|
||||
if (ret == 0)
|
||||
{
|
||||
timed_out = std::chrono::system_clock::now() >= time_out;
|
||||
if (timed_out)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while ((ret == 0) ||
|
||||
((ret == -1) && errno == EINTR) ||
|
||||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status)));
|
||||
|
||||
if (ret == -1)
|
||||
boost::process::detail::throw_last_error("waitpid(2) failed");
|
||||
|
||||
exit_code = status;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
const child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::duration<Rep, Period>& rel_time,
|
||||
std::error_code & ec) noexcept
|
||||
{
|
||||
|
||||
pid_t ret;
|
||||
int status;
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
auto time_out = start + rel_time;
|
||||
bool timed_out;
|
||||
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(p.pid, &status, WNOHANG);
|
||||
if (ret == 0)
|
||||
{
|
||||
timed_out = std::chrono::system_clock::now() >= time_out;
|
||||
if (timed_out)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while ((ret == 0) ||
|
||||
(((ret == -1) && errno == EINTR) ||
|
||||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status))));
|
||||
|
||||
|
||||
if (timed_out && (ret == -1))
|
||||
return false;
|
||||
|
||||
if (ret == -1)
|
||||
ec = boost::process::detail::get_last_error();
|
||||
@@ -133,49 +37,15 @@ inline bool wait_for(
|
||||
ec.clear();
|
||||
exit_code = status;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template< class Clock, class Duration >
|
||||
inline bool wait_until(
|
||||
const child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::time_point<Clock, Duration>& time_out)
|
||||
inline void wait(const child_handle &p, int & exit_code) noexcept
|
||||
{
|
||||
|
||||
pid_t ret;
|
||||
int status;
|
||||
|
||||
bool timed_out;
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(p.pid, &status, WNOHANG);
|
||||
if (ret == 0)
|
||||
{
|
||||
timed_out = std::chrono::system_clock::now() >= time_out;
|
||||
if (timed_out)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while ((ret == 0) ||
|
||||
(((ret == -1) && errno == EINTR) ||
|
||||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status))));
|
||||
|
||||
|
||||
if (timed_out && !WIFEXITED(status))
|
||||
return false;
|
||||
|
||||
if (ret == -1)
|
||||
boost::process::detail::throw_last_error("waitpid(2) failed");
|
||||
exit_code = status;
|
||||
|
||||
return true;
|
||||
std::error_code ec;
|
||||
wait(p, exit_code, ec);
|
||||
boost::process::detail::throw_error(ec, "waitpid(2) failed in wait");
|
||||
}
|
||||
|
||||
|
||||
template< class Clock, class Duration >
|
||||
inline bool wait_until(
|
||||
const child_handle &p,
|
||||
@@ -183,7 +53,6 @@ inline bool wait_until(
|
||||
const std::chrono::time_point<Clock, Duration>& time_out,
|
||||
std::error_code & ec) noexcept
|
||||
{
|
||||
|
||||
pid_t ret;
|
||||
int status;
|
||||
|
||||
@@ -194,20 +63,15 @@ inline bool wait_until(
|
||||
ret = ::waitpid(p.pid, &status, WNOHANG);
|
||||
if (ret == 0)
|
||||
{
|
||||
timed_out = std::chrono::system_clock::now() >= time_out;
|
||||
timed_out = Clock::now() >= time_out;
|
||||
if (timed_out)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
while ((ret == 0) ||
|
||||
(((ret == -1) && errno == EINTR) ||
|
||||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status))));
|
||||
|
||||
|
||||
|
||||
if (timed_out && !WIFEXITED(status))
|
||||
return false;
|
||||
|
||||
if (ret == -1)
|
||||
ec = boost::process::detail::get_last_error();
|
||||
else
|
||||
@@ -219,6 +83,40 @@ inline bool wait_until(
|
||||
return true;
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
inline bool wait_until(
|
||||
const child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::time_point<Clock, Duration>& time_out) noexcept
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = wait_until(p, exit_code, time_out, ec);
|
||||
boost::process::detail::throw_error(ec, "waitpid(2) failed in wait_until");
|
||||
return b;
|
||||
}
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
const child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::duration<Rep, Period>& rel_time,
|
||||
std::error_code & ec) noexcept
|
||||
{
|
||||
return wait_until(p, exit_code, std::chrono::steady_clock::now() + rel_time, ec);
|
||||
}
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
const child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::duration<Rep, Period>& rel_time) noexcept
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = wait_for(p, exit_code, rel_time, ec);
|
||||
boost::process::detail::throw_error(ec, "waitpid(2) failed in wait_for");
|
||||
return b;
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,26 +12,13 @@
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/posix/group_handle.hpp>
|
||||
#include <chrono>
|
||||
#include <system_error>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
inline void wait(const group_handle &p)
|
||||
{
|
||||
pid_t ret;
|
||||
int status;
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(-p.grp, &status, 0);
|
||||
} while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status) && !WIFSIGNALED(status)));
|
||||
if (ret == -1)
|
||||
boost::process::detail::throw_last_error("waitpid(2) failed");
|
||||
if (WIFSIGNALED(status))
|
||||
throw process_error(std::error_code(), "process group terminated due to receipt of a signal");
|
||||
}
|
||||
|
||||
inline void wait(const group_handle &p, std::error_code &ec) noexcept
|
||||
{
|
||||
pid_t ret;
|
||||
@@ -42,50 +29,63 @@ inline void wait(const group_handle &p, std::error_code &ec) noexcept
|
||||
ret = ::waitpid(-p.grp, &status, 0);
|
||||
}
|
||||
while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status) && !WIFSIGNALED(status)));
|
||||
|
||||
|
||||
if (ret == -1)
|
||||
ec = boost::process::detail::get_last_error();
|
||||
else if (WIFSIGNALED(status))
|
||||
ec = std::make_error_code(std::errc::no_such_process);
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
}
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
const group_handle &p,
|
||||
const std::chrono::duration<Rep, Period>& rel_time)
|
||||
inline void wait(const group_handle &p) noexcept
|
||||
{
|
||||
std::error_code ec;
|
||||
wait(p, ec);
|
||||
boost::process::detail::throw_error(ec, "waitpid(2) failed in wait");
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
inline bool wait_until(
|
||||
const group_handle &p,
|
||||
const std::chrono::time_point<Clock, Duration>& time_out,
|
||||
std::error_code & ec) noexcept
|
||||
{
|
||||
pid_t ret;
|
||||
int status;
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
auto time_out = start + rel_time;
|
||||
bool timed_out;
|
||||
|
||||
bool time_out_occured = false;
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG);
|
||||
if (std::chrono::system_clock::now() >= time_out)
|
||||
ret = ::waitpid(-p.grp, &status, WNOHANG);
|
||||
if (ret == 0)
|
||||
{
|
||||
time_out_occured = true;
|
||||
break;
|
||||
timed_out = Clock::now() >= time_out;
|
||||
if (timed_out)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while (((ret == -1) && errno == EINTR) ||
|
||||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status)));
|
||||
|
||||
}
|
||||
while ((ret == 0) ||
|
||||
(((ret == -1) && errno == EINTR) ||
|
||||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status))));
|
||||
|
||||
if (ret == -1)
|
||||
boost::process::detail::throw_last_error("waitpid(2) failed");
|
||||
if (WIFSIGNALED(status))
|
||||
throw process_error(std::error_code(), "process group terminated due to receipt of a signal");
|
||||
ec = boost::process::detail::get_last_error();
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
return !time_out_occured;
|
||||
return true;
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
inline bool wait_until(
|
||||
const group_handle &p,
|
||||
const std::chrono::time_point<Clock, Duration>& time_out) noexcept
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = wait_until(p, time_out, ec);
|
||||
boost::process::detail::throw_error(ec, "waitpid(2) failed in wait_until");
|
||||
return b;
|
||||
}
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
@@ -93,104 +93,18 @@ inline bool wait_for(
|
||||
const std::chrono::duration<Rep, Period>& rel_time,
|
||||
std::error_code & ec) noexcept
|
||||
{
|
||||
|
||||
pid_t ret;
|
||||
int status;
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
auto time_out = start + rel_time;
|
||||
|
||||
bool time_out_occured = false;
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG);
|
||||
if (std::chrono::system_clock::now() >= time_out)
|
||||
{
|
||||
time_out_occured = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (((ret == -1) && errno == EINTR) ||
|
||||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status)));
|
||||
|
||||
|
||||
if (ret == -1)
|
||||
ec = boost::process::detail::get_last_error();
|
||||
else if (WIFSIGNALED(status))
|
||||
ec = std::make_error_code(std::errc::no_such_process);
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
return !time_out_occured;
|
||||
return wait_until(p, std::chrono::steady_clock::now() + rel_time, ec);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_until(
|
||||
inline bool wait_for(
|
||||
const group_handle &p,
|
||||
const std::chrono::duration<Rep, Period>& time_out)
|
||||
const std::chrono::duration<Rep, Period>& rel_time) noexcept
|
||||
{
|
||||
|
||||
pid_t ret;
|
||||
int status;
|
||||
|
||||
bool time_out_occured = false;
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG);
|
||||
if (std::chrono::system_clock::now() >= time_out)
|
||||
{
|
||||
time_out_occured = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (((ret == -1) && errno == EINTR) ||
|
||||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status)));
|
||||
|
||||
|
||||
if (ret == -1)
|
||||
boost::process::detail::throw_last_error("waitpid(2) failed");
|
||||
if (WIFSIGNALED(status))
|
||||
throw process_error(std::error_code(), "process group terminated due to receipt of a signal");
|
||||
|
||||
|
||||
return !time_out_occured;
|
||||
}
|
||||
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_until(
|
||||
const group_handle &p,
|
||||
const std::chrono::duration<Rep, Period>& time_out,
|
||||
std::error_code & ec) noexcept
|
||||
{
|
||||
|
||||
pid_t ret;
|
||||
int status;
|
||||
|
||||
bool time_out_occured = false;
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG);
|
||||
if (std::chrono::system_clock::now() >= time_out)
|
||||
{
|
||||
time_out_occured = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (((ret == -1) && errno == EINTR) ||
|
||||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status)));
|
||||
|
||||
|
||||
if (ret == -1)
|
||||
ec = boost::process::detail::get_last_error();
|
||||
else if (WIFSIGNALED(status))
|
||||
ec = std::make_error_code(std::errc::no_such_process);
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
return !time_out_occured;
|
||||
std::error_code ec;
|
||||
bool b = wait_for(p, rel_time, ec);
|
||||
boost::process::detail::throw_error(ec, "waitpid(2) failed in wait_for");
|
||||
return b;
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
@@ -27,7 +27,7 @@ inline std::string make_pipe_name()
|
||||
|
||||
auto pid = ::boost::winapi::GetCurrentProcessId();
|
||||
|
||||
static std::atomic_size_t cnt = 0;
|
||||
static std::atomic_size_t cnt{0};
|
||||
name += std::to_string(pid);
|
||||
name += "_";
|
||||
name += std::to_string(cnt++);
|
||||
@@ -265,7 +265,11 @@ async_pipe::async_pipe(boost::asio::io_context & ios_source,
|
||||
static constexpr int FILE_FLAG_OVERLAPPED_ = 0x40000000; //temporary
|
||||
|
||||
::boost::winapi::HANDLE_ source = ::boost::winapi::create_named_pipe(
|
||||
#if defined(BOOST_NO_ANSI_APIS)
|
||||
::boost::process::detail::convert(name).c_str(),
|
||||
#else
|
||||
name.c_str(),
|
||||
#endif
|
||||
::boost::winapi::PIPE_ACCESS_INBOUND_
|
||||
| FILE_FLAG_OVERLAPPED_, //write flag
|
||||
0, 1, 8192, 8192, 0, nullptr);
|
||||
@@ -277,7 +281,11 @@ async_pipe::async_pipe(boost::asio::io_context & ios_source,
|
||||
_source.assign(source);
|
||||
|
||||
::boost::winapi::HANDLE_ sink = boost::winapi::create_file(
|
||||
#if defined(BOOST_NO_ANSI_APIS)
|
||||
::boost::process::detail::convert(name).c_str(),
|
||||
#else
|
||||
name.c_str(),
|
||||
#endif
|
||||
::boost::winapi::GENERIC_WRITE_, 0, nullptr,
|
||||
::boost::winapi::OPEN_EXISTING_,
|
||||
FILE_FLAG_OVERLAPPED_, //to allow read
|
||||
|
||||
@@ -45,11 +45,19 @@ struct file_descriptor
|
||||
}
|
||||
|
||||
file_descriptor(const std::string & path , mode_t mode = read_write)
|
||||
: file_descriptor(path.c_str(), mode) {}
|
||||
#if defined(BOOST_NO_ANSI_APIS)
|
||||
: file_descriptor(::boost::process::detail::convert(path), mode)
|
||||
#else
|
||||
: file_descriptor(path.c_str(), mode)
|
||||
#endif
|
||||
{}
|
||||
file_descriptor(const std::wstring & path, mode_t mode = read_write)
|
||||
: file_descriptor(path.c_str(), mode) {}
|
||||
|
||||
file_descriptor(const char* path, mode_t mode = read_write)
|
||||
#if defined(BOOST_NO_ANSI_APIS)
|
||||
: file_descriptor(std::string(path), mode)
|
||||
#else
|
||||
: _handle(
|
||||
::boost::winapi::create_file(
|
||||
path,
|
||||
@@ -62,8 +70,8 @@ struct file_descriptor
|
||||
::boost::winapi::FILE_ATTRIBUTE_NORMAL_,
|
||||
nullptr
|
||||
))
|
||||
#endif
|
||||
{
|
||||
|
||||
}
|
||||
file_descriptor(const wchar_t * path, mode_t mode = read_write)
|
||||
: _handle(
|
||||
|
||||
@@ -103,7 +103,7 @@ struct group_handle
|
||||
}
|
||||
|
||||
|
||||
group_handle() : group_handle(::boost::winapi::CreateJobObjectA(nullptr, nullptr))
|
||||
group_handle() : group_handle(::boost::winapi::CreateJobObjectW(nullptr, nullptr))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -18,22 +18,6 @@ constexpr static ::boost::winapi::DWORD_ still_active = 259;
|
||||
|
||||
struct child_handle;
|
||||
|
||||
inline bool is_running(const child_handle &p, int & exit_code)
|
||||
{
|
||||
::boost::winapi::DWORD_ code;
|
||||
//single value, not needed in the winapi.
|
||||
if (!::boost::winapi::GetExitCodeProcess(p.process_handle(), &code))
|
||||
::boost::process::detail::throw_last_error("GetExitCodeProcess() failed");
|
||||
|
||||
if (code == still_active)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
exit_code = code;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool is_running(const child_handle &p, int & exit_code, std::error_code &ec) noexcept
|
||||
{
|
||||
::boost::winapi::DWORD_ code;
|
||||
@@ -49,7 +33,15 @@ inline bool is_running(const child_handle &p, int & exit_code, std::error_code &
|
||||
{
|
||||
exit_code = code;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline bool is_running(const child_handle &p, int & exit_code)
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = is_running(p, exit_code, ec);
|
||||
boost::process::detail::throw_error(ec, "GetExitCodeProcess() failed in is_running");
|
||||
return b;
|
||||
}
|
||||
|
||||
inline bool is_running(int code)
|
||||
|
||||
@@ -97,7 +97,7 @@ inline ::boost::winapi::BOOL_ WINAPI query_information_job_object(
|
||||
::boost::winapi::DWORD_ cbJobObjectInfoLength,
|
||||
::boost::winapi::DWORD_ *lpReturnLength)
|
||||
{
|
||||
static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle("Kernel32.dll");
|
||||
static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle(L"Kernel32.dll");
|
||||
static query_information_job_object_p f = reinterpret_cast<query_information_job_object_p>(::boost::winapi::get_proc_address(h, "QueryInformationJobObject"));
|
||||
|
||||
return (*f)(hJob, JobObjectInfoClass, lpJobObjectInfo, cbJobObjectInfoLength, lpReturnLength);
|
||||
@@ -124,7 +124,7 @@ inline ::boost::winapi::BOOL_ WINAPI set_information_job_object(
|
||||
void * lpJobObjectInfo,
|
||||
::boost::winapi::DWORD_ cbJobObjectInfoLength)
|
||||
{
|
||||
static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle("Kernel32.dll");
|
||||
static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle(L"Kernel32.dll");
|
||||
static set_information_job_object_p f = reinterpret_cast<set_information_job_object_p>(::boost::winapi::get_proc_address(h, "SetInformationJobObject"));
|
||||
|
||||
return (*f)(hJob, JobObjectInfoClass, lpJobObjectInfo, cbJobObjectInfoLength);
|
||||
|
||||
@@ -41,11 +41,15 @@ class windows_file_codecvt
|
||||
wchar_t* to, wchar_t* to_end, wchar_t*& to_next) const override
|
||||
{
|
||||
boost::ignore_unused(state);
|
||||
::boost::winapi::UINT_ codepage = AreFileApisANSI() ?
|
||||
::boost::winapi::CP_ACP_ :
|
||||
::boost::winapi::CP_OEMCP_;
|
||||
|
||||
int count;
|
||||
auto codepage =
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
::boost::winapi::AreFileApisANSI() ?
|
||||
::boost::winapi::CP_ACP_ :
|
||||
#endif
|
||||
::boost::winapi::CP_OEMCP_;
|
||||
|
||||
int count = 0;
|
||||
if ((count = ::boost::winapi::MultiByteToWideChar(codepage,
|
||||
::boost::winapi::MB_PRECOMPOSED_, from,
|
||||
static_cast<int>(from_end - from), to, static_cast<int>(to_end - to))) == 0)
|
||||
@@ -64,11 +68,15 @@ class windows_file_codecvt
|
||||
char* to, char* to_end, char*& to_next) const override
|
||||
{
|
||||
boost::ignore_unused(state);
|
||||
auto codepage = ::boost::winapi::AreFileApisANSI() ?
|
||||
auto codepage =
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
::boost::winapi::AreFileApisANSI() ?
|
||||
::boost::winapi::CP_ACP_ :
|
||||
#endif
|
||||
::boost::winapi::CP_OEMCP_;
|
||||
int count = 0;
|
||||
|
||||
|
||||
int count;
|
||||
if ((count = ::boost::winapi::WideCharToMultiByte(codepage,
|
||||
::boost::winapi::WC_NO_BEST_FIT_CHARS_, from,
|
||||
static_cast<int>(from_end - from), to, static_cast<int>(to_end - to), 0, 0)) == 0)
|
||||
|
||||
@@ -29,8 +29,14 @@ struct show_window : ::boost::process::detail::handler_base
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct create_no_window_ : public ::boost::process::detail::handler_base
|
||||
{
|
||||
template <class Executor>
|
||||
void on_setup(Executor &exec) const
|
||||
{
|
||||
exec.creation_flags |= ::boost::detail::winapi::CREATE_NO_WINDOW_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
@@ -20,15 +20,6 @@ namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
struct child_handle;
|
||||
|
||||
inline void terminate(child_handle &p)
|
||||
{
|
||||
if (!::boost::winapi::TerminateProcess(p.process_handle(), EXIT_FAILURE))
|
||||
boost::process::detail::throw_last_error("TerminateProcess() failed");
|
||||
|
||||
::boost::winapi::CloseHandle(p.proc_info.hProcess);
|
||||
p.proc_info.hProcess = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
}
|
||||
|
||||
inline void terminate(child_handle &p, std::error_code &ec) noexcept
|
||||
{
|
||||
if (!::boost::winapi::TerminateProcess(p.process_handle(), EXIT_FAILURE))
|
||||
@@ -41,8 +32,12 @@ inline void terminate(child_handle &p, std::error_code &ec) noexcept
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline void terminate(child_handle &p)
|
||||
{
|
||||
std::error_code ec;
|
||||
terminate(p, ec);
|
||||
boost::process::detail::throw_error(ec, "TerminateProcess() failed in terminate");
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
@@ -20,21 +20,6 @@
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
inline void wait(child_handle &p, int & exit_code)
|
||||
{
|
||||
if (::boost::winapi::WaitForSingleObject(p.process_handle(),
|
||||
::boost::winapi::infinite) == ::boost::winapi::wait_failed)
|
||||
throw_last_error("WaitForSingleObject() failed");
|
||||
|
||||
::boost::winapi::DWORD_ _exit_code;
|
||||
if (!::boost::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
|
||||
throw_last_error("GetExitCodeProcess() failed");
|
||||
|
||||
::boost::winapi::CloseHandle(p.proc_info.hProcess);
|
||||
p.proc_info.hProcess = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
exit_code = static_cast<int>(_exit_code);
|
||||
}
|
||||
|
||||
inline void wait(child_handle &p, int & exit_code, std::error_code &ec) noexcept
|
||||
{
|
||||
::boost::winapi::DWORD_ _exit_code = 1;
|
||||
@@ -56,104 +41,13 @@ inline void wait(child_handle &p, int & exit_code, std::error_code &ec) noexcept
|
||||
exit_code = static_cast<int>(_exit_code);
|
||||
}
|
||||
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::duration<Rep, Period>& rel_time)
|
||||
inline void wait(child_handle &p, int & exit_code)
|
||||
{
|
||||
|
||||
std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time);
|
||||
|
||||
::boost::winapi::DWORD_ wait_code;
|
||||
wait_code = ::boost::winapi::WaitForSingleObject(p.process_handle(),
|
||||
static_cast<::boost::winapi::DWORD_>(ms.count()));
|
||||
if (wait_code == ::boost::winapi::wait_failed)
|
||||
throw_last_error("WaitForSingleObject() failed");
|
||||
else if (wait_code == ::boost::winapi::wait_timeout)
|
||||
return false; //
|
||||
|
||||
::boost::winapi::DWORD_ _exit_code;
|
||||
if (!::boost::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
|
||||
throw_last_error("GetExitCodeProcess() failed");
|
||||
|
||||
exit_code = static_cast<int>(_exit_code);
|
||||
::boost::winapi::CloseHandle(p.proc_info.hProcess);
|
||||
p.proc_info.hProcess = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
return true;
|
||||
std::error_code ec;
|
||||
wait(p, exit_code, ec);
|
||||
boost::process::detail::throw_error(ec, "wait error");
|
||||
}
|
||||
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::duration<Rep, Period>& rel_time,
|
||||
std::error_code &ec) noexcept
|
||||
{
|
||||
|
||||
std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time);
|
||||
|
||||
|
||||
::boost::winapi::DWORD_ wait_code;
|
||||
wait_code = ::boost::winapi::WaitForSingleObject(p.process_handle(),
|
||||
static_cast<::boost::winapi::DWORD_>(ms.count()));
|
||||
if (wait_code == ::boost::winapi::wait_failed)
|
||||
ec = std::error_code(
|
||||
::boost::winapi::GetLastError(),
|
||||
std::system_category());
|
||||
else if (wait_code == ::boost::winapi::wait_timeout)
|
||||
return false; //
|
||||
|
||||
::boost::winapi::DWORD_ _exit_code = 1;
|
||||
if (!::boost::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
|
||||
{
|
||||
ec = std::error_code(
|
||||
::boost::winapi::GetLastError(),
|
||||
std::system_category());
|
||||
return false;
|
||||
}
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
exit_code = static_cast<int>(_exit_code);
|
||||
::boost::winapi::CloseHandle(p.proc_info.hProcess);
|
||||
p.proc_info.hProcess = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
return true;
|
||||
;
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
inline bool wait_until(
|
||||
child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::time_point<Clock, Duration>& timeout_time)
|
||||
{
|
||||
std::chrono::milliseconds ms =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
timeout_time - std::chrono::system_clock::now());
|
||||
|
||||
::boost::winapi::DWORD_ wait_code;
|
||||
wait_code = ::boost::winapi::WaitForSingleObject(p.process_handle(),
|
||||
static_cast<::boost::winapi::DWORD_>(ms.count()));
|
||||
|
||||
if (wait_code == ::boost::winapi::wait_failed)
|
||||
throw_last_error("WaitForSingleObject() failed");
|
||||
else if (wait_code == ::boost::winapi::wait_timeout)
|
||||
return false;
|
||||
|
||||
::boost::winapi::DWORD_ _exit_code;
|
||||
if (!::boost::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
|
||||
throw_last_error("GetExitCodeProcess() failed");
|
||||
|
||||
exit_code = static_cast<int>(_exit_code);
|
||||
::boost::winapi::CloseHandle(p.proc_info.hProcess);
|
||||
p.proc_info.hProcess = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template< class Clock, class Duration >
|
||||
inline bool wait_until(
|
||||
child_handle &p,
|
||||
@@ -163,7 +57,7 @@ inline bool wait_until(
|
||||
{
|
||||
std::chrono::milliseconds ms =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
timeout_time - std::chrono::system_clock::now());
|
||||
timeout_time - Clock::now());
|
||||
|
||||
::boost::winapi::DWORD_ wait_code;
|
||||
wait_code = ::boost::winapi::WaitForSingleObject(p.process_handle(),
|
||||
@@ -174,7 +68,7 @@ inline bool wait_until(
|
||||
::boost::winapi::GetLastError(),
|
||||
std::system_category());
|
||||
else if (wait_code == ::boost::winapi::wait_timeout)
|
||||
return false;
|
||||
return false;
|
||||
|
||||
::boost::winapi::DWORD_ _exit_code;
|
||||
if (!::boost::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
|
||||
@@ -188,9 +82,41 @@ inline bool wait_until(
|
||||
::boost::winapi::CloseHandle(p.proc_info.hProcess);
|
||||
p.proc_info.hProcess = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
return true;
|
||||
;
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
inline bool wait_until(
|
||||
child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::time_point<Clock, Duration>& timeout_time)
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = wait_until(p, exit_code, timeout_time, ec);
|
||||
boost::process::detail::throw_error(ec, "wait_until error");
|
||||
return b;
|
||||
}
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::duration<Rep, Period>& rel_time,
|
||||
std::error_code &ec) noexcept
|
||||
{
|
||||
return wait_until(p, exit_code, std::chrono::steady_clock::now() + rel_time, ec);
|
||||
}
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = wait_for(p, exit_code, rel_time, ec);
|
||||
boost::process::detail::throw_error(ec, "wait_for error");
|
||||
return b;
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
@@ -9,20 +9,12 @@
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/winapi/jobs.hpp>
|
||||
#include <boost/winapi/wait.hpp>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
struct group_handle;
|
||||
|
||||
inline void wait(const group_handle &p)
|
||||
{
|
||||
if (::boost::winapi::WaitForSingleObject(p.handle(),
|
||||
::boost::winapi::infinite) == ::boost::winapi::wait_failed)
|
||||
throw_last_error("WaitForSingleObject() failed");
|
||||
|
||||
}
|
||||
|
||||
inline void wait(const group_handle &p, std::error_code &ec)
|
||||
{
|
||||
if (::boost::winapi::WaitForSingleObject(p.handle(),
|
||||
@@ -30,38 +22,26 @@ inline void wait(const group_handle &p, std::error_code &ec)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
const group_handle &p,
|
||||
const std::chrono::duration<Rep, Period>& rel_time)
|
||||
inline void wait(const group_handle &p)
|
||||
{
|
||||
|
||||
std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time);
|
||||
|
||||
::boost::winapi::DWORD_ wait_code;
|
||||
wait_code = ::boost::winapi::WaitForSingleObject(p.handle(), ms.count());
|
||||
if (wait_code == ::boost::winapi::wait_failed)
|
||||
throw_last_error("WaitForSingleObject() failed");
|
||||
else if (wait_code == ::boost::winapi::wait_timeout)
|
||||
return false; //
|
||||
|
||||
return true;
|
||||
std::error_code ec;
|
||||
wait(p, ec);
|
||||
boost::process::detail::throw_error(ec, "wait error");
|
||||
}
|
||||
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
template< class Clock, class Duration >
|
||||
inline bool wait_until(
|
||||
const group_handle &p,
|
||||
const std::chrono::duration<Rep, Period>& rel_time,
|
||||
const std::chrono::time_point<Clock, Duration>& timeout_time,
|
||||
std::error_code &ec)
|
||||
{
|
||||
|
||||
std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time);
|
||||
|
||||
std::chrono::milliseconds ms =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
timeout_time - Clock::now());
|
||||
|
||||
::boost::winapi::DWORD_ wait_code;
|
||||
wait_code = ::boost::winapi::WaitForSingleObject(p.handle(), ms.count());
|
||||
|
||||
if (wait_code == ::boost::winapi::wait_failed)
|
||||
ec = get_last_error();
|
||||
|
||||
@@ -76,44 +56,30 @@ inline bool wait_until(
|
||||
const group_handle &p,
|
||||
const std::chrono::time_point<Clock, Duration>& timeout_time)
|
||||
{
|
||||
std::chrono::milliseconds ms =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
timeout_time - std::chrono::system_clock::now());
|
||||
|
||||
::boost::winapi::DWORD_ wait_code;
|
||||
wait_code = ::boost::winapi::WaitForSingleObject(p.handle(), ms.count());
|
||||
|
||||
if (wait_code == ::boost::winapi::wait_failed)
|
||||
throw_last_error("WaitForSingleObject() failed");
|
||||
|
||||
else if (wait_code == ::boost::winapi::wait_timeout)
|
||||
return false; //
|
||||
|
||||
return true;
|
||||
std::error_code ec;
|
||||
bool b = wait_until(p, timeout_time, ec);
|
||||
boost::process::detail::throw_error(ec, "wait_until error");
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
template< class Clock, class Duration >
|
||||
inline bool wait_until(
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
const group_handle &p,
|
||||
const std::chrono::time_point<Clock, Duration>& timeout_time,
|
||||
const std::chrono::duration<Rep, Period>& rel_time,
|
||||
std::error_code &ec)
|
||||
{
|
||||
std::chrono::milliseconds ms =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
timeout_time - std::chrono::system_clock::now());
|
||||
return wait_until(p, std::chrono::steady_clock::now() + rel_time, ec);
|
||||
}
|
||||
|
||||
::boost::winapi::DWORD_ wait_code;
|
||||
wait_code = ::boost::winapi::WaitForSingleObject(p.handle(), ms.count());
|
||||
|
||||
if (wait_code == ::boost::winapi::wait_failed)
|
||||
ec = get_last_error();
|
||||
|
||||
else if (wait_code == ::boost::winapi::wait_timeout)
|
||||
return false; //
|
||||
|
||||
return true;
|
||||
;
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
const group_handle &p,
|
||||
const std::chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = wait_for(p, rel_time, ec);
|
||||
boost::process::detail::throw_error(ec, "wait_for error");
|
||||
return b;
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
@@ -631,14 +631,17 @@ public:
|
||||
};
|
||||
|
||||
|
||||
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
///Definition of the environment for the current process.
|
||||
typedef basic_native_environment<char> native_environment;
|
||||
#endif
|
||||
///Definition of the environment for the current process.
|
||||
typedef basic_native_environment<wchar_t> wnative_environment;
|
||||
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
///Type definition to hold a seperate environment.
|
||||
typedef basic_environment<char> environment;
|
||||
#endif
|
||||
///Type definition to hold a seperate environment.
|
||||
typedef basic_environment<wchar_t> wenvironment;
|
||||
|
||||
@@ -651,8 +654,10 @@ namespace this_process
|
||||
///Definition of the native handle type.
|
||||
typedef ::boost::process::detail::api::native_handle_t native_handle_type;
|
||||
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
///Definition of the environment for this process.
|
||||
using ::boost::process::native_environment;
|
||||
#endif
|
||||
///Definition of the environment for this process.
|
||||
using ::boost::process::wnative_environment;
|
||||
|
||||
@@ -660,8 +665,10 @@ using ::boost::process::wnative_environment;
|
||||
inline int get_id() { return ::boost::process::detail::api::get_id();}
|
||||
///Get the native handle of the current process.
|
||||
inline native_handle_type native_handle() { return ::boost::process::detail::api::native_handle();}
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
///Get the enviroment of the current process.
|
||||
inline native_environment environment() { return ::boost::process:: native_environment(); }
|
||||
#endif
|
||||
///Get the enviroment of the current process.
|
||||
inline wnative_environment wenvironment() { return ::boost::process::wnative_environment(); }
|
||||
///Get the path environment variable of the current process runs.
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace boost {
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::windows::not_active">not_active</globalname>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::windows::show">show</globalname>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::windows::show_normal">show_normal</globalname>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::windows::create_no_window">create_no_window</globalname>;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,7 +35,7 @@ namespace boost {
|
||||
|
||||
namespace boost { namespace process {
|
||||
|
||||
///Namespace containing the windows exensions.
|
||||
///Namespace containing the windows extensions.
|
||||
namespace windows {
|
||||
|
||||
///Hides the window and activates another window.
|
||||
@@ -52,6 +53,8 @@ constexpr ::boost::process::detail::windows::show_window<::boost::winapi::SW_SHO
|
||||
///Activates and displays a window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when displaying the window for the first time.
|
||||
constexpr ::boost::process::detail::windows::show_window<::boost::winapi::SW_SHOWNORMAL_ > show_normal;
|
||||
|
||||
///Adds the [CREATE_NO_WINDOW](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx) flag.
|
||||
constexpr ::boost::process::detail::windows::create_no_window_ create_no_window;
|
||||
|
||||
}}}
|
||||
|
||||
|
||||
@@ -15,16 +15,17 @@ if [ os.name ] = NT
|
||||
{
|
||||
lib ws2_32 ;
|
||||
lib shell32 ;
|
||||
lib Advapi32 ;
|
||||
}
|
||||
|
||||
project : requirements
|
||||
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
|
||||
<toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
|
||||
<toolset>msvc:<cxxflags>/bigobj
|
||||
<target-os>windows:<define>WIN32_LEAN_AND_MEAN
|
||||
<target-os>linux:<linkflags>-lpthread
|
||||
<os>NT,<toolset>cw:<library>ws2_32
|
||||
<os>NT,<toolset>gcc:<library>ws2_32
|
||||
|
||||
;
|
||||
|
||||
|
||||
@@ -45,17 +46,26 @@ exe sparring_partner : sparring_partner.cpp program_options system filesystem io
|
||||
<warnings>off <target-os>windows:<source>shell32
|
||||
;
|
||||
|
||||
exe exit_argc : exit_argc.cpp :
|
||||
<warnings>off <target-os>windows:<source>shell32
|
||||
;
|
||||
|
||||
exe sub_launch : sub_launcher.cpp program_options iostreams system filesystem : <warnings>off <target-os>windows:<source>shell32 ;
|
||||
|
||||
test-suite bare :
|
||||
[ run environment.cpp system filesystem ]
|
||||
[ run async_pipe.cpp system filesystem ]
|
||||
[ run pipe.cpp system filesystem ]
|
||||
[ run environment.cpp system filesystem ]
|
||||
[ run async_pipe.cpp system filesystem ]
|
||||
[ run pipe.cpp system filesystem ]
|
||||
[ compile no_ansi_apps.cpp ]
|
||||
[ compile-fail spawn_fail.cpp ]
|
||||
[ compile-fail async_system_fail.cpp ]
|
||||
[ compile asio_no_deprecated.cpp ]
|
||||
;
|
||||
|
||||
test-suite with-valgrind :
|
||||
[ run async.cpp system thread filesystem : : sparring_partner ]
|
||||
[ run async_fut.cpp system thread filesystem : : sparring_partner ]
|
||||
[ run args_handling.cpp system thread filesystem : : exit_argc ]
|
||||
[ run args_cmd.cpp system filesystem : : sparring_partner ]
|
||||
[ run wargs_cmd.cpp system filesystem : : sparring_partner ]
|
||||
[ run bind_stderr.cpp filesystem : : sparring_partner ]
|
||||
@@ -89,17 +99,17 @@ test-suite with-valgrind :
|
||||
[ run on_exit.cpp system filesystem : : sparring_partner ]
|
||||
[ run on_exit2.cpp system filesystem : : sparring_partner ]
|
||||
[ run on_exit3.cpp system filesystem : : sparring_partner ]
|
||||
[ compile-fail spawn_fail.cpp ]
|
||||
[ compile-fail async_system_fail.cpp ]
|
||||
[ run posix_specific.cpp system filesystem : : sparring_partner : <build>no <target-os>linux:<build>yes ]
|
||||
[ run windows_specific.cpp filesystem system : : sparring_partner : <build>no <target-os>windows:<build>yes ]
|
||||
: <dependency>bare ;
|
||||
|
||||
test-suite without-valgrind :
|
||||
[ run async_system.cpp filesystem system coroutine : : sparring_partner : <link>static ]
|
||||
[ run async_system_future.cpp filesystem system coroutine : : sparring_partner : <link>static ]
|
||||
[ run async_system_stackless.cpp filesystem system coroutine : : sparring_partner : <link>static ]
|
||||
[ run vfork.cpp system filesystem : : sparring_partner : <build>no <target-os>linux:<build>yes ]
|
||||
[ run async_system_future.cpp filesystem system coroutine : : sparring_partner : <link>static <toolset>msvc:<cxxflags>/bigobj ]
|
||||
[ run async_system_stackful.cpp filesystem system coroutine : : sparring_partner : <link>static <toolset>msvc:<cxxflags>/bigobj ]
|
||||
[ run async_system_stackful_error.cpp filesystem system coroutine : : sparring_partner : <link>static <toolset>msvc:<cxxflags>/bigobj ]
|
||||
[ run async_system_stackful_except.cpp filesystem system coroutine : : sparring_partner : <link>static <toolset>msvc:<cxxflags>/bigobj ]
|
||||
[ run async_system_stackless.cpp filesystem system coroutine : : sparring_partner : <link>static <toolset>msvc:<cxxflags>/bigobj ]
|
||||
[ run vfork.cpp system filesystem : : sparring_partner : <build>no <target-os>linux:<build>yes ]
|
||||
;
|
||||
|
||||
|
||||
|
||||
79
test/args_handling.cpp
Normal file
79
test/args_handling.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2018 Oxford Nanopore Technologies
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_TEST_MAIN
|
||||
#define BOOST_TEST_IGNORE_SIGCHLD
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
|
||||
#include <system_error>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <boost/process/cmd.hpp>
|
||||
#include <boost/process/error.hpp>
|
||||
#include <boost/process/child.hpp>
|
||||
|
||||
namespace bp = boost::process;
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(implicit_args_fs_path)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
|
||||
boost::filesystem::path exe = master_test_suite().argv[1];
|
||||
|
||||
std::error_code ec;
|
||||
bp::child c(
|
||||
exe,
|
||||
ec
|
||||
);
|
||||
BOOST_REQUIRE(!ec);
|
||||
|
||||
c.wait(ec);
|
||||
BOOST_REQUIRE(!ec);
|
||||
|
||||
BOOST_CHECK(c.exit_code() == 1); // should pass at least exe!
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(implicit_args_cmd)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
|
||||
std::error_code ec;
|
||||
bp::child c(
|
||||
master_test_suite().argv[1],
|
||||
ec
|
||||
);
|
||||
BOOST_REQUIRE(!ec);
|
||||
|
||||
c.wait(ec);
|
||||
BOOST_REQUIRE(!ec);
|
||||
|
||||
BOOST_CHECK(c.exit_code() == 1); // should pass at least exe!
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(explicit_args_fs_path)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
|
||||
boost::filesystem::path exe = master_test_suite().argv[1];
|
||||
|
||||
std::error_code ec;
|
||||
bp::child c(
|
||||
exe,
|
||||
"hello",
|
||||
ec
|
||||
);
|
||||
BOOST_REQUIRE(!ec);
|
||||
|
||||
c.wait(ec);
|
||||
BOOST_REQUIRE(!ec);
|
||||
|
||||
BOOST_CHECK(c.exit_code() == 2); // exe + "hello"
|
||||
}
|
||||
13
test/asio_no_deprecated.cpp
Normal file
13
test/asio_no_deprecated.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// Created by kleme on 26.02.2018.
|
||||
//
|
||||
|
||||
#define BOOST_ASIO_NO_DEPRECATED 1
|
||||
#include <boost/process.hpp>
|
||||
int main() {}
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/posix.hpp>
|
||||
#elif
|
||||
#include <boost/process/windows.hpp>
|
||||
#endif
|
||||
163
test/async.cpp
163
test/async.cpp
@@ -35,12 +35,71 @@ BOOST_AUTO_TEST_CASE(async_wait, *boost::unit_test::timeout(2))
|
||||
|
||||
boost::asio::io_context io_context;
|
||||
|
||||
std::error_code ec;
|
||||
|
||||
bool exit_called_for_c1 = false;
|
||||
int exit_code_c1 = 0;
|
||||
bp::child c1(
|
||||
master_test_suite().argv[1],
|
||||
"test", "--exit-code", "123",
|
||||
ec,
|
||||
io_context,
|
||||
bp::on_exit([&](int exit, const std::error_code& ec_in)
|
||||
{
|
||||
BOOST_CHECK(!exit_called_for_c1);
|
||||
exit_code_c1 = exit; exit_called_for_c1=true;
|
||||
BOOST_CHECK(!ec_in);
|
||||
})
|
||||
);
|
||||
BOOST_REQUIRE(!ec);
|
||||
|
||||
bool exit_called_for_c2 = false;
|
||||
int exit_code_c2 = 0;
|
||||
bp::child c2(
|
||||
master_test_suite().argv[1],
|
||||
"test", "--exit-code", "21",
|
||||
ec,
|
||||
io_context,
|
||||
bp::on_exit([&](int exit, const std::error_code& ec_in)
|
||||
{
|
||||
BOOST_CHECK(!exit_called_for_c2);
|
||||
exit_code_c2 = exit; exit_called_for_c2=true;
|
||||
BOOST_CHECK(!ec_in);
|
||||
})
|
||||
);
|
||||
BOOST_REQUIRE(!ec);
|
||||
|
||||
io_context.run();
|
||||
|
||||
BOOST_CHECK(exit_called_for_c1);
|
||||
BOOST_CHECK_EQUAL(exit_code_c1, 123);
|
||||
BOOST_CHECK_EQUAL(c1.exit_code(), 123);
|
||||
|
||||
BOOST_CHECK(exit_called_for_c2);
|
||||
BOOST_CHECK_EQUAL(exit_code_c2, 21);
|
||||
BOOST_CHECK_EQUAL(c2.exit_code(), 21);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(async_wait_sync_wait, *boost::unit_test::timeout(3))
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
using namespace boost::asio;
|
||||
|
||||
boost::asio::io_context io_context;
|
||||
|
||||
bool exit_called = false;
|
||||
int exit_code = 0;
|
||||
std::error_code ec;
|
||||
bp::child c(
|
||||
bp::child c1(
|
||||
master_test_suite().argv[1],
|
||||
"test", "--exit-code", "123",
|
||||
"test", "--exit-code", "1",
|
||||
ec
|
||||
);
|
||||
BOOST_REQUIRE(!ec);
|
||||
|
||||
bp::child c2(
|
||||
master_test_suite().argv[1],
|
||||
"test", "--exit-code", "2", "--wait", "1",
|
||||
ec,
|
||||
io_context,
|
||||
bp::on_exit([&](int exit, const std::error_code& ec_in)
|
||||
@@ -49,12 +108,106 @@ BOOST_AUTO_TEST_CASE(async_wait, *boost::unit_test::timeout(2))
|
||||
BOOST_CHECK(!ec_in);
|
||||
})
|
||||
);
|
||||
|
||||
BOOST_REQUIRE(!ec);
|
||||
|
||||
io_context.run();
|
||||
// Regression test for #143: make sure the async SIGCHLD handler on POSIX does not reap the
|
||||
// child c1 is watching (this will error if so)
|
||||
c1.wait(ec);
|
||||
BOOST_REQUIRE(!ec);
|
||||
|
||||
BOOST_CHECK(exit_called);
|
||||
BOOST_CHECK_EQUAL(exit_code, 123);
|
||||
BOOST_CHECK_EQUAL(c.exit_code(), 123);
|
||||
BOOST_CHECK_EQUAL(exit_code, 2);
|
||||
BOOST_CHECK_EQUAL(c2.exit_code(), 2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(async_wait_different_contexts, *boost::unit_test::timeout(3))
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
using namespace boost::asio;
|
||||
|
||||
boost::asio::io_context io_context1;
|
||||
boost::asio::io_context io_context2;
|
||||
|
||||
std::error_code ec;
|
||||
|
||||
bool exit_called_for_c1 = false;
|
||||
int exit_code_c1 = 0;
|
||||
bp::child c1(
|
||||
master_test_suite().argv[1],
|
||||
"test", "--exit-code", "1",
|
||||
ec,
|
||||
io_context1,
|
||||
bp::on_exit([&](int exit, const std::error_code& ec_in)
|
||||
{
|
||||
BOOST_CHECK(!exit_called_for_c1);
|
||||
exit_code_c1 = exit; exit_called_for_c1=true;
|
||||
BOOST_CHECK(!ec_in);
|
||||
})
|
||||
);
|
||||
BOOST_REQUIRE(!ec);
|
||||
|
||||
bool exit_called_for_c2 = false;
|
||||
int exit_code_c2 = 0;
|
||||
bp::child c2(
|
||||
master_test_suite().argv[1],
|
||||
"test", "--exit-code", "2", "--wait", "1",
|
||||
ec,
|
||||
io_context2,
|
||||
bp::on_exit([&](int exit, const std::error_code& ec_in)
|
||||
{
|
||||
BOOST_CHECK(!exit_called_for_c2);
|
||||
exit_code_c2 = exit; exit_called_for_c2=true;
|
||||
BOOST_CHECK(!ec_in);
|
||||
})
|
||||
);
|
||||
BOOST_REQUIRE(!ec);
|
||||
|
||||
// Regression test for #143: make sure each io_context handles its own children
|
||||
io_context2.run();
|
||||
io_context1.run();
|
||||
c1.wait(ec);
|
||||
BOOST_REQUIRE(!ec);
|
||||
|
||||
BOOST_CHECK(exit_called_for_c1);
|
||||
BOOST_CHECK_EQUAL(exit_code_c1, 1);
|
||||
BOOST_CHECK_EQUAL(c1.exit_code(), 1);
|
||||
BOOST_CHECK(exit_called_for_c2);
|
||||
BOOST_CHECK_EQUAL(exit_code_c2, 2);
|
||||
BOOST_CHECK_EQUAL(c2.exit_code(), 2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(async_wait_abort, *boost::unit_test::timeout(2))
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
using namespace boost::asio;
|
||||
|
||||
boost::asio::io_context io_context;
|
||||
|
||||
std::error_code ec;
|
||||
|
||||
bool exit_called = false;
|
||||
int exit_code = 0;
|
||||
bp::child c(
|
||||
master_test_suite().argv[1],
|
||||
"test", "--abort",
|
||||
ec,
|
||||
io_context,
|
||||
bp::on_exit([&](int exit, const std::error_code& ec_in)
|
||||
{
|
||||
BOOST_CHECK(!exit_called);
|
||||
exit_code = exit; exit_called=true;
|
||||
BOOST_TEST_MESSAGE(ec_in.message());
|
||||
BOOST_CHECK(!ec_in);
|
||||
})
|
||||
);
|
||||
BOOST_REQUIRE(!ec);
|
||||
|
||||
io_context.run();
|
||||
|
||||
BOOST_CHECK(exit_called);
|
||||
BOOST_CHECK(exit_code != 0);
|
||||
BOOST_CHECK_EQUAL(c.exit_code(), exit_code);
|
||||
}
|
||||
|
||||
|
||||
|
||||
52
test/async_system_stackful.cpp
Normal file
52
test/async_system_stackful.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_TEST_MAIN
|
||||
#define BOOST_TEST_IGNORE_SIGCHLD
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
|
||||
#include <boost/process/error.hpp>
|
||||
#include <boost/process/io.hpp>
|
||||
#include <boost/process/async.hpp>
|
||||
#include <boost/process/child.hpp>
|
||||
#include <boost/process/async_system.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/spawn.hpp>
|
||||
#include <boost/asio/coroutine.hpp>
|
||||
#include <boost/asio/use_future.hpp>
|
||||
#include <boost/asio/yield.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
namespace bp = boost::process;
|
||||
BOOST_AUTO_TEST_CASE(stackful, *boost::unit_test::timeout(15))
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
|
||||
bool did_something_else = false;
|
||||
|
||||
boost::asio::io_context ios;
|
||||
auto stackful =
|
||||
[&](boost::asio::yield_context yield_)
|
||||
{
|
||||
int ret =
|
||||
bp::async_system(
|
||||
ios, yield_,
|
||||
master_test_suite().argv[1],
|
||||
"test", "--exit-code", "123");
|
||||
|
||||
BOOST_CHECK_EQUAL(ret, 123);
|
||||
BOOST_CHECK(did_something_else);
|
||||
};
|
||||
|
||||
boost::asio::spawn(ios, stackful);
|
||||
ios.post([&]{did_something_else = true;});
|
||||
|
||||
ios.run();
|
||||
BOOST_CHECK(did_something_else);
|
||||
}
|
||||
53
test/async_system_stackful_except.cpp
Normal file
53
test/async_system_stackful_except.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_TEST_MAIN
|
||||
#define BOOST_TEST_IGNORE_SIGCHLD
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
|
||||
#include <boost/process/error.hpp>
|
||||
#include <boost/process/io.hpp>
|
||||
#include <boost/process/async.hpp>
|
||||
#include <boost/process/child.hpp>
|
||||
#include <boost/process/async_system.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/spawn.hpp>
|
||||
#include <boost/asio/coroutine.hpp>
|
||||
#include <boost/asio/use_future.hpp>
|
||||
#include <boost/asio/yield.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
namespace bp = boost::process;
|
||||
BOOST_AUTO_TEST_CASE(stackful_except, *boost::unit_test::timeout(15))
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
|
||||
bool did_something_else = false;
|
||||
|
||||
boost::asio::io_context ios;
|
||||
auto stackful =
|
||||
[&](boost::asio::yield_context yield_)
|
||||
{
|
||||
|
||||
BOOST_CHECK_THROW(
|
||||
bp::async_system(
|
||||
ios, yield_,
|
||||
"none-existing-exe"), boost::system::system_error);
|
||||
|
||||
BOOST_CHECK(did_something_else);
|
||||
};
|
||||
|
||||
boost::asio::spawn(ios, stackful);
|
||||
ios.post([&]{did_something_else = true;});
|
||||
ios.run();
|
||||
|
||||
BOOST_CHECK(did_something_else);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include <array>
|
||||
|
||||
namespace bp = boost::process;
|
||||
|
||||
BOOST_AUTO_TEST_CASE(stackless, *boost::unit_test::timeout(15))
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
@@ -65,5 +64,3 @@ BOOST_AUTO_TEST_CASE(stackless, *boost::unit_test::timeout(15))
|
||||
|
||||
BOOST_CHECK(did_something_else);
|
||||
}
|
||||
|
||||
|
||||
|
||||
14
test/exit_argc.cpp
Normal file
14
test/exit_argc.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright (c) 2018 Oxford Nanopore Technologies
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
std::cout << argv[i] << '\n';
|
||||
}
|
||||
return argc;
|
||||
}
|
||||
@@ -48,6 +48,26 @@ BOOST_AUTO_TEST_CASE(sync_wait)
|
||||
c.wait();
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(sync_wait_abort)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
|
||||
std::error_code ec;
|
||||
bp::child c(
|
||||
master_test_suite().argv[1],
|
||||
"test", "--abort",
|
||||
ec
|
||||
);
|
||||
BOOST_REQUIRE(!ec);
|
||||
c.wait();
|
||||
int exit_code = c.exit_code();
|
||||
|
||||
|
||||
BOOST_CHECK(exit_code != 0);
|
||||
|
||||
c.wait();
|
||||
}
|
||||
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
struct wait_handler
|
||||
{
|
||||
|
||||
7
test/no_ansi_apps.cpp
Normal file
7
test/no_ansi_apps.cpp
Normal file
@@ -0,0 +1,7 @@
|
||||
// Copyright (c) 2018 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_NO_ANSI_APIS 1
|
||||
#include <boost/process.hpp>
|
||||
@@ -51,6 +51,7 @@ int main(int argc, char *argv[])
|
||||
("is-nul-stdout", bool_switch())
|
||||
("is-nul-stderr", bool_switch())
|
||||
("loop", bool_switch())
|
||||
("abort", bool_switch())
|
||||
("prefix", value<std::string>())
|
||||
("prefix-once", value<std::string>())
|
||||
("pwd", bool_switch())
|
||||
@@ -147,6 +148,10 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
while (true);
|
||||
}
|
||||
else if (vm["abort"].as<bool>())
|
||||
{
|
||||
std::abort();
|
||||
}
|
||||
else if (vm.count("prefix"))
|
||||
{
|
||||
std::string line;
|
||||
|
||||
Reference in New Issue
Block a user