mirror of
https://github.com/boostorg/process.git
synced 2026-01-20 16:52:14 +00:00
Compare commits
32 Commits
boost-1.71
...
boost-1.73
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0341e08297 | ||
|
|
5853345715 | ||
|
|
41f8b1cf00 | ||
|
|
56ae00c7a4 | ||
|
|
f58882c956 | ||
|
|
3f14ebc755 | ||
|
|
6a4d2ff721 | ||
|
|
6bf37ea8e8 | ||
|
|
ad38cdfada | ||
|
|
167ee79fa9 | ||
|
|
6b83d0b9dd | ||
|
|
16d16d40be | ||
|
|
f5f0866745 | ||
|
|
408cff1997 | ||
|
|
09faec4732 | ||
|
|
5ab43529b7 | ||
|
|
97f5b3c049 | ||
|
|
6dd3e0bdb4 | ||
|
|
eba5cb7be2 | ||
|
|
f4c51bcd5a | ||
|
|
410c0d592e | ||
|
|
40df7899b2 | ||
|
|
51083a8fa8 | ||
|
|
fe3cb0efc7 | ||
|
|
e0dd3b9658 | ||
|
|
d7d84f3952 | ||
|
|
6ccce9104a | ||
|
|
984c0c5b71 | ||
|
|
43523fcf8b | ||
|
|
cf7ad36438 | ||
|
|
ca994c1972 | ||
|
|
1b6ccb6d39 |
@@ -85,7 +85,7 @@ before_install:
|
||||
- git checkout $BOOST_BRANCH
|
||||
- git submodule update --init --merge
|
||||
- git remote set-branches --add origin $BOOST_BRANCH
|
||||
- git pull --recurse-submodules
|
||||
- git pull --recurse-submodules || true
|
||||
- git submodule update --init
|
||||
- git checkout $BOOST_BRANCH
|
||||
- git submodule foreach "git reset --quiet --hard; git clean -fxd"
|
||||
@@ -131,6 +131,7 @@ after_success:
|
||||
- coveralls-lcov coverals/coverage.info
|
||||
|
||||
after_script:
|
||||
- curl -s https://report.ci/upload.py | python - --name="$BADGE test run"
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
- cd $BOOST/libs/$PROJECT_TO_TEST/test
|
||||
- curl -s https://report.ci/upload.py | python - --name="$BADGE test run" --root_dir $BOOST
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ Though please note, that if the the same thread reads and write to a pipe, it wi
|
||||
|
||||
[section:anonymous Anonymous Pipes]
|
||||
|
||||
The usual type of pipes, are the anonymous ones. Since the have no name,
|
||||
The most common pipes are anonymous. Since the have no name,
|
||||
a handle to them can only be obtained from duplicating either handle.
|
||||
|
||||
In this library the following functions are used for the creation of unnamed pipes:
|
||||
|
||||
@@ -47,6 +47,8 @@ public:
|
||||
*/
|
||||
typedef platform_specific handle_type;
|
||||
|
||||
typedef typename handle_type::executor_type executor_type;
|
||||
|
||||
/** Construct a new async_pipe, does automatically open the pipe.
|
||||
* Initializes source and sink with the same io_context.
|
||||
* @note Windows creates a named pipe here, where the name is automatically generated.
|
||||
|
||||
@@ -145,8 +145,11 @@ struct async_out_future : ::boost::process::detail::posix::handler_base_ext,
|
||||
{
|
||||
std::istream is (buffer_.get());
|
||||
Type arg;
|
||||
arg.resize(buffer_->size());
|
||||
is.read(&*arg.begin(), buffer_->size());
|
||||
if (buffer_->size() > 0)
|
||||
{
|
||||
arg.resize(buffer_->size());
|
||||
is.read(&*arg.begin(), buffer_->size());
|
||||
}
|
||||
promise_->set_value(std::move(arg));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -23,6 +23,7 @@ class async_pipe
|
||||
public:
|
||||
typedef int native_handle_type;
|
||||
typedef ::boost::asio::posix::stream_descriptor handle_type;
|
||||
typedef typename handle_type::executor_type executor_type;
|
||||
|
||||
inline async_pipe(boost::asio::io_context & ios) : async_pipe(ios, ios) {}
|
||||
|
||||
|
||||
@@ -82,18 +82,26 @@ public:
|
||||
|
||||
int_type write(const char_type * data, int_type count)
|
||||
{
|
||||
auto write_len = ::write(_sink, data, count * sizeof(char_type));
|
||||
if (write_len == -1)
|
||||
::boost::process::detail::throw_last_error();
|
||||
|
||||
int_type write_len;
|
||||
while ((write_len = ::write(_sink, data, count * sizeof(char_type))) == -1)
|
||||
{
|
||||
//Try again if interrupted
|
||||
auto err = errno;
|
||||
if (err != EINTR)
|
||||
::boost::process::detail::throw_last_error();
|
||||
}
|
||||
return write_len;
|
||||
}
|
||||
int_type read(char_type * data, int_type count)
|
||||
{
|
||||
auto read_len = ::read(_source, data, count * sizeof(char_type));
|
||||
if (read_len == -1)
|
||||
::boost::process::detail::throw_last_error();
|
||||
|
||||
int_type read_len;
|
||||
while ((read_len = ::read(_source, data, count * sizeof(char_type))) == -1)
|
||||
{
|
||||
//Try again if interrupted
|
||||
auto err = errno;
|
||||
if (err != EINTR)
|
||||
::boost::process::detail::throw_last_error();
|
||||
}
|
||||
return read_len;
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ public:
|
||||
native_environment_impl & operator=(native_environment_impl && ) = default;
|
||||
native_handle_type _env_impl = _impl.data();
|
||||
|
||||
native_handle_type native_handle() const {return environ;}
|
||||
native_handle_type native_handle() const {return _env_impl;}
|
||||
};
|
||||
|
||||
template<>
|
||||
@@ -294,7 +294,11 @@ std::vector<Char*> basic_environment_impl<Char>::_load_var(std::vector<std::basi
|
||||
ret.reserve(data.size() +1);
|
||||
|
||||
for (auto & val : data)
|
||||
{
|
||||
if (val.empty())
|
||||
val.push_back(0);
|
||||
ret.push_back(&val.front());
|
||||
}
|
||||
|
||||
ret.push_back(nullptr);
|
||||
return ret;
|
||||
|
||||
@@ -64,79 +64,9 @@ inline bool wait_until(
|
||||
bool timed_out = false;
|
||||
int ret;
|
||||
|
||||
#if defined(BOOST_POSIX_HAS_SIGTIMEDWAIT)
|
||||
auto get_timespec =
|
||||
+[](const Duration & dur)
|
||||
{
|
||||
::timespec ts;
|
||||
ts.tv_sec = std::chrono::duration_cast<std::chrono::seconds>(dur).count();
|
||||
ts.tv_nsec = std::chrono::duration_cast<std::chrono::nanoseconds>(dur).count() % 1000000000;
|
||||
return ts;
|
||||
};
|
||||
|
||||
::sigset_t sigset;
|
||||
|
||||
if (sigemptyset(&sigset) != 0)
|
||||
{
|
||||
ec = get_last_error();
|
||||
return false;
|
||||
}
|
||||
if (sigaddset(&sigset, SIGCHLD) != 0)
|
||||
{
|
||||
ec = get_last_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ::sigaction old_sig;
|
||||
if (-1 == ::sigaction(SIGCHLD, nullptr, &old_sig))
|
||||
{
|
||||
ec = get_last_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
auto ts = get_timespec(time_out - Clock::now());
|
||||
ret = ::sigtimedwait(&sigset, nullptr, &ts);
|
||||
errno = 0;
|
||||
if ((ret == SIGCHLD) && (old_sig.sa_handler != SIG_DFL) && (old_sig.sa_handler != SIG_IGN))
|
||||
old_sig.sa_handler(ret);
|
||||
|
||||
ret = ::waitpid(-p.grp, &siginfo.si_status, 0); //so in case it exited, we wanna reap it first
|
||||
if (ret == -1)
|
||||
{
|
||||
if ((errno == ECHILD) || (errno == ESRCH))
|
||||
{
|
||||
ec.clear();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ec = get_last_error();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//check if we're done ->
|
||||
ret = ::waitid(P_PGID, p.grp, &siginfo, WEXITED | WNOHANG);
|
||||
}
|
||||
while (((ret != -1) || ((errno != ECHILD) && (errno != ESRCH))) && !(timed_out = (Clock::now() > time_out)));
|
||||
|
||||
if (errno != ECHILD)
|
||||
{
|
||||
ec = boost::process::detail::get_last_error();
|
||||
return !timed_out;
|
||||
}
|
||||
else
|
||||
{
|
||||
ec.clear();
|
||||
return true; //even if timed out, there are no child proccessess left
|
||||
}
|
||||
|
||||
#else
|
||||
::timespec sleep_interval;
|
||||
sleep_interval.tv_sec = 0;
|
||||
sleep_interval.tv_nsec = 1000000;
|
||||
sleep_interval.tv_nsec = 100000000;
|
||||
|
||||
|
||||
while (!(timed_out = (Clock::now() > time_out)))
|
||||
@@ -156,7 +86,6 @@ inline bool wait_until(
|
||||
::nanosleep(&sleep_interval, nullptr);
|
||||
}
|
||||
return !timed_out;
|
||||
#endif
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
|
||||
@@ -48,6 +48,7 @@ class async_pipe
|
||||
public:
|
||||
typedef ::boost::winapi::HANDLE_ native_handle_type;
|
||||
typedef ::boost::asio::windows::stream_handle handle_type;
|
||||
typedef typename handle_type::executor_type executor_type;
|
||||
|
||||
async_pipe(boost::asio::io_context & ios) : async_pipe(ios, ios, make_pipe_name(), true) {}
|
||||
async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink)
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <boost/winapi/file_management.hpp>
|
||||
#include <string>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/core/exchange.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
@@ -90,10 +91,18 @@ struct file_descriptor
|
||||
|
||||
}
|
||||
file_descriptor(const file_descriptor & ) = delete;
|
||||
file_descriptor(file_descriptor && ) = default;
|
||||
file_descriptor(file_descriptor &&other)
|
||||
: _handle( boost::exchange(other._handle, ::boost::winapi::INVALID_HANDLE_VALUE_) )
|
||||
{
|
||||
}
|
||||
|
||||
file_descriptor& operator=(const file_descriptor & ) = delete;
|
||||
file_descriptor& operator=(file_descriptor && ) = default;
|
||||
file_descriptor& operator=(file_descriptor &&other)
|
||||
{
|
||||
if (_handle != ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::winapi::CloseHandle(_handle);
|
||||
_handle = boost::exchange(other._handle, ::boost::winapi::INVALID_HANDLE_VALUE_);
|
||||
}
|
||||
|
||||
~file_descriptor()
|
||||
{
|
||||
|
||||
@@ -34,12 +34,12 @@ inline std::vector<native_handle_type> get_handles(std::error_code & ec)
|
||||
|
||||
::boost::winapi::NTSTATUS_ nt_status = STATUS_INFO_LENGTH_MISMATCH_;
|
||||
|
||||
for (int cnt = 0;
|
||||
for (;
|
||||
nt_status == STATUS_INFO_LENGTH_MISMATCH_;
|
||||
nt_status = workaround::nt_system_query_information(
|
||||
workaround::SystemHandleInformation_,
|
||||
info_pointer, buffer.size(),
|
||||
NULL))
|
||||
info_pointer, static_cast<::boost::winapi::ULONG_>(buffer.size()),
|
||||
nullptr))
|
||||
{
|
||||
buffer.resize(buffer.size() * 2);
|
||||
info_pointer = reinterpret_cast<workaround::SYSTEM_HANDLE_INFORMATION_*>(buffer.data());
|
||||
|
||||
@@ -60,14 +60,14 @@ inline boost::filesystem::path search_path(
|
||||
auto p = pp_ / filename;
|
||||
for (boost::filesystem::path ext : extensions)
|
||||
{
|
||||
boost::filesystem::path pp = p;
|
||||
pp += ext;
|
||||
boost::filesystem::path pp_ext = p;
|
||||
pp_ext += ext;
|
||||
boost::system::error_code ec;
|
||||
bool file = boost::filesystem::is_regular_file(pp, ec);
|
||||
bool file = boost::filesystem::is_regular_file(pp_ext, ec);
|
||||
if (!ec && file &&
|
||||
::boost::winapi::sh_get_file_info(pp.native().c_str(), 0, 0, 0, ::boost::winapi::SHGFI_EXETYPE_))
|
||||
::boost::winapi::sh_get_file_info(pp_ext.native().c_str(), 0, 0, 0, ::boost::winapi::SHGFI_EXETYPE_))
|
||||
{
|
||||
return pp;
|
||||
return pp_ext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ struct const_entry
|
||||
bool operator()(char c) const {return c == api::env_seperator<char> ();}
|
||||
} s;
|
||||
boost::split(data, _data, s);
|
||||
return std::move(data);
|
||||
return data;
|
||||
}
|
||||
string_type to_string() const
|
||||
{
|
||||
|
||||
@@ -340,8 +340,9 @@ public:
|
||||
basic_ipstream& operator=(basic_ipstream && lhs)
|
||||
{
|
||||
std::basic_istream<CharT, Traits>::operator=(std::move(lhs));
|
||||
_buf = std::move(lhs);
|
||||
_buf = std::move(lhs._buf);
|
||||
std::basic_istream<CharT, Traits>::rdbuf(&_buf);
|
||||
return *this;
|
||||
};
|
||||
///Move assignment of a pipe.
|
||||
basic_ipstream& operator=(pipe_type && p)
|
||||
@@ -366,7 +367,7 @@ public:
|
||||
///Get a rvalue reference to the pipe. Qualified as rvalue.
|
||||
pipe_type && pipe() && {return std::move(_buf).pipe();}
|
||||
///Check if the pipe is open
|
||||
bool is_open() const {return _buf->is_open();}
|
||||
bool is_open() const {return _buf.is_open();}
|
||||
|
||||
///Open a new pipe
|
||||
void open()
|
||||
@@ -448,8 +449,9 @@ public:
|
||||
basic_opstream& operator=(basic_opstream && lhs)
|
||||
{
|
||||
std::basic_ostream<CharT, Traits>::operator=(std::move(lhs));
|
||||
_buf = std::move(lhs);
|
||||
_buf = std::move(lhs._buf);
|
||||
std::basic_ostream<CharT, Traits>::rdbuf(&_buf);
|
||||
return *this;
|
||||
};
|
||||
|
||||
///Move assignment of a pipe.
|
||||
@@ -556,8 +558,9 @@ public:
|
||||
basic_pstream& operator=(basic_pstream && lhs)
|
||||
{
|
||||
std::basic_istream<CharT, Traits>::operator=(std::move(lhs));
|
||||
_buf = std::move(lhs);
|
||||
_buf = std::move(lhs._buf);
|
||||
std::basic_iostream<CharT, Traits>::rdbuf(&_buf);
|
||||
return *this;
|
||||
};
|
||||
///Move assignment of a pipe.
|
||||
basic_pstream& operator=(pipe_type && p)
|
||||
|
||||
@@ -73,5 +73,5 @@ after_test:
|
||||
on_success:
|
||||
on_failure:
|
||||
on_finish:
|
||||
- curl -s https://report.ci/upload.py | python - --name "Windows test run" --root_dir=%BOOST%/libs/%PROJECT_TO_TEST% --framework boost
|
||||
- curl -s https://report.ci/upload.py | python - --name "Windows test run" --root_dir=%BOOST%
|
||||
|
||||
|
||||
@@ -96,8 +96,13 @@ BOOST_AUTO_TEST_CASE(move_pipe)
|
||||
bp::async_pipe ap{ios};
|
||||
BOOST_TEST_CHECKPOINT("First move");
|
||||
bp::async_pipe ap2{std::move(ap)};
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
BOOST_CHECK_EQUAL(ap.native_source(), ::boost::winapi::INVALID_HANDLE_VALUE_);
|
||||
BOOST_CHECK_EQUAL(ap.native_sink (), ::boost::winapi::INVALID_HANDLE_VALUE_);
|
||||
#elif defined(BOOST_POSIX_API)
|
||||
BOOST_CHECK_EQUAL(ap.native_source(), -1);
|
||||
BOOST_CHECK_EQUAL(ap.native_sink (), -1);
|
||||
#endif
|
||||
|
||||
BOOST_TEST_CHECKPOINT("Second move");
|
||||
ap = std::move(ap2);
|
||||
|
||||
@@ -118,6 +118,29 @@ BOOST_AUTO_TEST_CASE(compare, *boost::unit_test::timeout(5))
|
||||
BOOST_TEST_PASSPOINT();
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(wcompare, *boost::unit_test::timeout(5))
|
||||
{
|
||||
auto nat = boost::this_process::wenvironment();
|
||||
bp::wenvironment env = nat;
|
||||
|
||||
{
|
||||
BOOST_CHECK_EQUAL(nat.size(), env.size());
|
||||
auto ni = nat.begin();
|
||||
auto ei = env.begin();
|
||||
|
||||
while ((ni != nat.end()) &&(ei != env.end()))
|
||||
{
|
||||
BOOST_CHECK_EQUAL(ni->get_name(), ei->get_name());
|
||||
BOOST_CHECK_EQUAL(ni->to_string(), ei->to_string());
|
||||
ni++; ei++;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_TEST_PASSPOINT();
|
||||
env.clear();
|
||||
BOOST_TEST_PASSPOINT();
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(insert_remove, *boost::unit_test::timeout(5))
|
||||
{
|
||||
bp::environment env(boost::this_process::environment());
|
||||
|
||||
106
test/pipe.cpp
106
test/pipe.cpp
@@ -102,6 +102,110 @@ BOOST_AUTO_TEST_CASE(stream, *boost::unit_test::timeout(2))
|
||||
BOOST_CHECK_EQUAL(i, j);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(stream_move, *boost::unit_test::timeout(2))
|
||||
{
|
||||
|
||||
bp::pipe pipe;
|
||||
|
||||
bp::pstream os(pipe);
|
||||
bp::ipstream is(pipe);
|
||||
|
||||
int i = 42, j = 0, k = 0;
|
||||
|
||||
os << i << std::endl;
|
||||
os << std::endl;
|
||||
is >> j;
|
||||
|
||||
BOOST_CHECK_EQUAL(i, j);
|
||||
|
||||
bp::pstream os2 = std::move(os);
|
||||
bp::ipstream is2 = std::move(is);
|
||||
os2 << i << std::endl;
|
||||
os2 << std::endl;
|
||||
is2 >> k;
|
||||
|
||||
BOOST_CHECK_EQUAL(i, k);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ostream_move, *boost::unit_test::timeout(2))
|
||||
{
|
||||
|
||||
bp::pipe pipe;
|
||||
|
||||
bp::opstream os(pipe);
|
||||
bp::ipstream is(pipe);
|
||||
|
||||
int i = 42, j = 0, k = 0;
|
||||
|
||||
os << i << std::endl;
|
||||
os << std::endl;
|
||||
is >> j;
|
||||
|
||||
BOOST_CHECK_EQUAL(i, j);
|
||||
|
||||
bp::opstream os2 = std::move(os);
|
||||
bp::ipstream is2 = std::move(is);
|
||||
os2 << i << std::endl;
|
||||
os2 << std::endl;
|
||||
is2 >> k;
|
||||
|
||||
BOOST_CHECK_EQUAL(i, k);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(stream_move_assignment, *boost::unit_test::timeout(2))
|
||||
{
|
||||
|
||||
bp::pipe pipe;
|
||||
|
||||
bp::pstream os(pipe);
|
||||
bp::ipstream is(pipe);
|
||||
|
||||
int i = 42, j = 0, k = 0;
|
||||
|
||||
os << i << std::endl;
|
||||
os << std::endl;
|
||||
is >> j;
|
||||
|
||||
BOOST_CHECK_EQUAL(i, j);
|
||||
|
||||
bp::pstream os2;
|
||||
os2 = std::move(os);
|
||||
bp::ipstream is2;
|
||||
is2 = std::move(is);
|
||||
os2 << i << std::endl;
|
||||
os2 << std::endl;
|
||||
is2 >> k;
|
||||
|
||||
BOOST_CHECK_EQUAL(i, k);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ostream_move_assignment, *boost::unit_test::timeout(2))
|
||||
{
|
||||
|
||||
bp::pipe pipe;
|
||||
|
||||
bp::opstream os(pipe);
|
||||
bp::ipstream is(pipe);
|
||||
|
||||
int i = 42, j = 0, k = 0;
|
||||
|
||||
os << i << std::endl;
|
||||
os << std::endl;
|
||||
is >> j;
|
||||
|
||||
BOOST_CHECK_EQUAL(i, j);
|
||||
|
||||
bp::opstream os2;
|
||||
os2 = std::move(os);
|
||||
bp::ipstream is2;
|
||||
is2 = std::move(is);
|
||||
os2 << i << std::endl;
|
||||
os2 << std::endl;
|
||||
is2 >> k;
|
||||
|
||||
BOOST_CHECK_EQUAL(i, k);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(stream_line, *boost::unit_test::timeout(2))
|
||||
{
|
||||
|
||||
@@ -268,4 +372,4 @@ BOOST_AUTO_TEST_CASE(stream_close_scope, *boost::unit_test::timeout(5))
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END();
|
||||
BOOST_AUTO_TEST_SUITE_END();
|
||||
|
||||
Reference in New Issue
Block a user