mirror of
https://github.com/boostorg/process.git
synced 2026-01-20 16:52:14 +00:00
Compare commits
2 Commits
boost-1.72
...
sfinae_dyn
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83c2a986cb | ||
|
|
41fff78e00 |
@@ -70,6 +70,7 @@ jobs:
|
||||
|
||||
python <(curl -s https://report.ci/annotate.py) --tool gcc --input test.log
|
||||
python <(curl -s https://report.ci/annotate.py) --tool gcc --input no-valgrind.log
|
||||
bash <(curl -s https://codecov.io/bash) -x gcov > /dev/null || true
|
||||
python <(curl -s https://report.ci/upload.py) --name "Circle CI Gcc Tests" --framework boost
|
||||
bash <(curl -s https://codecov.io/bash) -x gcov || true
|
||||
echo "BUILD_RESULT: $FAILED"
|
||||
exit $FAILED
|
||||
|
||||
10
.travis.yml
10
.travis.yml
@@ -23,6 +23,8 @@ os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
secure: "vs7qgXb0lQg8CTyDPSi3RQtOIOtssaCkBIx86UoEvTXwJCTOLPe7ZufQ0lobn0OVWo261AMx9GbumBBzqfsvJc1G6ixGBVwymiGli/R8DZDvvg9UdljsEk65s/XbujE/9qh97zKGGioFyCn1Bmf5+SdDAxsuXTZm/cBny5VxYaaCR7s2cFUmp4up/djqg1GI7uwBh3ceodT3OL1X3dlMV59gOJWWNsB+RO9b9DPhTW7nOlMNRiEFik4rweecQB0JS8LaHDjYwzIRrGYHX+lR9cE/O8GCCHcUOmq9jCozDdxx+HZRu4rb1ST1RiDbvYaoeTif0Df1fVXHWOoO2D4NlXB6tJPXw2mkop00j6zkcydUJYid6T1lwfEpXAhd5A9FvOIXO5hoju1wlqfkU2eFQ9Na8z8bCIX2niZmveZWp4Ag52gEPzJMFx9hHGT8J4FWMvkqTWezux1sPZrjZjc0kXdJrIp84D9MsBc1sKrxOAOb5ekSfIK5n4JDkgUtuwMSTvEdWqNJXFPZq1rEu4GTwX99z3/XF+pM5XaCDQtZ/zUA5SPHhy0dKLH/BvceUqLJt53+lMcpsltJDB+XxQ/CFL7IdgR91OKGus/z4dbVWiSdkoNvcuZqjQLFLOMVNxoqC6PRvDAEhpy21j/5GUPvM5baQS7IEin0NF7bOTtXJdY="
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- BADGE=linux
|
||||
@@ -71,7 +73,7 @@ before_install:
|
||||
# Set this to the name of the library
|
||||
- PROJECT_TO_TEST=`basename $TRAVIS_BUILD_DIR`
|
||||
- echo "Testing $PROJECT_TO_TEST"
|
||||
- if [ $TRAVIS_OS_NAME = "osx" ]; then brew install gcc5; brew install valgrind; brew install llvm; TOOLSET=clang; BOOST_TEST_CATCH_SYSTEM_ERRORS=no; MULTITHREAD=-j8; else TOOLSET=gcc-5; REPORT_CI=--boost-process-report-ci USE_VALGRIND="testing.launcher=valgrind valgrind=on"; fi
|
||||
- if [ $TRAVIS_OS_NAME = "osx" ]; then brew install gcc5; brew install valgrind; brew install llvm; TOOLSET=clang; BOOST_TEST_CATCH_SYSTEM_ERRORS=no; MULTITHREAD=-j8; else TOOLSET=gcc-5; USE_VALGRIND="testing.launcher=valgrind valgrind=on"; fi
|
||||
# Cloning Boost libraries (fast nondeep cloning)
|
||||
- BOOST=$HOME/boost-local
|
||||
- git init $BOOST
|
||||
@@ -101,8 +103,8 @@ before_install:
|
||||
- echo BOOST_TEST_CATCH_SYSTEM_ERRORS $BOOST_TEST_CATCH_SYSTEM_ERRORS
|
||||
script:
|
||||
# `--coverage` flags required to generate coverage info for Coveralls
|
||||
- ../../../b2 $MULTITHREAD with-valgrind address-model=64 architecture=x86 $USE_VALGRIND toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=. $REPORT_CI
|
||||
- ../../../b2 $MULTITHREAD without-valgrind address-model=64 architecture=x86 toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=. $REPORT_CI
|
||||
- ../../../b2 $MULTITHREAD with-valgrind address-model=64 architecture=x86 $USE_VALGRIND toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=.
|
||||
- ../../../b2 $MULTITHREAD without-valgrind address-model=64 architecture=x86 toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=.
|
||||
after_success:
|
||||
# Copying Coveralls data to a separate folder
|
||||
- mkdir -p $TRAVIS_BUILD_DIR/coverals
|
||||
@@ -131,6 +133,6 @@ after_success:
|
||||
- coveralls-lcov coverals/coverage.info
|
||||
|
||||
after_script:
|
||||
- curl -s https://report.ci/upload.py | python - --name="$BADGE test run"
|
||||
- curl -s https://report.ci/upload.py | python - --token=$REPORT_CI_TOKEN --name="$BADGE test run"
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ In that it is different than other facilities (like sockets) and provides anothe
|
||||
Pipes are typically used for interprocess communication. The main reason is, that pipes can be directly assigned to the process stdio, i.e. stderr, stdin and stdout.
|
||||
Additionally, half of the pipe can be inherited to the child process and closed in the father process. This will cause the pipe to be broken when the child process exits.
|
||||
|
||||
Though please note, that if the the same thread reads and write to a pipe, it will only talk to itself.
|
||||
Though please not, that if the the same thread reads and write to a pipe, it will only talk to itself.
|
||||
|
||||
[section:anonymous Anonymous Pipes]
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
[def asio_async_read [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/async_read.html boost::asio::async_read]]
|
||||
[def bp::environment [classref boost::process::basic_environment bp::environment]]
|
||||
[def bp::native_environment [classref boost::process::basic_native_environment bp::native_environment]]
|
||||
[def boost::this_process::environment [funcref boost::this_process::environment boost::this_process:deadlock :environment]]
|
||||
[def boost::this_process::environment [funcref boost::this_process::environment boost::this_process::environment]]
|
||||
[def std::chrono::seconds [@http://en.cppreference.com/w/cpp/chrono/duration std::chrono::seconds]]
|
||||
[def std::vector [@http://en.cppreference.com/w/cpp/container/vector std::vector]]
|
||||
|
||||
@@ -217,7 +217,8 @@ std::vector<std::string> read_outline(std::string & file)
|
||||
What this does is redirect the `stdout` of the process into a pipe and we read this
|
||||
synchronously.
|
||||
|
||||
[note You can do the same thing with [globalref boost::process::std_err std_err]]
|
||||
[warning The pipe will cause a deadlock if you try to read after nm exited]
|
||||
[note You can do the same thing with [globalref boost::process::std_err std_err]]
|
||||
|
||||
Now we get the name from `nm` and we might want to demangle it, so we use input and output.
|
||||
`nm` has a demangle option, but for the sake of the example, we'll use
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <boost/process/error.hpp>
|
||||
#include <boost/process/exe.hpp>
|
||||
#include <boost/process/group.hpp>
|
||||
#include <boost/process/handles.hpp>
|
||||
#include <boost/process/io.hpp>
|
||||
#include <boost/process/pipe.hpp>
|
||||
#include <boost/process/shell.hpp>
|
||||
|
||||
@@ -10,11 +10,13 @@
|
||||
|
||||
namespace boost { namespace asio {
|
||||
|
||||
class mutable_buffer;
|
||||
class mutable_buffers_1;
|
||||
template<typename T>
|
||||
struct is_mutable_buffer_sequence;
|
||||
|
||||
template<typename T>
|
||||
struct is_const_buffer_sequence;
|
||||
|
||||
|
||||
class const_buffer;
|
||||
class const_buffers_1;
|
||||
|
||||
template<typename Allocator>
|
||||
class basic_streambuf;
|
||||
|
||||
@@ -16,16 +16,13 @@
|
||||
#include <boost/process/async_pipe.hpp>
|
||||
#include <memory>
|
||||
#include <future>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
template<typename Buffer>
|
||||
struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
::boost::process::detail::posix::require_io_context,
|
||||
::boost::process::detail::uses_handles
|
||||
::boost::process::detail::posix::require_io_context
|
||||
{
|
||||
Buffer & buf;
|
||||
|
||||
@@ -36,7 +33,6 @@ struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
fut = promise->get_future(); return std::move(*this);
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<boost::process::async_pipe> pipe;
|
||||
|
||||
async_in_buffer(Buffer & buf) : buf(buf)
|
||||
@@ -80,19 +76,9 @@ struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
template<typename Executor>
|
||||
void on_setup(Executor & exec)
|
||||
{
|
||||
if (!pipe)
|
||||
pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq));
|
||||
pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq));
|
||||
}
|
||||
|
||||
std::array<int, 3> get_used_handles()
|
||||
{
|
||||
if (pipe)
|
||||
return {STDIN_FILENO, pipe->native_source(), pipe->native_sink()};
|
||||
else //if pipe is not constructed, limit_ds is invoked before -> this also means on_exec_setup gets invoked before.
|
||||
return {STDIN_FILENO, STDIN_FILENO, STDIN_FILENO};
|
||||
}
|
||||
|
||||
|
||||
template <typename Executor>
|
||||
void on_exec_setup(Executor &exec)
|
||||
{
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
#include <memory>
|
||||
#include <exception>
|
||||
#include <future>
|
||||
#include <array>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
@@ -47,24 +45,12 @@ inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::in
|
||||
|
||||
template<int p1, int p2, typename Buffer>
|
||||
struct async_out_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
::boost::process::detail::posix::require_io_context,
|
||||
::boost::process::detail::uses_handles
|
||||
::boost::process::detail::posix::require_io_context
|
||||
{
|
||||
Buffer & buf;
|
||||
|
||||
std::shared_ptr<boost::process::async_pipe> pipe;
|
||||
|
||||
std::array<int, 4> get_used_handles()
|
||||
{
|
||||
const auto pp1 = p1 != -1 ? p1 : p2;
|
||||
const auto pp2 = p2 != -1 ? p2 : p1;
|
||||
|
||||
if (pipe)
|
||||
return {pipe->native_source(), pipe->native_sink(), pp1, pp2};
|
||||
else //if pipe is not constructed, limit_ds is invoked before -> this also means on_exec_setup gets invoked before.
|
||||
return {pp1, pp2, pp1, pp2};
|
||||
}
|
||||
|
||||
|
||||
async_out_buffer(Buffer & buf) : buf(buf)
|
||||
{
|
||||
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
return read_len;
|
||||
}
|
||||
|
||||
bool is_open() const
|
||||
bool is_open()
|
||||
{
|
||||
return (_source != -1) ||
|
||||
(_sink != -1);
|
||||
|
||||
@@ -12,11 +12,10 @@
|
||||
|
||||
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
struct close_in : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
struct close_in : handler_base_ext
|
||||
{
|
||||
template <class Executor>
|
||||
void on_exec_setup(Executor &e) const
|
||||
@@ -24,9 +23,6 @@ struct close_in : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
if (::close(STDIN_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
|
||||
}
|
||||
|
||||
int get_used_handles() {return STDIN_FILENO;}
|
||||
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
@@ -10,9 +10,8 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_CLOSE_OUT_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_CLOSE_OUT_HPP
|
||||
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
@@ -21,8 +20,6 @@ struct close_out : handler_base_ext
|
||||
{
|
||||
template <class Executor>
|
||||
inline void on_exec_setup(Executor &e) const;
|
||||
|
||||
std::array<int, 2> get_used_handles() {return {p1 != -1 ? p1 : p2, p2 != -1 ? p2 : p1};}
|
||||
};
|
||||
|
||||
template<>
|
||||
|
||||
@@ -420,7 +420,7 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
|
||||
_msg = "execve failed";
|
||||
boost::fusion::for_each(seq, call_on_exec_error(*this, _ec));
|
||||
|
||||
_write_error(_pipe_sink);
|
||||
_write_error(p.p[1]);
|
||||
::close(p.p[1]);
|
||||
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
@@ -12,13 +12,11 @@
|
||||
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <unistd.h>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
struct close_fd_ : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
struct close_fd_ : handler_base_ext
|
||||
{
|
||||
close_fd_(int fd) : fd_(fd) {}
|
||||
|
||||
@@ -29,15 +27,12 @@ struct close_fd_ : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
|
||||
}
|
||||
|
||||
int get_used_handles() {return fd_;}
|
||||
|
||||
|
||||
private:
|
||||
int fd_;
|
||||
};
|
||||
|
||||
template <class Range>
|
||||
struct close_fds_ : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
struct close_fds_ : handler_base_ext
|
||||
{
|
||||
public:
|
||||
close_fds_(const Range &fds) : fds_(fds) {}
|
||||
@@ -53,8 +48,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
Range& get_used_handles() {return fds_;}
|
||||
|
||||
private:
|
||||
Range fds_;
|
||||
};
|
||||
@@ -62,7 +55,7 @@ private:
|
||||
|
||||
|
||||
template <class FileDescriptor>
|
||||
struct bind_fd_ : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
struct bind_fd_ : handler_base_ext
|
||||
{
|
||||
public:
|
||||
bind_fd_(int id, const FileDescriptor &fd) : id_(id), fd_(fd) {}
|
||||
@@ -74,9 +67,6 @@ public:
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
}
|
||||
|
||||
std::array<int, 2> get_used_handles() {return {id_, fd_};}
|
||||
|
||||
|
||||
private:
|
||||
int id_;
|
||||
FileDescriptor fd_;
|
||||
|
||||
@@ -13,22 +13,16 @@
|
||||
#include <boost/process/pipe.hpp>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/posix/file_descriptor.hpp>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <cstdio>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
struct file_in : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
struct file_in : handler_base_ext
|
||||
{
|
||||
file_descriptor file;
|
||||
int handle = file.handle();
|
||||
|
||||
std::array<int, 2> get_used_handles()
|
||||
{
|
||||
return {STDIN_FILENO, handle};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
file_in(T&& t) : file(std::forward<T>(t)) {}
|
||||
file_in(FILE * f) : handle(fileno(f)) {}
|
||||
|
||||
@@ -13,13 +13,12 @@
|
||||
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/posix/file_descriptor.hpp>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <unistd.h>
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
template<int p1, int p2>
|
||||
struct file_out : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
struct file_out : handler_base_ext
|
||||
{
|
||||
file_descriptor file;
|
||||
int handle = file.handle();
|
||||
@@ -28,13 +27,6 @@ struct file_out : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
file_out(T&& t) : file(std::forward<T>(t), file_descriptor::write), handle(file.handle()) {}
|
||||
file_out(FILE * f) : handle(fileno(f)) {}
|
||||
|
||||
std::array<int, 3> get_used_handles()
|
||||
{
|
||||
const auto pp1 = p1 != -1 ? p1 : p2;
|
||||
const auto pp2 = p2 != -1 ? p2 : p1;
|
||||
|
||||
return {handle, pp1, pp2};
|
||||
}
|
||||
|
||||
template <typename Executor>
|
||||
void on_exec_setup(Executor &e) const;
|
||||
|
||||
@@ -1,146 +0,0 @@
|
||||
// Copyright (c) 2019 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)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_HANDLES_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_HANDLES_HPP_
|
||||
|
||||
#include <vector>
|
||||
#include <system_error>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <algorithm>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
using native_handle_type = int;
|
||||
|
||||
inline std::vector<native_handle_type> get_handles(std::error_code & ec)
|
||||
{
|
||||
std::vector<native_handle_type> res;
|
||||
|
||||
std::unique_ptr<DIR, void(*)(DIR*)> dir{::opendir("/dev/fd"), +[](DIR* p){::closedir(p);}};
|
||||
if (!dir)
|
||||
{
|
||||
ec = ::boost::process::detail::get_last_error();
|
||||
return {};
|
||||
}
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
auto my_fd = ::dirfd(dir.get());
|
||||
|
||||
struct ::dirent * ent_p;
|
||||
|
||||
while ((ent_p = readdir(dir.get())) != nullptr)
|
||||
{
|
||||
if (ent_p->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
const auto conv = std::atoi(ent_p->d_name);
|
||||
if (conv == 0 && (ent_p->d_name[0] != '0' && ent_p->d_name[1] != '\0'))
|
||||
continue;
|
||||
|
||||
if (conv == my_fd)
|
||||
continue;
|
||||
|
||||
res.push_back(conv);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
inline std::vector<native_handle_type> get_handles()
|
||||
{
|
||||
std::error_code ec;
|
||||
|
||||
auto res = get_handles(ec);
|
||||
if (ec)
|
||||
boost::process::detail::throw_error(ec, "open_dir(\"/dev/fd\") failed");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
inline bool is_stream_handle(native_handle_type handle, std::error_code & ec)
|
||||
{
|
||||
struct ::stat stat_;
|
||||
|
||||
if (::fstat(handle, &stat_) != 0)
|
||||
{
|
||||
ec = ::boost::process::detail::get_last_error();
|
||||
}
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
return S_ISCHR (stat_.st_mode) //This macro returns non-zero if the file is a character special file (a device like a terminal).
|
||||
|| S_ISBLK (stat_.st_mode) // This macro returns non-zero if the file is a block special file (a device like a disk).
|
||||
|| S_ISREG (stat_.st_mode) // This macro returns non-zero if the file is a regular file.
|
||||
|| S_ISFIFO (stat_.st_mode) // This macro returns non-zero if the file is a FIFO special file, or a pipe. See section 15. Pipes and FIFOs.
|
||||
|| S_ISSOCK (stat_.st_mode) ;// This macro returns non-zero if the file is a socket. See section 16. Sockets.;
|
||||
}
|
||||
|
||||
|
||||
inline bool is_stream_handle(native_handle_type handle)
|
||||
{
|
||||
std::error_code ec;
|
||||
auto res = is_stream_handle(handle, ec);
|
||||
if (ec)
|
||||
boost::process::detail::throw_error(ec, "fstat() failed");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
struct limit_handles_ : handler_base_ext
|
||||
{
|
||||
limit_handles_() {}
|
||||
~limit_handles_() {}
|
||||
mutable std::vector<int> used_handles;
|
||||
|
||||
template<typename Executor>
|
||||
void on_setup(Executor & exec) const
|
||||
{
|
||||
used_handles = get_used_handles(exec);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_exec_setup(Executor & exec) const
|
||||
{
|
||||
auto dir = ::opendir("/dev/fd");
|
||||
if (!dir)
|
||||
{
|
||||
exec.set_error(::boost::process::detail::get_last_error(), "opendir(\"/dev/fd\")");
|
||||
return;
|
||||
}
|
||||
|
||||
auto my_fd = ::dirfd(dir);
|
||||
struct ::dirent * ent_p;
|
||||
|
||||
while ((ent_p = readdir(dir)) != nullptr)
|
||||
{
|
||||
if (ent_p->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
const auto conv = std::atoi(ent_p->d_name);
|
||||
|
||||
if ((conv == my_fd) || (conv == -1))
|
||||
continue;
|
||||
|
||||
if (std::find(used_handles.begin(), used_handles.end(), conv) != used_handles.end())
|
||||
continue;
|
||||
|
||||
if (::close(conv) != 0)
|
||||
{
|
||||
exec.set_error(::boost::process::detail::get_last_error(), "close() failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
::closedir(dir);
|
||||
}
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
#endif //PROCESS_HANDLES_HPP
|
||||
@@ -14,21 +14,13 @@
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/posix/file_descriptor.hpp>
|
||||
#include <unistd.h>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
struct null_in : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
struct null_in : handler_base_ext
|
||||
{
|
||||
file_descriptor source{"/dev/null", file_descriptor::read};
|
||||
|
||||
std::array<int, 2> get_used_handles()
|
||||
{
|
||||
return {STDIN_FILENO, source.handle()};
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
template <class Executor>
|
||||
void on_exec_setup(Executor &e) const
|
||||
|
||||
@@ -13,27 +13,17 @@
|
||||
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/posix/file_descriptor.hpp>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <unistd.h>
|
||||
#include <array>
|
||||
|
||||
#include <unistd.h>
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
template<int p1, int p2>
|
||||
struct null_out : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
struct null_out : handler_base_ext
|
||||
{
|
||||
file_descriptor sink{"/dev/null", file_descriptor::write};
|
||||
|
||||
template <typename Executor>
|
||||
void on_exec_setup(Executor &e) const;
|
||||
|
||||
std::array<int, 3> get_used_handles()
|
||||
{
|
||||
const auto pp1 = p1 != -1 ? p1 : p2;
|
||||
const auto pp2 = p2 != -1 ? p2 : p1;
|
||||
|
||||
return {sink.handle(), pp1, pp2};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
|
||||
@@ -13,23 +13,17 @@
|
||||
#include <boost/process/pipe.hpp>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <unistd.h>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <array>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
struct pipe_in : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
struct pipe_in : handler_base_ext
|
||||
{
|
||||
int source;
|
||||
int sink; //opposite end
|
||||
|
||||
pipe_in(int sink, int source) : source(source), sink(sink) {}
|
||||
|
||||
std::array<int, 3> get_used_handles()
|
||||
{
|
||||
return {STDIN_FILENO, source, sink};
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
pipe_in(T & p) : source(p.native_source()), sink(p.native_sink())
|
||||
@@ -54,9 +48,7 @@ struct pipe_in : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
{
|
||||
if (::dup2(source, STDIN_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
if (source != STDIN_FILENO)
|
||||
::close(source);
|
||||
|
||||
::close(source);
|
||||
::close(sink);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,10 +52,8 @@ template<typename Executor>
|
||||
void pipe_out<1,-1>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(sink, STDOUT_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
if (sink != STDOUT_FILENO)
|
||||
::close(sink);
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup3() failed");
|
||||
::close(sink);
|
||||
::close(source);
|
||||
}
|
||||
|
||||
@@ -65,9 +63,7 @@ void pipe_out<2,-1>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(sink, STDERR_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
if (sink != STDOUT_FILENO)
|
||||
::close(sink);
|
||||
::close(sink);
|
||||
::close(source);
|
||||
}
|
||||
|
||||
@@ -79,8 +75,8 @@ void pipe_out<1,2>::on_exec_setup(Executor &e) const
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
if (::dup2(sink, STDERR_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
if ((sink != STDOUT_FILENO) && (sink != STDERR_FILENO))
|
||||
::close(sink);
|
||||
::close(sink);
|
||||
::close(source);
|
||||
}
|
||||
|
||||
class async_pipe;
|
||||
|
||||
@@ -27,7 +27,7 @@ inline void terminate(const child_handle &p, std::error_code &ec) noexcept
|
||||
ec.clear();
|
||||
|
||||
int status;
|
||||
::waitpid(p.pid, &status, WNOHANG); //just to clean it up
|
||||
::waitpid(p.pid, &status, 0); //just to clean it up
|
||||
}
|
||||
|
||||
inline void terminate(const child_handle &p)
|
||||
|
||||
@@ -54,35 +54,11 @@ inline bool wait_until(
|
||||
const std::chrono::time_point<Clock, Duration>& time_out,
|
||||
std::error_code & ec) noexcept
|
||||
{
|
||||
|
||||
::sigset_t sigset;
|
||||
|
||||
//I need to set the signal, because it might be ignore / default, in which case sigwait might not work.
|
||||
|
||||
using _signal_t = void(*)(int);
|
||||
static thread_local _signal_t sigchld_handler = SIG_DFL;
|
||||
|
||||
struct signal_interceptor_t
|
||||
{
|
||||
static void handler_func(int val)
|
||||
{
|
||||
if ((sigchld_handler != SIG_DFL) && (sigchld_handler != SIG_IGN))
|
||||
sigchld_handler(val);
|
||||
}
|
||||
signal_interceptor_t() { sigchld_handler = ::signal(SIGCHLD, &handler_func); }
|
||||
~signal_interceptor_t() { ::signal(SIGCHLD, sigchld_handler); sigchld_handler = SIG_DFL;}
|
||||
|
||||
} signal_interceptor{};
|
||||
|
||||
if (sigemptyset(&sigset) != 0)
|
||||
{
|
||||
ec = get_last_error();
|
||||
return false;
|
||||
}
|
||||
if (sigaddset(&sigset, SIGCHLD) != 0)
|
||||
{
|
||||
ec = get_last_error();
|
||||
return false;
|
||||
}
|
||||
sigemptyset(&sigset);
|
||||
sigaddset(&sigset, SIGCHLD);
|
||||
|
||||
auto get_timespec =
|
||||
[](const Duration & dur)
|
||||
@@ -93,8 +69,8 @@ inline bool wait_until(
|
||||
return ts;
|
||||
};
|
||||
|
||||
int ret;
|
||||
int status{0};
|
||||
pid_t ret;
|
||||
int status;
|
||||
|
||||
struct ::sigaction old_sig;
|
||||
if (-1 == ::sigaction(SIGCHLD, nullptr, &old_sig))
|
||||
@@ -104,7 +80,6 @@ inline bool wait_until(
|
||||
}
|
||||
|
||||
bool timed_out;
|
||||
|
||||
#if defined(BOOST_POSIX_HAS_SIGTIMEDWAIT)
|
||||
do
|
||||
{
|
||||
@@ -138,16 +113,9 @@ inline bool wait_until(
|
||||
{
|
||||
auto ts = get_timespec(time_out - Clock::now());
|
||||
::timespec rem;
|
||||
while (ts.tv_sec > 0 || ts.tv_nsec > 0)
|
||||
{
|
||||
if (::nanosleep(&ts, &rem) != 0)
|
||||
{
|
||||
auto err = errno;
|
||||
if ((err == EINVAL) || (err == EFAULT))
|
||||
break;
|
||||
}
|
||||
ts = get_timespec(time_out - Clock::now());
|
||||
}
|
||||
::nanosleep(&ts, &rem);
|
||||
while (rem.tv_sec > 0 || rem.tv_nsec > 0)
|
||||
::nanosleep(&rem, &rem);
|
||||
::exit(0);
|
||||
}
|
||||
|
||||
@@ -157,7 +125,7 @@ inline bool wait_until(
|
||||
~child_cleaner_t()
|
||||
{
|
||||
int res;
|
||||
::kill(pid, SIGKILL);
|
||||
::kill(pid, -15);
|
||||
::waitpid(pid, &res, WNOHANG);
|
||||
}
|
||||
};
|
||||
@@ -165,21 +133,19 @@ inline bool wait_until(
|
||||
|
||||
do
|
||||
{
|
||||
int sig_{0};
|
||||
int ret_sig = 0;
|
||||
if ((::waitpid(timeout_pid, &status, WNOHANG) != 0)
|
||||
&& (WIFEXITED(status) || WIFSIGNALED(status)))
|
||||
|
||||
return false;
|
||||
|
||||
ret = ::sigwait(&sigset, &sig_);
|
||||
&& (WIFEXITED(status) || WIFSIGNALED(status)))
|
||||
ret_sig = ::sigwait(&sigset, nullptr);
|
||||
errno = 0;
|
||||
|
||||
if ((sig_ == SIGCHLD) &&
|
||||
ret = ::waitpid(p.pid, &status, WNOHANG);
|
||||
|
||||
if ((ret_sig == SIGCHLD) &&
|
||||
(old_sig.sa_handler != SIG_DFL) && (old_sig.sa_handler != SIG_IGN))
|
||||
old_sig.sa_handler(ret);
|
||||
|
||||
ret = ::waitpid(p.pid, &status, WNOHANG);
|
||||
if (ret == 0) // == > is running
|
||||
if (ret <= 0)
|
||||
{
|
||||
timed_out = Clock::now() >= time_out;
|
||||
if (timed_out)
|
||||
|
||||
@@ -59,14 +59,15 @@ inline bool wait_until(
|
||||
std::error_code & ec) noexcept
|
||||
{
|
||||
|
||||
::sigset_t sigset;
|
||||
::siginfo_t siginfo;
|
||||
|
||||
bool timed_out = false;
|
||||
int ret;
|
||||
sigemptyset(&sigset);
|
||||
sigaddset(&sigset, SIGCHLD);
|
||||
|
||||
#if defined(BOOST_POSIX_HAS_SIGTIMEDWAIT)
|
||||
auto get_timespec =
|
||||
+[](const Duration & dur)
|
||||
|
||||
auto get_timespec =
|
||||
[](const Duration & dur)
|
||||
{
|
||||
::timespec ts;
|
||||
ts.tv_sec = std::chrono::duration_cast<std::chrono::seconds>(dur).count();
|
||||
@@ -74,18 +75,9 @@ inline bool wait_until(
|
||||
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;
|
||||
}
|
||||
bool timed_out = false;
|
||||
int ret;
|
||||
|
||||
struct ::sigaction old_sig;
|
||||
if (-1 == ::sigaction(SIGCHLD, nullptr, &old_sig))
|
||||
@@ -94,6 +86,7 @@ inline bool wait_until(
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(BOOST_POSIX_HAS_SIGTIMEDWAIT)
|
||||
do
|
||||
{
|
||||
auto ts = get_timespec(time_out - Clock::now());
|
||||
@@ -105,22 +98,67 @@ inline bool wait_until(
|
||||
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;
|
||||
}
|
||||
ec = get_last_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
//check if we're done ->
|
||||
//check if we're done
|
||||
ret = ::waitid(P_PGID, p.grp, &siginfo, WEXITED | WNOHANG);
|
||||
|
||||
}
|
||||
while (((ret != -1) || (errno != ECHILD)) && !(timed_out = (Clock::now() > time_out)));
|
||||
#else
|
||||
//if we do not have sigtimedwait, we fork off a child process to get the signal in time
|
||||
pid_t timeout_pid = ::fork();
|
||||
if (timeout_pid == -1)
|
||||
{
|
||||
ec = boost::process::detail::get_last_error();
|
||||
return true;
|
||||
}
|
||||
while (((ret != -1) || ((errno != ECHILD) && (errno != ESRCH))) && !(timed_out = (Clock::now() > time_out)));
|
||||
else if (timeout_pid == 0)
|
||||
{
|
||||
auto ts = get_timespec(time_out - Clock::now());
|
||||
::setpgid(0, p.grp);
|
||||
::nanosleep(&ts, nullptr);
|
||||
::exit(0);
|
||||
}
|
||||
|
||||
struct child_cleaner_t
|
||||
{
|
||||
pid_t pid;
|
||||
~child_cleaner_t()
|
||||
{
|
||||
int res;
|
||||
::kill(pid, -15);
|
||||
::waitpid(pid, &res, WNOHANG);
|
||||
}
|
||||
};
|
||||
child_cleaner_t child_cleaner{timeout_pid};
|
||||
|
||||
do
|
||||
{
|
||||
int status;
|
||||
if ((::waitpid(timeout_pid, &status, WNOHANG) != 0)
|
||||
&& (WIFEXITED(status) || WIFSIGNALED(status)))
|
||||
ret = ::sigwait(&sigset, nullptr);
|
||||
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)
|
||||
{
|
||||
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)) && !(timed_out = (Clock::now() > time_out)));
|
||||
|
||||
#endif
|
||||
|
||||
if (errno != ECHILD)
|
||||
{
|
||||
@@ -133,30 +171,6 @@ inline bool wait_until(
|
||||
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;
|
||||
|
||||
|
||||
while (!(timed_out = (Clock::now() > time_out)))
|
||||
{
|
||||
ret = ::waitid(P_PGID, p.grp, &siginfo, WEXITED | WSTOPPED | WNOHANG);
|
||||
if (ret == -1)
|
||||
{
|
||||
if ((errno == ECHILD) || (errno == ESRCH))
|
||||
{
|
||||
ec.clear();
|
||||
return true;
|
||||
}
|
||||
ec = boost::process::detail::get_last_error();
|
||||
return false;
|
||||
}
|
||||
//we can wait, because unlike in the wait_for_exit, we have no race condition regarding eh exit code.
|
||||
::nanosleep(&sleep_interval, nullptr);
|
||||
}
|
||||
return !timed_out;
|
||||
#endif
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_USED_HANDLES_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_USED_HANDLES_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
#include <boost/fusion/include/filter_if.hpp>
|
||||
#include <boost/fusion/include/for_each.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/handles.hpp>
|
||||
#include <boost/process/detail/posix/asio_fwd.hpp>
|
||||
#else
|
||||
#include <boost/process/detail/windows/handles.hpp>
|
||||
#include <boost/process/detail/windows/asio_fwd.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
struct uses_handles
|
||||
{
|
||||
//If you get an error here, you must add a `get_handles` function that returns a range or a single handle value
|
||||
void get_used_handles() const;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct does_use_handle: std::is_base_of<uses_handles, T> {};
|
||||
|
||||
template<typename T>
|
||||
struct does_use_handle<T&> : std::is_base_of<uses_handles, T> {};
|
||||
|
||||
template<typename T>
|
||||
struct does_use_handle<const T&> : std::is_base_of<uses_handles, T> {};
|
||||
|
||||
template<typename Char, typename Sequence>
|
||||
class executor;
|
||||
|
||||
template<typename Func>
|
||||
struct foreach_handle_invocator
|
||||
{
|
||||
Func & func;
|
||||
foreach_handle_invocator(Func & func) : func(func) {}
|
||||
|
||||
|
||||
template<typename Range>
|
||||
void invoke(const Range & range) const
|
||||
{
|
||||
for (auto handle_ : range)
|
||||
func(handle_);
|
||||
|
||||
}
|
||||
void invoke(::boost::process::detail::api::native_handle_type handle) const {func(handle);};
|
||||
|
||||
template<typename T>
|
||||
void operator()(T & val) const {invoke(val.get_used_handles());}
|
||||
};
|
||||
|
||||
template<typename Executor, typename Function>
|
||||
void foreach_used_handle(Executor &exec, Function &&func)
|
||||
{
|
||||
boost::fusion::for_each(boost::fusion::filter_if<does_use_handle<boost::mpl::_>>(exec.seq),
|
||||
foreach_handle_invocator<Function>(func));
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
std::vector<::boost::process::detail::api::native_handle_type>
|
||||
get_used_handles(Executor &exec)
|
||||
{
|
||||
std::vector<::boost::process::detail::api::native_handle_type> res;
|
||||
foreach_used_handle(exec, [&](::boost::process::detail::api::native_handle_type handle){res.push_back(handle);});
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_USED_HANDLES_HPP_ */
|
||||
@@ -10,10 +10,12 @@
|
||||
|
||||
namespace boost { namespace asio {
|
||||
|
||||
class mutable_buffer;
|
||||
class mutable_buffers_1;
|
||||
class const_buffer;
|
||||
class const_buffers_1;
|
||||
template<typename T>
|
||||
struct is_mutable_buffer_sequence;
|
||||
|
||||
template<typename T>
|
||||
struct is_const_buffer_sequence;
|
||||
|
||||
|
||||
template<typename Allocator>
|
||||
class basic_streambuf;
|
||||
|
||||
@@ -17,20 +17,19 @@
|
||||
|
||||
#include <boost/asio/write.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <boost/process/detail/windows/async_handler.hpp>
|
||||
#include <boost/process/detail/windows/asio_fwd.hpp>
|
||||
#include <boost/process/async_pipe.hpp>
|
||||
#include <memory>
|
||||
#include <future>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
|
||||
template<typename Buffer>
|
||||
struct async_in_buffer : ::boost::process::detail::windows::handler_base_ext,
|
||||
::boost::process::detail::windows::require_io_context,
|
||||
::boost::process::detail::uses_handles
|
||||
::boost::process::detail::windows::require_io_context
|
||||
{
|
||||
Buffer & buf;
|
||||
|
||||
@@ -43,11 +42,6 @@ struct async_in_buffer : ::boost::process::detail::windows::handler_base_ext,
|
||||
|
||||
std::shared_ptr<boost::process::async_pipe> pipe;
|
||||
|
||||
::boost::winapi::HANDLE_ get_used_handles() const
|
||||
{
|
||||
return std::move(*pipe).source().native_handle();
|
||||
}
|
||||
|
||||
async_in_buffer(Buffer & buf) : buf(buf)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <boost/winapi/error_codes.hpp>
|
||||
#include <boost/asio/read.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <boost/process/detail/windows/asio_fwd.hpp>
|
||||
|
||||
#include <istream>
|
||||
@@ -109,18 +108,12 @@ struct async_out_buffer : ::boost::process::detail::windows::handler_base_ext,
|
||||
|
||||
template<int p1, int p2, typename Type>
|
||||
struct async_out_future : ::boost::process::detail::windows::handler_base_ext,
|
||||
::boost::process::detail::windows::require_io_context,
|
||||
::boost::process::detail::uses_handles
|
||||
::boost::process::detail::windows::require_io_context
|
||||
{
|
||||
std::shared_ptr<boost::process::async_pipe> pipe;
|
||||
std::shared_ptr<std::promise<Type>> promise = std::make_shared<std::promise<Type>>();
|
||||
std::shared_ptr<boost::asio::streambuf> buffer = std::make_shared<boost::asio::streambuf>();
|
||||
|
||||
::boost::winapi::HANDLE_ get_used_handles() const
|
||||
{
|
||||
return std::move(*pipe).sink().native_handle();
|
||||
}
|
||||
|
||||
|
||||
async_out_future(std::future<Type> & fut)
|
||||
{
|
||||
|
||||
@@ -40,26 +40,17 @@ class async_pipe
|
||||
{
|
||||
::boost::asio::windows::stream_handle _source;
|
||||
::boost::asio::windows::stream_handle _sink ;
|
||||
|
||||
inline async_pipe(boost::asio::io_context & ios_source,
|
||||
boost::asio::io_context & ios_sink,
|
||||
const std::string & name, bool private_);
|
||||
|
||||
public:
|
||||
typedef ::boost::winapi::HANDLE_ native_handle_type;
|
||||
typedef ::boost::asio::windows::stream_handle handle_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)
|
||||
: async_pipe(ios_source, ios_sink, make_pipe_name(), true) {}
|
||||
|
||||
async_pipe(boost::asio::io_context & ios, const std::string & name)
|
||||
: async_pipe(ios, ios, name, false) {}
|
||||
|
||||
async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink, const std::string & name)
|
||||
: async_pipe(ios_source, ios_sink, name, false) {}
|
||||
|
||||
inline async_pipe(boost::asio::io_context & ios,
|
||||
const std::string & name = make_pipe_name())
|
||||
: async_pipe(ios, ios, name) {}
|
||||
|
||||
inline async_pipe(boost::asio::io_context & ios_source,
|
||||
boost::asio::io_context & ios_sink,
|
||||
const std::string & name = make_pipe_name());
|
||||
|
||||
inline async_pipe(const async_pipe& rhs);
|
||||
async_pipe(async_pipe&& rhs) : _source(std::move(rhs._source)), _sink(std::move(rhs._sink))
|
||||
@@ -283,7 +274,7 @@ async_pipe::async_pipe(const async_pipe& p) :
|
||||
|
||||
async_pipe::async_pipe(boost::asio::io_context & ios_source,
|
||||
boost::asio::io_context & ios_sink,
|
||||
const std::string & name, bool private_) : _source(ios_source), _sink(ios_sink)
|
||||
const std::string & name) : _source(ios_source), _sink(ios_sink)
|
||||
{
|
||||
static constexpr int FILE_FLAG_OVERLAPPED_ = 0x40000000; //temporary
|
||||
|
||||
@@ -295,7 +286,7 @@ async_pipe::async_pipe(boost::asio::io_context & ios_source,
|
||||
#endif
|
||||
::boost::winapi::PIPE_ACCESS_INBOUND_
|
||||
| FILE_FLAG_OVERLAPPED_, //write flag
|
||||
0, private_ ? 1 : ::boost::winapi::PIPE_UNLIMITED_INSTANCES_, 8192, 8192, 0, nullptr);
|
||||
0, 1, 8192, 8192, 0, nullptr);
|
||||
|
||||
|
||||
if (source == boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
|
||||
@@ -98,7 +98,7 @@ public:
|
||||
return static_cast<int_type>(read_len);
|
||||
}
|
||||
|
||||
bool is_open() const
|
||||
bool is_open()
|
||||
{
|
||||
return (_source != ::boost::winapi::INVALID_HANDLE_VALUE_) ||
|
||||
(_sink != ::boost::winapi::INVALID_HANDLE_VALUE_);
|
||||
@@ -152,7 +152,7 @@ basic_pipe<Char, Traits>::basic_pipe(const std::string & name)
|
||||
name_.c_str(),
|
||||
::boost::winapi::PIPE_ACCESS_INBOUND_
|
||||
| FILE_FLAG_OVERLAPPED_, //write flag
|
||||
0, ::boost::winapi::PIPE_UNLIMITED_INSTANCES_, 8192, 8192, 0, nullptr);
|
||||
0, 1, 8192, 8192, 0, nullptr);
|
||||
|
||||
if (source == boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::process::detail::throw_last_error("create_named_pipe() failed");
|
||||
|
||||
@@ -13,20 +13,16 @@
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <boost/process/detail/windows/file_descriptor.hpp>
|
||||
#include <io.h>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
struct file_in : public ::boost::process::detail::handler_base,
|
||||
::boost::process::detail::uses_handles
|
||||
struct file_in : public ::boost::process::detail::handler_base
|
||||
{
|
||||
file_descriptor file;
|
||||
::boost::winapi::HANDLE_ handle = file.handle();
|
||||
|
||||
::boost::winapi::HANDLE_ get_used_handles() const { return handle; }
|
||||
|
||||
template<typename T>
|
||||
file_in(T&& t) : file(std::forward<T>(t), file_descriptor::read) {}
|
||||
file_in(FILE * f) : handle(reinterpret_cast<::boost::winapi::HANDLE_>(_get_osfhandle(_fileno(f)))) {}
|
||||
|
||||
@@ -14,21 +14,16 @@
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/winapi/handle_info.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <boost/process/detail/windows/file_descriptor.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
template<int p1, int p2>
|
||||
struct file_out : public ::boost::process::detail::handler_base,
|
||||
::boost::process::detail::uses_handles
|
||||
struct file_out : public ::boost::process::detail::handler_base
|
||||
{
|
||||
file_descriptor file;
|
||||
::boost::winapi::HANDLE_ handle = file.handle();
|
||||
|
||||
::boost::winapi::HANDLE_ get_used_handles() const { return handle; }
|
||||
|
||||
|
||||
template<typename T>
|
||||
file_out(T&& t) : file(std::forward<T>(t), file_descriptor::write) {}
|
||||
file_out(FILE * f) : handle(reinterpret_cast<void*>(_get_osfhandle(_fileno(f)))) {}
|
||||
|
||||
@@ -6,10 +6,9 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_GROUP_REF_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_GROUP_REF_HPP_
|
||||
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/windows/group_handle.hpp>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/process/detail/windows/handler.hpp>
|
||||
|
||||
namespace boost { namespace process {
|
||||
@@ -18,12 +17,10 @@ namespace detail { namespace windows {
|
||||
|
||||
|
||||
|
||||
struct group_ref : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
struct group_ref : handler_base_ext
|
||||
{
|
||||
::boost::winapi::HANDLE_ handle;
|
||||
|
||||
::boost::winapi::HANDLE_ get_used_handles() const { return handle; }
|
||||
|
||||
explicit group_ref(group_handle &g) :
|
||||
handle(g.handle())
|
||||
{}
|
||||
|
||||
@@ -1,262 +0,0 @@
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_HANDLE_WORKAROUND_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_HANDLE_WORKAROUND_HPP_
|
||||
|
||||
#include <boost/winapi/basic_types.hpp>
|
||||
#include <boost/winapi/dll.hpp>
|
||||
#include <boost/winapi/access_rights.hpp>
|
||||
//#define BOOST_USE_WINDOWS_H 1
|
||||
|
||||
#if defined( BOOST_USE_WINDOWS_H )
|
||||
#include <Winternl.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows { namespace workaround
|
||||
{
|
||||
|
||||
|
||||
typedef struct _SYSTEM_HANDLE_ENTRY_
|
||||
{
|
||||
::boost::winapi::ULONG_ OwnerPid;
|
||||
::boost::winapi::BYTE_ ObjectType;
|
||||
::boost::winapi::BYTE_ HandleFlags;
|
||||
::boost::winapi::USHORT_ HandleValue;
|
||||
::boost::winapi::PVOID_ ObjectPointer;
|
||||
::boost::winapi::ULONG_ AccessMask;
|
||||
} SYSTEM_HANDLE_ENTRY_, *PSYSTEM_HANDLE_ENTRY_;
|
||||
|
||||
typedef struct _SYSTEM_HANDLE_INFORMATION_
|
||||
{
|
||||
::boost::winapi::ULONG_ Count;
|
||||
SYSTEM_HANDLE_ENTRY_ Handle[1];
|
||||
} SYSTEM_HANDLE_INFORMATION_, *PSYSTEM_HANDLE_INFORMATION_;
|
||||
|
||||
#if defined( BOOST_USE_WINDOWS_H )
|
||||
|
||||
using UNICODE_STRING_ = ::UNICODE_STRING;
|
||||
using GENERIC_MAPPING_ = ::GENERIC_MAPPING;
|
||||
using OBJECT_INFORMATION_CLASS_ = ::OBJECT_INFORMATION_CLASS;
|
||||
|
||||
constexpr static OBJECT_INFORMATION_CLASS_ ObjectTypeInformation = ::OBJECT_INFORMATION_CLASS::ObjectTypeInformation;
|
||||
|
||||
typedef struct _OBJECT_TYPE_INFORMATION_ {
|
||||
UNICODE_STRING TypeName;
|
||||
ULONG TotalNumberOfObjects;
|
||||
ULONG TotalNumberOfHandles;
|
||||
ULONG TotalPagedPoolUsage;
|
||||
ULONG TotalNonPagedPoolUsage;
|
||||
ULONG TotalNamePoolUsage;
|
||||
ULONG TotalHandleTableUsage;
|
||||
ULONG HighWaterNumberOfObjects;
|
||||
ULONG HighWaterNumberOfHandles;
|
||||
ULONG HighWaterPagedPoolUsage;
|
||||
ULONG HighWaterNonPagedPoolUsage;
|
||||
ULONG HighWaterNamePoolUsage;
|
||||
ULONG HighWaterHandleTableUsage;
|
||||
ULONG InvalidAttributes;
|
||||
GENERIC_MAPPING GenericMapping;
|
||||
ULONG ValidAccessMask;
|
||||
BOOLEAN SecurityRequired;
|
||||
BOOLEAN MaintainHandleCount;
|
||||
UCHAR TypeIndex;
|
||||
CHAR ReservedByte;
|
||||
ULONG PoolType;
|
||||
ULONG DefaultPagedPoolCharge;
|
||||
ULONG DefaultNonPagedPoolCharge;
|
||||
} OBJECT_TYPE_INFORMATION_, *POBJECT_TYPE_INFORMATION_;
|
||||
|
||||
#else
|
||||
|
||||
typedef enum _OBJECT_INFORMATION_CLASS_
|
||||
{
|
||||
ObjectBasicInformation,
|
||||
ObjectNameInformation,
|
||||
ObjectTypeInformation,
|
||||
ObjectAllInformation,
|
||||
ObjectDataInformation
|
||||
} OBJECT_INFORMATION_CLASS_, *POBJECT_INFORMATION_CLASS_;
|
||||
|
||||
typedef struct _UNICODE_STRING_ {
|
||||
::boost::winapi::USHORT_ Length;
|
||||
::boost::winapi::USHORT_ MaximumLength;
|
||||
::boost::winapi::LPWSTR_ Buffer;
|
||||
} UNICODE_STRING_, *PUNICODE_STRING_;
|
||||
|
||||
typedef struct _GENERIC_MAPPING_ {
|
||||
::boost::winapi::ACCESS_MASK_ GenericRead;
|
||||
::boost::winapi::ACCESS_MASK_ GenericWrite;
|
||||
::boost::winapi::ACCESS_MASK_ GenericExecute;
|
||||
::boost::winapi::ACCESS_MASK_ GenericAll;
|
||||
} GENERIC_MAPPING_;
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct _OBJECT_BASIC_INFORMATION {
|
||||
::boost::winapi::ULONG_ Attributes;
|
||||
::boost::winapi::ACCESS_MASK_ GrantedAccess;
|
||||
::boost::winapi::ULONG_ HandleCount;
|
||||
::boost::winapi::ULONG_ PointerCount;
|
||||
::boost::winapi::ULONG_ PagedPoolUsage;
|
||||
::boost::winapi::ULONG_ NonPagedPoolUsage;
|
||||
::boost::winapi::ULONG_ Reserved[3];
|
||||
::boost::winapi::ULONG_ NameInformationLength;
|
||||
::boost::winapi::ULONG_ TypeInformationLength;
|
||||
::boost::winapi::ULONG_ SecurityDescriptorLength;
|
||||
::boost::winapi::LARGE_INTEGER_ CreateTime;
|
||||
} OBJECT_BASIC_INFORMATION_, *POBJECT_BASIC_INFORMATION_;
|
||||
|
||||
typedef struct _OBJECT_NAME_INFORMATION {
|
||||
UNICODE_STRING_ Name;
|
||||
} OBJECT_NAME_INFORMATION_, *POBJECT_NAME_INFORMATION_;
|
||||
|
||||
|
||||
#if defined( BOOST_USE_WINDOWS_H )
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
using SYSTEM_INFORMATION_CLASS_ = ::SYSTEM_INFORMATION_CLASS;
|
||||
constexpr static SYSTEM_INFORMATION_CLASS_ SystemHandleInformation_ = static_cast<SYSTEM_INFORMATION_CLASS_>(16);
|
||||
|
||||
inline ::boost::winapi::NTSTATUS_ nt_system_query_information(
|
||||
SYSTEM_INFORMATION_CLASS SystemInformationClass,
|
||||
void * SystemInformation,
|
||||
::boost::winapi::ULONG_ SystemInformationLength,
|
||||
::boost::winapi::PULONG_ ReturnLength)
|
||||
{
|
||||
return ::NtQuerySystemInformation(SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength);
|
||||
}
|
||||
|
||||
inline ::boost::winapi::NTSTATUS_ nt_query_object(
|
||||
::boost::winapi::HANDLE_ Handle,
|
||||
OBJECT_INFORMATION_CLASS_ ObjectInformationClass,
|
||||
::boost::winapi::PVOID_ ObjectInformation,
|
||||
::boost::winapi::ULONG_ ObjectInformationLength,
|
||||
::boost::winapi::PULONG_ ReturnLength
|
||||
)
|
||||
{
|
||||
return ::NtQueryObject(Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength, ReturnLength);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
//this import workaround is to keep it a header-only library. and enums cannot be imported from the winapi.
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
typedef enum _SYSTEM_INFORMATION_CLASS_
|
||||
{
|
||||
SystemBasicInformation_ = 0,
|
||||
SystemProcessorInformation_ = 1,
|
||||
SystemPerformanceInformation_ = 2,
|
||||
SystemTimeOfDayInformation_ = 3,
|
||||
SystemProcessInformation_ = 5,
|
||||
SystemProcessorPerformanceInformation_ = 8,
|
||||
SystemHandleInformation_ = 16,
|
||||
SystemPagefileInformation_ = 18,
|
||||
SystemInterruptInformation_ = 23,
|
||||
SystemExceptionInformation_ = 33,
|
||||
SystemRegistryQuotaInformation_ = 37,
|
||||
SystemLookasideInformation_ = 45
|
||||
} SYSTEM_INFORMATION_CLASS_;
|
||||
|
||||
|
||||
typedef struct _OBJECT_TYPE_INFORMATION_ {
|
||||
UNICODE_STRING_ TypeName;
|
||||
::boost::winapi::ULONG_ TotalNumberOfObjects;
|
||||
::boost::winapi::ULONG_ TotalNumberOfHandles;
|
||||
::boost::winapi::ULONG_ TotalPagedPoolUsage;
|
||||
::boost::winapi::ULONG_ TotalNonPagedPoolUsage;
|
||||
::boost::winapi::ULONG_ TotalNamePoolUsage;
|
||||
::boost::winapi::ULONG_ TotalHandleTableUsage;
|
||||
::boost::winapi::ULONG_ HighWaterNumberOfObjects;
|
||||
::boost::winapi::ULONG_ HighWaterNumberOfHandles;
|
||||
::boost::winapi::ULONG_ HighWaterPagedPoolUsage;
|
||||
::boost::winapi::ULONG_ HighWaterNonPagedPoolUsage;
|
||||
::boost::winapi::ULONG_ HighWaterNamePoolUsage;
|
||||
::boost::winapi::ULONG_ HighWaterHandleTableUsage;
|
||||
::boost::winapi::ULONG_ InvalidAttributes;
|
||||
GENERIC_MAPPING_ GenericMapping;
|
||||
::boost::winapi::ULONG_ ValidAccessMask;
|
||||
::boost::winapi::BOOLEAN_ SecurityRequired;
|
||||
::boost::winapi::BOOLEAN_ MaintainHandleCount;
|
||||
::boost::winapi::UCHAR_ TypeIndex;
|
||||
::boost::winapi::CHAR_ ReservedByte;
|
||||
::boost::winapi::ULONG_ PoolType;
|
||||
::boost::winapi::ULONG_ DefaultPagedPoolCharge;
|
||||
::boost::winapi::ULONG_ DefaultNonPagedPoolCharge;
|
||||
} OBJECT_TYPE_INFORMATION_, *POBJECT_TYPE_INFORMATION_;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
__kernel_entry NTSTATUS NtQuerySystemInformation(
|
||||
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
|
||||
OUT PVOID SystemInformation,
|
||||
IN ULONG SystemInformationLength,
|
||||
OUT PULONG ReturnLength
|
||||
);
|
||||
*/
|
||||
typedef ::boost::winapi::NTSTATUS_ (__kernel_entry *nt_system_query_information_p )(
|
||||
SYSTEM_INFORMATION_CLASS_,
|
||||
void *,
|
||||
::boost::winapi::ULONG_,
|
||||
::boost::winapi::PULONG_);
|
||||
/*
|
||||
__kernel_entry NTSYSCALLAPI NTSTATUS NtQueryObject(
|
||||
HANDLE Handle,
|
||||
OBJECT_INFORMATION_CLASS ObjectInformationClass,
|
||||
PVOID ObjectInformation,
|
||||
ULONG ObjectInformationLength,
|
||||
PULONG ReturnLength
|
||||
);
|
||||
*/
|
||||
|
||||
typedef ::boost::winapi::NTSTATUS_ (__kernel_entry *nt_query_object_p )(
|
||||
::boost::winapi::HANDLE_,
|
||||
OBJECT_INFORMATION_CLASS_,
|
||||
void *,
|
||||
::boost::winapi::ULONG_,
|
||||
::boost::winapi::PULONG_);
|
||||
|
||||
}
|
||||
|
||||
inline ::boost::winapi::NTSTATUS_ nt_system_query_information(
|
||||
SYSTEM_INFORMATION_CLASS_ SystemInformationClass,
|
||||
void *SystemInformation,
|
||||
::boost::winapi::ULONG_ SystemInformationLength,
|
||||
::boost::winapi::PULONG_ ReturnLength)
|
||||
{
|
||||
static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle(L"Ntdll.dll");
|
||||
static nt_system_query_information_p f = reinterpret_cast<nt_system_query_information_p>(::boost::winapi::get_proc_address(h, "NtQuerySystemInformation"));
|
||||
|
||||
return (*f)(SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength);
|
||||
}
|
||||
|
||||
|
||||
inline ::boost::winapi::BOOL_ nt_query_object(
|
||||
::boost::winapi::HANDLE_ Handle,
|
||||
OBJECT_INFORMATION_CLASS_ ObjectInformationClass,
|
||||
void *ObjectInformation,
|
||||
::boost::winapi::ULONG_ ObjectInformationLength,
|
||||
::boost::winapi::PULONG_ ReturnLength)
|
||||
{
|
||||
static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle(L"Ntdll.dll");
|
||||
static nt_query_object_p f = reinterpret_cast<nt_query_object_p>(::boost::winapi::get_proc_address(h, "NtQueryObject"));
|
||||
|
||||
return (*f)(Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength, ReturnLength);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_JOB_WORKAROUND_HPP_ */
|
||||
@@ -1,176 +0,0 @@
|
||||
// Copyright (c) 2019 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)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_HANDLES_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_HANDLES_HPP_
|
||||
|
||||
#include <vector>
|
||||
#include <system_error>
|
||||
#include <boost/process/detail/windows/handle_workaround.hpp>
|
||||
#include <boost/process/detail/windows/handler.hpp>
|
||||
#include <boost/winapi/get_current_process_id.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
|
||||
template<typename Executor, typename Function>
|
||||
void foreach_used_handle(Executor &exec, Function &&func);
|
||||
|
||||
|
||||
namespace windows {
|
||||
|
||||
|
||||
using native_handle_type = ::boost::winapi::HANDLE_ ;
|
||||
|
||||
inline std::vector<native_handle_type> get_handles(std::error_code & ec)
|
||||
{
|
||||
auto pid = ::boost::winapi::GetCurrentProcessId();
|
||||
|
||||
std::vector<char> buffer(2048);
|
||||
constexpr static auto STATUS_INFO_LENGTH_MISMATCH_ = static_cast<::boost::winapi::NTSTATUS_>(0xC0000004l);
|
||||
auto info_pointer = reinterpret_cast<workaround::SYSTEM_HANDLE_INFORMATION_*>(buffer.data());
|
||||
|
||||
::boost::winapi::NTSTATUS_ nt_status = STATUS_INFO_LENGTH_MISMATCH_;
|
||||
|
||||
for (int cnt = 0;
|
||||
nt_status == STATUS_INFO_LENGTH_MISMATCH_;
|
||||
nt_status = workaround::nt_system_query_information(
|
||||
workaround::SystemHandleInformation_,
|
||||
info_pointer, buffer.size(),
|
||||
NULL))
|
||||
{
|
||||
buffer.resize(buffer.size() * 2);
|
||||
info_pointer = reinterpret_cast<workaround::SYSTEM_HANDLE_INFORMATION_*>(buffer.data());
|
||||
}
|
||||
|
||||
|
||||
if (nt_status < 0 || nt_status > 0x7FFFFFFF)
|
||||
{
|
||||
ec = ::boost::process::detail::get_last_error();
|
||||
return {};
|
||||
}
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
std::vector<native_handle_type> res;
|
||||
for (auto itr = info_pointer->Handle; itr != (info_pointer->Handle + info_pointer->Count); itr++)
|
||||
{
|
||||
if (itr->OwnerPid == pid)
|
||||
res.push_back(reinterpret_cast<native_handle_type>(static_cast<std::uintptr_t>(itr->HandleValue)));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
inline std::vector<native_handle_type> get_handles()
|
||||
{
|
||||
std::error_code ec;
|
||||
|
||||
auto res = get_handles(ec);
|
||||
if (ec)
|
||||
boost::process::detail::throw_error(ec, "NtQuerySystemInformation failed");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
inline bool is_stream_handle(native_handle_type handle, std::error_code & ec)
|
||||
{
|
||||
::boost::winapi::ULONG_ actual_size;
|
||||
auto nt_status = workaround::nt_query_object(
|
||||
handle,
|
||||
workaround::ObjectTypeInformation,
|
||||
NULL,
|
||||
0, &actual_size);
|
||||
|
||||
std::vector<char> vec;
|
||||
vec.resize(actual_size);
|
||||
|
||||
workaround::OBJECT_TYPE_INFORMATION_ * type_info_p = reinterpret_cast<workaround::OBJECT_TYPE_INFORMATION_*>(vec.data());
|
||||
nt_status = workaround::nt_query_object(
|
||||
handle,
|
||||
workaround::ObjectTypeInformation,
|
||||
type_info_p,
|
||||
actual_size, &actual_size);
|
||||
|
||||
if (nt_status < 0 || nt_status > 0x7FFFFFFF)
|
||||
{
|
||||
ec = ::boost::process::detail::get_last_error();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
auto &nm = type_info_p->TypeName.Buffer;
|
||||
return type_info_p->TypeName.Length >= 5 &&
|
||||
nm[0] == L'F' &&
|
||||
nm[1] == L'i' &&
|
||||
nm[2] == L'l' &&
|
||||
nm[3] == L'e' &&
|
||||
nm[4] == L'\0';
|
||||
}
|
||||
|
||||
|
||||
inline bool is_stream_handle(native_handle_type handle)
|
||||
{
|
||||
std::error_code ec;
|
||||
auto res = is_stream_handle(handle, ec);
|
||||
if (ec)
|
||||
boost::process::detail::throw_error(ec, "NtQueryObject failed");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
struct limit_handles_ : handler_base_ext
|
||||
{
|
||||
mutable std::vector<::boost::winapi::HANDLE_> handles_with_inherit_flag;
|
||||
|
||||
template<typename Executor>
|
||||
void on_setup(Executor & exec) const
|
||||
{
|
||||
auto all_handles = get_handles();
|
||||
foreach_used_handle(exec,
|
||||
[&](::boost::winapi::HANDLE_ handle)
|
||||
{
|
||||
auto itr = std::find(all_handles.begin(), all_handles .end(), handle);
|
||||
DWORD flags = 0u;
|
||||
if (itr != all_handles.end())
|
||||
*itr = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if ((::boost::winapi::GetHandleInformation(*itr, &flags) != 0)
|
||||
&&((flags & ::boost::winapi::HANDLE_FLAG_INHERIT_) == 0)) //it is NOT inherited anyhow, so ignore too
|
||||
*itr = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
});
|
||||
|
||||
auto part_itr = std::partition(all_handles.begin(), all_handles.end(),
|
||||
[](::boost::winapi::HANDLE_ handle) {return handle != ::boost::winapi::INVALID_HANDLE_VALUE_;});
|
||||
|
||||
all_handles.erase(part_itr, all_handles.end()); //remove invalid handles
|
||||
handles_with_inherit_flag = std::move(all_handles);
|
||||
|
||||
for (auto handle : handles_with_inherit_flag)
|
||||
::boost::winapi::SetHandleInformation(handle, ::boost::winapi::HANDLE_FLAG_INHERIT_, 0);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor & exec, const std::error_code & ec) const
|
||||
{
|
||||
for (auto handle : handles_with_inherit_flag)
|
||||
::boost::winapi::SetHandleInformation(handle, ::boost::winapi::HANDLE_FLAG_INHERIT_, ::boost::winapi::HANDLE_FLAG_INHERIT_);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_sucess(Executor & exec) const
|
||||
{
|
||||
for (auto handle : handles_with_inherit_flag)
|
||||
::boost::winapi::SetHandleInformation(handle, ::boost::winapi::HANDLE_FLAG_INHERIT_, ::boost::winapi::HANDLE_FLAG_INHERIT_);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
#endif //PROCESS_HANDLES_HPP
|
||||
@@ -14,18 +14,14 @@
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/winapi/handle_info.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <boost/process/detail/windows/file_descriptor.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
struct null_in : public ::boost::process::detail::handler_base, ::boost::process::detail::uses_handles
|
||||
struct null_in : public ::boost::process::detail::handler_base
|
||||
{
|
||||
file_descriptor source{"NUL", file_descriptor::read};
|
||||
|
||||
::boost::winapi::HANDLE_ get_used_handles() const { return source.handle(); }
|
||||
|
||||
|
||||
public:
|
||||
template <class WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &e) const
|
||||
|
||||
@@ -14,18 +14,15 @@
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/winapi/handle_info.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <boost/process/detail/windows/file_descriptor.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
template<int p1, int p2>
|
||||
struct null_out : public ::boost::process::detail::handler_base, ::boost::process::detail::uses_handles
|
||||
struct null_out : public ::boost::process::detail::handler_base
|
||||
{
|
||||
file_descriptor sink {"NUL", file_descriptor::write}; //works because it gets destroyed AFTER launch.
|
||||
|
||||
::boost::winapi::HANDLE_ get_used_handles() const { return sink.handle(); }
|
||||
|
||||
template <typename WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &e) const;
|
||||
};
|
||||
|
||||
@@ -12,17 +12,14 @@
|
||||
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
struct pipe_in : public ::boost::process::detail::handler_base, ::boost::process::detail::uses_handles
|
||||
struct pipe_in : public ::boost::process::detail::handler_base
|
||||
{
|
||||
::boost::winapi::HANDLE_ handle;
|
||||
|
||||
::boost::winapi::HANDLE_ get_used_handles() const { return handle; }
|
||||
|
||||
pipe_in(::boost::winapi::HANDLE_ handle) : handle(handle) {}
|
||||
|
||||
template<typename T> //async_pipe
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
@@ -21,12 +20,10 @@ namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
|
||||
template<int p1, int p2>
|
||||
struct pipe_out : public ::boost::process::detail::handler_base, ::boost::process::detail::uses_handles
|
||||
struct pipe_out : public ::boost::process::detail::handler_base
|
||||
{
|
||||
::boost::winapi::HANDLE_ handle;
|
||||
|
||||
::boost::winapi::HANDLE_ get_used_handles() const { return handle; }
|
||||
|
||||
pipe_out(::boost::winapi::HANDLE_ handle) : handle(handle) {}
|
||||
template<typename T>
|
||||
pipe_out(T & p) : handle(p.native_sink())
|
||||
|
||||
@@ -27,7 +27,7 @@ inline bool wait_impl(const group_handle & p, std::error_code & ec, std::chrono:
|
||||
|
||||
while (workaround::get_queued_completion_status(
|
||||
p._io_port, &completion_code,
|
||||
&completion_key, &overlapped, static_cast<::boost::winapi::DWORD_>(wait_time)))
|
||||
&completion_key, &overlapped, wait_time))
|
||||
{
|
||||
if (reinterpret_cast<::boost::winapi::HANDLE_>(completion_key) == p._job_object &&
|
||||
completion_code == workaround::JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO_)
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#define BOOST_PROCESS_EXTENSIONS_HPP_
|
||||
|
||||
#include <boost/process/detail/handler.hpp>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/executor.hpp>
|
||||
@@ -63,9 +62,6 @@ using ::boost::process::detail::api::async_handler;
|
||||
using ::boost::process::detail::get_io_context;
|
||||
using ::boost::process::detail::get_last_error;
|
||||
using ::boost::process::detail::throw_last_error;
|
||||
using ::boost::process::detail::uses_handles;
|
||||
using ::boost::process::detail::foreach_used_handle;
|
||||
using ::boost::process::detail::get_used_handles;
|
||||
|
||||
///This handler is invoked before the process in launched, to setup parameters. The required signature is `void(Exec &)`, where `Exec` is a template parameter.
|
||||
constexpr boost::process::detail::make_handler_t<boost::process::detail::on_setup_> on_setup;
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
// Copyright (c) 2019 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)
|
||||
|
||||
#ifndef BOOST_PROCESS_HANDLES_HPP_
|
||||
#define BOOST_PROCESS_HANDLES_HPP_
|
||||
|
||||
/**
|
||||
* \file boost/process/handles.hpp
|
||||
*
|
||||
* Defines functions to obtain handles of the current process and limit the amount for inherited ones.
|
||||
*/
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/handles.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/handles.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace this_process
|
||||
{
|
||||
|
||||
///The native type for handles
|
||||
using native_handle_type = ::boost::process::detail::api::native_handle_type;
|
||||
|
||||
/**
|
||||
* Get a snapshot of all handles of the process (i.e. file descriptors on posix and handles on windows) of the current process.
|
||||
*
|
||||
* \note This function might not work on certain posix systems.
|
||||
*
|
||||
* \note On Windows version older than windows 8 this function will iterate all the system handles, meaning it might be quite slow.
|
||||
*
|
||||
* \warning This functionality is utterly prone to race conditions, since other threads might open or close handles.
|
||||
*
|
||||
* \return The list of all open handles of the current process
|
||||
*/
|
||||
inline std::vector<native_handle_type> get_handles()
|
||||
{
|
||||
return ::boost::process::detail::api::get_handles();
|
||||
}
|
||||
|
||||
|
||||
/** \overload std::vector<native_handle_type> get_handles() */
|
||||
inline std::vector<native_handle_type> get_handles(std::error_code &ec)
|
||||
{
|
||||
return ::boost::process::detail::api::get_handles(ec);
|
||||
}
|
||||
|
||||
/** Determines if a given handle is a a stream-handle, i.e. any handle that can be used with read and write functions.
|
||||
* Stream handles include pipes, regular files and sockets.
|
||||
*
|
||||
* \return Indicates if it's a stream handle.
|
||||
*/
|
||||
inline bool is_stream_handle(native_handle_type handle)
|
||||
{
|
||||
return ::boost::process::detail::api::is_stream_handle(handle);
|
||||
}
|
||||
|
||||
|
||||
/** \overload bool is_stream_handle(native_handle_type handle) */
|
||||
inline bool is_stream_handle(native_handle_type handle, std::error_code &ec)
|
||||
{
|
||||
return ::boost::process::detail::api::is_stream_handle(handle, ec);
|
||||
}
|
||||
|
||||
}
|
||||
namespace process
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
using limit_handles_ = ::boost::process::detail::api::limit_handles_;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The limit_handles property sets all properties to be inherited only expcitly. It closes all unused file-descriptors on posix after the fork and
|
||||
* removes the inherit flags on windows.
|
||||
*
|
||||
* \note This is executed after the fork on posix.
|
||||
*
|
||||
* \code{.cpp}
|
||||
* system("gcc", limit_handles);
|
||||
* \endcode
|
||||
*
|
||||
* Since limit also closes the standard handles unless they are explicitly redirected they can be ignored by `limit_handles` in the following way.
|
||||
*
|
||||
* \code{.cpp}
|
||||
* system("gcc", limit_handles.allowStd())
|
||||
* \endcode
|
||||
*
|
||||
*/
|
||||
const static ::boost::process::detail::api::limit_handles_ limit_handles;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif //BOOST_PROCESS_HANDLES_HPP_
|
||||
@@ -122,20 +122,6 @@ system("b2", std_out > null);
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
|
||||
template<typename T> using is_streambuf = typename std::is_same<T, boost::asio::streambuf>::type;
|
||||
template<typename T> using is_const_buffer =
|
||||
std::integral_constant<bool,
|
||||
std::is_same< boost::asio::const_buffer, T>::value |
|
||||
std::is_base_of<boost::asio::const_buffer, T>::value
|
||||
>;
|
||||
template<typename T> using is_mutable_buffer =
|
||||
std::integral_constant<bool,
|
||||
std::is_same< boost::asio::mutable_buffer, T>::value |
|
||||
std::is_base_of<boost::asio::mutable_buffer, T>::value
|
||||
>;
|
||||
|
||||
|
||||
struct null_t {constexpr null_t() {}};
|
||||
struct close_t;
|
||||
|
||||
@@ -177,19 +163,25 @@ struct std_in_
|
||||
api::async_pipe_in operator=(async_pipe & p) const {return p;}
|
||||
api::async_pipe_in operator<(async_pipe & p) const {return p;}
|
||||
|
||||
template<typename T, typename = typename std::enable_if<
|
||||
is_const_buffer<T>::value || is_mutable_buffer<T>::value
|
||||
>::type>
|
||||
api::async_in_buffer<const T> operator=(const T & buf) const {return buf;}
|
||||
template<typename T, typename = typename std::enable_if<is_streambuf<T>::value>::type >
|
||||
api::async_in_buffer<T> operator=(T & buf) const {return buf;}
|
||||
template<typename T>
|
||||
auto operator=(const T & buf) const -> typename std::enable_if<asio::is_const_buffer_sequence<T>::value, api::async_in_buffer<const T>>::type {return buf;}
|
||||
template<typename T>
|
||||
auto operator<(const T & buf) const -> typename std::enable_if<asio::is_const_buffer_sequence<T>::value, api::async_in_buffer<const T>>::type {return buf;}
|
||||
|
||||
template<typename T, typename = typename std::enable_if<
|
||||
is_const_buffer<T>::value || is_mutable_buffer<T>::value
|
||||
>::type>
|
||||
api::async_in_buffer<const T> operator<(const T & buf) const {return buf;}
|
||||
template<typename T, typename = typename std::enable_if<is_streambuf<T>::value>::type >
|
||||
api::async_in_buffer<T> operator<(T & buf) const {return buf;}
|
||||
template<typename T>
|
||||
auto operator=(T & buf) const -> typename std::enable_if<asio::is_const_buffer_sequence<T>::value, api::async_in_buffer<T>>::type {return buf;}
|
||||
template<typename T>
|
||||
auto operator<(T & buf) const -> typename std::enable_if<asio::is_const_buffer_sequence<T>::value, api::async_in_buffer<T>>::type {return buf;}
|
||||
|
||||
template<typename Allocator>
|
||||
api::async_in_buffer<asio::basic_streambuf<Allocator>> operator<(boost::asio::basic_streambuf<Allocator> & p) const {return p;}
|
||||
template<typename Allocator>
|
||||
api::async_in_buffer<asio::basic_streambuf<Allocator>> operator=(boost::asio::basic_streambuf<Allocator> & p) const {return p;}
|
||||
|
||||
template<typename Allocator>
|
||||
api::async_in_buffer<asio::basic_streambuf<Allocator>> operator<(const boost::asio::basic_streambuf<Allocator> & p) const {return p;}
|
||||
template<typename Allocator>
|
||||
api::async_in_buffer<asio::basic_streambuf<Allocator>> operator=(const boost::asio::basic_streambuf<Allocator> & p) const {return p;}
|
||||
|
||||
};
|
||||
|
||||
@@ -234,13 +226,24 @@ struct std_out_
|
||||
api::async_pipe_out<p1, p2> operator=(async_pipe & p) const {return p;}
|
||||
api::async_pipe_out<p1, p2> operator>(async_pipe & p) const {return p;}
|
||||
|
||||
api::async_out_buffer<p1, p2, const asio::mutable_buffer> operator=(const asio::mutable_buffer & buf) const {return buf;}
|
||||
api::async_out_buffer<p1, p2, const asio::mutable_buffers_1> operator=(const asio::mutable_buffers_1 & buf) const {return buf;}
|
||||
api::async_out_buffer<p1, p2, asio::streambuf> operator=(asio::streambuf & os) const {return os ;}
|
||||
template<typename Allocator>
|
||||
api::async_out_buffer<p1, p2, asio::basic_streambuf<Allocator>> operator=(boost::asio::basic_streambuf<Allocator> & p) const {return p;}
|
||||
template<typename Allocator>
|
||||
api::async_out_buffer<p1, p2, asio::basic_streambuf<Allocator>> operator>(boost::asio::basic_streambuf<Allocator> & p) const {return p;}
|
||||
|
||||
api::async_out_buffer<p1, p2, const asio::mutable_buffer> operator>(const asio::mutable_buffer & buf) const {return buf;}
|
||||
api::async_out_buffer<p1, p2, const asio::mutable_buffers_1> operator>(const asio::mutable_buffers_1 & buf) const {return buf;}
|
||||
api::async_out_buffer<p1, p2, asio::streambuf> operator>(asio::streambuf & os) const {return os ;}
|
||||
template<typename Buffer>
|
||||
auto operator=(const Buffer & buf) const
|
||||
-> typename std::enable_if<asio::is_mutable_buffer_sequence<Buffer>::value, api::async_out_buffer<p1, p2, Buffer>>::type
|
||||
{
|
||||
return buf;
|
||||
}
|
||||
|
||||
template<typename Buffer>
|
||||
auto operator>(const Buffer & buf) const
|
||||
-> typename std::enable_if<asio::is_mutable_buffer_sequence<Buffer>::value, api::async_out_buffer<p1, p2, Buffer>>::type
|
||||
{
|
||||
return buf;
|
||||
}
|
||||
|
||||
api::async_out_future<p1,p2, std::string> operator=(std::future<std::string> & fut) const { return fut;}
|
||||
api::async_out_future<p1,p2, std::string> operator>(std::future<std::string> & fut) const { return fut;}
|
||||
|
||||
@@ -120,13 +120,6 @@ struct basic_pipebuf : std::basic_streambuf<CharT, Traits>
|
||||
///Move Constructor
|
||||
basic_pipebuf(basic_pipebuf && ) = default;
|
||||
|
||||
///Destructor -> writes the frest of the data
|
||||
~basic_pipebuf()
|
||||
{
|
||||
if (is_open())
|
||||
overflow(Traits::eof());
|
||||
}
|
||||
|
||||
///Move construct from a pipe.
|
||||
basic_pipebuf(pipe_type && p) : _pipe(std::move(p)),
|
||||
_write(default_buffer_size),
|
||||
@@ -162,7 +155,7 @@ struct basic_pipebuf : std::basic_streambuf<CharT, Traits>
|
||||
///Writes characters to the associated output sequence from the put area
|
||||
int_type overflow(int_type ch = traits_type::eof()) override
|
||||
{
|
||||
if (_pipe.is_open() && (ch != traits_type::eof()))
|
||||
if ((ch != traits_type::eof()) && _pipe.is_open())
|
||||
{
|
||||
if (this->pptr() == this->epptr())
|
||||
{
|
||||
@@ -180,9 +173,6 @@ struct basic_pipebuf : std::basic_streambuf<CharT, Traits>
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
else if (ch == traits_type::eof())
|
||||
this->sync();
|
||||
|
||||
return traits_type::eof();
|
||||
}
|
||||
///Synchronizes the buffers with the associated character sequence
|
||||
@@ -222,36 +212,6 @@ struct basic_pipebuf : std::basic_streambuf<CharT, Traits>
|
||||
const pipe_type &pipe() const & {return _pipe;}
|
||||
///Get a rvalue reference to the pipe. Qualified as rvalue.
|
||||
pipe_type && pipe() && {return std::move(_pipe);}
|
||||
|
||||
///Check if the pipe is open
|
||||
bool is_open() const {return _pipe.is_open(); }
|
||||
|
||||
///Open a new pipe
|
||||
basic_pipebuf<CharT, Traits>* open()
|
||||
{
|
||||
if (is_open())
|
||||
return nullptr;
|
||||
_pipe = pipe();
|
||||
return this;
|
||||
}
|
||||
|
||||
///Open a new named pipe
|
||||
basic_pipebuf<CharT, Traits>* open(const std::string & name)
|
||||
{
|
||||
if (is_open())
|
||||
return nullptr;
|
||||
_pipe = pipe(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
///Flush the buffer & close the pipe
|
||||
basic_pipebuf<CharT, Traits>* close()
|
||||
{
|
||||
if (!is_open())
|
||||
return nullptr;
|
||||
overflow(Traits::eof());
|
||||
return this;
|
||||
}
|
||||
private:
|
||||
pipe_type _pipe;
|
||||
std::vector<char_type> _write;
|
||||
@@ -263,13 +223,8 @@ private:
|
||||
return false;
|
||||
|
||||
auto base = this->pbase();
|
||||
|
||||
if (base == this->pptr())
|
||||
return true;
|
||||
|
||||
std::ptrdiff_t wrt = _pipe.write(base,
|
||||
static_cast<typename pipe_type::int_type>(this->pptr() - base));
|
||||
|
||||
std::ptrdiff_t diff = this->pptr() - base;
|
||||
|
||||
if (wrt < diff)
|
||||
@@ -365,33 +320,6 @@ public:
|
||||
const pipe_type &pipe() const & {return _buf.pipe();}
|
||||
///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();}
|
||||
|
||||
///Open a new pipe
|
||||
void open()
|
||||
{
|
||||
if (_buf.open() == nullptr)
|
||||
this->setstate(std::ios_base::failbit);
|
||||
else
|
||||
this->clear();
|
||||
}
|
||||
|
||||
///Open a new named pipe
|
||||
void open(const std::string & name)
|
||||
{
|
||||
if (_buf.open() == nullptr)
|
||||
this->setstate(std::ios_base::failbit);
|
||||
else
|
||||
this->clear();
|
||||
}
|
||||
|
||||
///Flush the buffer & close the pipe
|
||||
void close()
|
||||
{
|
||||
if (_buf.close() == nullptr)
|
||||
this->setstate(std::ios_base::failbit);
|
||||
}
|
||||
};
|
||||
|
||||
typedef basic_ipstream<char> ipstream;
|
||||
@@ -474,31 +402,6 @@ public:
|
||||
const pipe_type &pipe() const & {return _buf.pipe();}
|
||||
///Get a rvalue reference to the pipe. Qualified as rvalue.
|
||||
pipe_type && pipe() && {return std::move(_buf).pipe();}
|
||||
|
||||
///Open a new pipe
|
||||
void open()
|
||||
{
|
||||
if (_buf.open() == nullptr)
|
||||
this->setstate(std::ios_base::failbit);
|
||||
else
|
||||
this->clear();
|
||||
}
|
||||
|
||||
///Open a new named pipe
|
||||
void open(const std::string & name)
|
||||
{
|
||||
if (_buf.open() == nullptr)
|
||||
this->setstate(std::ios_base::failbit);
|
||||
else
|
||||
this->clear();
|
||||
}
|
||||
|
||||
///Flush the buffer & close the pipe
|
||||
void close()
|
||||
{
|
||||
if (_buf.close() == nullptr)
|
||||
this->setstate(std::ios_base::failbit);
|
||||
}
|
||||
};
|
||||
|
||||
typedef basic_opstream<char> opstream;
|
||||
@@ -581,31 +484,6 @@ public:
|
||||
const pipe_type &pipe() const & {return _buf.pipe();}
|
||||
///Get a rvalue reference to the pipe. Qualified as rvalue.
|
||||
pipe_type && pipe() && {return std::move(_buf).pipe();}
|
||||
|
||||
///Open a new pipe
|
||||
void open()
|
||||
{
|
||||
if (_buf.open() == nullptr)
|
||||
this->setstate(std::ios_base::failbit);
|
||||
else
|
||||
this->clear();
|
||||
}
|
||||
|
||||
///Open a new named pipe
|
||||
void open(const std::string & name)
|
||||
{
|
||||
if (_buf.open() == nullptr)
|
||||
this->setstate(std::ios_base::failbit);
|
||||
else
|
||||
this->clear();
|
||||
}
|
||||
|
||||
///Flush the buffer & close the pipe
|
||||
void close()
|
||||
{
|
||||
if (_buf.close() == nullptr)
|
||||
this->setstate(std::ios_base::failbit);
|
||||
}
|
||||
};
|
||||
|
||||
typedef basic_pstream<char> pstream;
|
||||
|
||||
@@ -16,7 +16,6 @@ if [ os.name ] = NT
|
||||
lib ws2_32 ;
|
||||
lib shell32 ;
|
||||
lib Advapi32 ;
|
||||
lib Ntdll ;
|
||||
}
|
||||
|
||||
project : requirements
|
||||
@@ -45,7 +44,7 @@ alias coroutine : /boost//coroutine : <link>static ;
|
||||
lib multi_ref : multi_ref1.cpp multi_ref2.cpp system : <target-os>windows:<source>shell32 ;
|
||||
|
||||
exe sparring_partner : sparring_partner.cpp program_options system filesystem iostreams :
|
||||
<warnings>off <target-os>windows:<source>shell32 <target-os>windows:<source>Ntdll
|
||||
<warnings>off <target-os>windows:<source>shell32
|
||||
;
|
||||
|
||||
exe exit_argc : exit_argc.cpp :
|
||||
@@ -56,15 +55,8 @@ exe sub_launch : sub_launcher.cpp program_options iostreams system filesystem :
|
||||
|
||||
rule test-options ( name )
|
||||
{
|
||||
if "--boost-process-report-ci" in [ modules.peek : ARGV ]
|
||||
{
|
||||
return --log_sink=log_$(name).xml --log_format=XML --log_level=error --report_sink=report_$(name).xml --report_format=XML --report_level=detailed -- ;
|
||||
}
|
||||
else
|
||||
{
|
||||
return --log_level=error --report_level=detailed -- ;
|
||||
}
|
||||
|
||||
return --log_sink=log_$(name).xml --log_format=XML --log_level=error --report_sink=report_$(name).xml --report_format=XML --report_level=detailed -- ;
|
||||
#return --log_level=error --report_level=detailed -- ;
|
||||
}
|
||||
|
||||
|
||||
@@ -101,7 +93,6 @@ test-suite with-valgrind :
|
||||
[ run group.cpp system thread filesystem : [ test-options group ] : sub_launch ]
|
||||
[ run group.cpp system thread filesystem : [ test-options group ] : sub_launch : <build>no <target-os>windows:<build>yes <define>BOOST_USE_WINDOWS_H=1 : group-windows-h ]
|
||||
[ run group_wait.cpp system thread filesystem : [ test-options group_wait ] : sparring_partner ]
|
||||
[ run limit_fd.cpp program_options system filesystem : [ test-options limit_fd ] : sparring_partner ]
|
||||
[ run run_exe.cpp filesystem : : sparring_partner ]
|
||||
[ run run_exe_path.cpp filesystem : [ test-options run_exe_path ] : sparring_partner ]
|
||||
[ run search_path.cpp filesystem system : [ test-options search_path ] : : <target-os>windows:<source>shell32 ]
|
||||
|
||||
@@ -67,11 +67,11 @@ build_script:
|
||||
after_build:
|
||||
before_test:
|
||||
test_script:
|
||||
- ..\..\..\b2.exe address-model=64 architecture=x86 cxxflags="-DBOOST_TRAVISCI_BUILD" -sBOOST_BUILD_PATH=. --boost-process-report-ci
|
||||
- ..\..\..\b2.exe address-model=64 architecture=x86 cxxflags="-DBOOST_TRAVISCI_BUILD" -sBOOST_BUILD_PATH=.
|
||||
|
||||
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%/libs/%PROJECT_TO_TEST%/test
|
||||
|
||||
|
||||
@@ -58,15 +58,10 @@ BOOST_AUTO_TEST_CASE(group_test, *boost::unit_test::timeout(5))
|
||||
BOOST_CHECK(!c.running());
|
||||
if (c.running())
|
||||
c.terminate();
|
||||
|
||||
std::cout << "group_test out" << std::endl;
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(attached, *boost::unit_test::timeout(5))
|
||||
{
|
||||
std::cout << "attached" << std::endl;
|
||||
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
|
||||
bp::ipstream is;
|
||||
@@ -94,11 +89,10 @@ BOOST_AUTO_TEST_CASE(attached, *boost::unit_test::timeout(5))
|
||||
|
||||
|
||||
BOOST_REQUIRE(sub_c);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100)); //just to be sure.
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50)); //just to be sure.
|
||||
|
||||
|
||||
#if defined( BOOST_POSIX_API )
|
||||
::waitpid(sub_c.id(), nullptr, WNOHANG);
|
||||
BOOST_CHECK(kill(sub_c.id(), 0) == 0);
|
||||
#else
|
||||
BOOST_CHECK(sub_c.running());
|
||||
@@ -107,27 +101,23 @@ BOOST_AUTO_TEST_CASE(attached, *boost::unit_test::timeout(5))
|
||||
BOOST_REQUIRE_NO_THROW(g.terminate());
|
||||
|
||||
BOOST_CHECK(sub_c);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100)); //just to be sure.
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50)); //just to be sure.
|
||||
|
||||
BOOST_CHECK(!c.running());
|
||||
|
||||
#if defined( BOOST_POSIX_API )
|
||||
errno = 0;
|
||||
::waitpid(sub_c.id(), nullptr, WNOHANG);
|
||||
bool still_runs = (kill(sub_c.id(), 0) == 0) && (errno != ECHILD) && (errno != ESRCH);
|
||||
#else
|
||||
bool still_runs = kill(sub_c.id(), 0) == 0;
|
||||
#else
|
||||
bool still_runs = sub_c.running();
|
||||
#endif
|
||||
BOOST_CHECK_MESSAGE(!still_runs, boost::process::detail::get_last_error().message());
|
||||
|
||||
BOOST_CHECK(!still_runs);
|
||||
if (still_runs)
|
||||
sub_c.terminate();
|
||||
BOOST_CHECK(!c.running());
|
||||
if (c.running())
|
||||
c.terminate();
|
||||
|
||||
std::cout << "attached out" << std::endl;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -186,6 +176,4 @@ BOOST_AUTO_TEST_CASE(detached, *boost::unit_test::timeout(5))
|
||||
BOOST_CHECK(!c.running());
|
||||
if (c.running())
|
||||
c.terminate();
|
||||
|
||||
std::cerr << "detached out" << std::endl;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#define BOOST_TEST_MAIN
|
||||
#define BOOST_TEST_IGNORE_SIGCHLD
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
@@ -107,7 +107,7 @@ BOOST_AUTO_TEST_CASE(wait_group_test_timeout, *boost::unit_test::timeout(15))
|
||||
|
||||
bp::child c2(
|
||||
master_test_suite().argv[1],
|
||||
"--wait", "4",
|
||||
"--wait", "3",
|
||||
g,
|
||||
ec
|
||||
);
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
// Copyright (c) 2019 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 <iostream>
|
||||
|
||||
#include <boost/process.hpp>
|
||||
#include <boost/process/handles.hpp>
|
||||
#include <boost/process/pipe.hpp>
|
||||
#include <boost/process/io.hpp>
|
||||
#include <boost/process/async_pipe.hpp>
|
||||
#include <boost/process/extend.hpp>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <system_error>
|
||||
#include <string>
|
||||
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/ip/udp.hpp>
|
||||
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
#include <boost/winapi/get_current_thread.hpp>
|
||||
#include <boost/winapi/get_current_process.hpp>
|
||||
#endif
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
namespace bp = boost::process;
|
||||
namespace bt = boost::this_process;
|
||||
|
||||
BOOST_AUTO_TEST_CASE(leak_test, *boost::unit_test::timeout(5))
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
const auto get_handle = [](FILE * f) {return reinterpret_cast<bt::native_handle_type>(_get_osfhandle(_fileno(f)));};
|
||||
const auto socket_to_handle = [](::boost::winapi::UINT_PTR_ sock){return reinterpret_cast<::boost::winapi::HANDLE_>(sock);};
|
||||
#else
|
||||
const auto get_handle = [](FILE * f) {return fileno(f);};
|
||||
const auto socket_to_handle = [](int i){ return i;};
|
||||
#endif
|
||||
|
||||
std::error_code ec;
|
||||
auto fd_list = bt::get_handles(ec);
|
||||
|
||||
BOOST_CHECK_EQUAL(std::count(fd_list.begin(), fd_list.end(), get_handle(stdin)), 1);
|
||||
BOOST_CHECK_EQUAL(std::count(fd_list.begin(), fd_list.end(), get_handle(stdout)), 1);
|
||||
BOOST_CHECK_EQUAL(std::count(fd_list.begin(), fd_list.end(), get_handle(stderr)), 1);
|
||||
|
||||
BOOST_CHECK(bt::is_stream_handle(get_handle(stdin), ec)); BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
BOOST_CHECK(bt::is_stream_handle(get_handle(stdout), ec)); BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
BOOST_CHECK(bt::is_stream_handle(get_handle(stderr), ec)); BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
|
||||
|
||||
BOOST_CHECK_GE(fd_list.size(), 3);
|
||||
BOOST_CHECK_GE(bt::get_handles(ec).size(), fd_list.size());
|
||||
|
||||
bp::pipe p;
|
||||
|
||||
{
|
||||
|
||||
auto fd_list_new = bt::get_handles(ec);
|
||||
BOOST_CHECK_MESSAGE(!ec, ec);
|
||||
BOOST_CHECK_LE(fd_list.size() + 2, fd_list_new.size());
|
||||
fd_list = std::move(fd_list_new);
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOST_CHECK_EQUAL(std::count(fd_list.begin(), fd_list.end(), p.native_source()), 1);
|
||||
BOOST_CHECK_EQUAL(std::count(fd_list.begin(), fd_list.end(), p.native_sink()), 1);
|
||||
|
||||
BOOST_CHECK(bt::is_stream_handle(p.native_source(), ec)); BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
BOOST_CHECK(bt::is_stream_handle(p.native_sink(), ec)); BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
|
||||
|
||||
p.close();
|
||||
fd_list = bt::get_handles(ec);
|
||||
|
||||
BOOST_CHECK_EQUAL(std::count(fd_list.begin(), fd_list.end(), p.native_source()), 0);
|
||||
BOOST_CHECK_EQUAL(std::count(fd_list.begin(), fd_list.end(), p.native_sink()), 0);
|
||||
|
||||
#if defined( BOOST_WINDOWS_API )
|
||||
std::thread thr([]{});
|
||||
BOOST_CHECK(!bt::is_stream_handle(thr.native_handle(), ec)); BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
thr.join();
|
||||
#else
|
||||
# if defined(TFD_CLOEXEC) //check timer
|
||||
int timer_fd = ::timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
|
||||
BOOST_CHECK(!bt::is_stream_handle(timer_fd , ec)); BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
#endif
|
||||
# if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
|
||||
int event_fd =::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
|
||||
BOOST_CHECK(!bt::is_stream_handle(event_fd , ec)); BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
#endif
|
||||
int dir_fd = ::dirfd(::opendir("."));
|
||||
BOOST_CHECK(!bt::is_stream_handle(dir_fd , ec)); BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
#endif
|
||||
|
||||
|
||||
boost::asio::io_context ioc;
|
||||
boost::asio::ip::tcp::socket tcp_socket(ioc);
|
||||
boost::asio::ip::udp::socket udp_socket(ioc);
|
||||
bp::async_pipe ap(ioc);
|
||||
|
||||
tcp_socket.open(boost::asio::ip::tcp::v4());
|
||||
udp_socket.open(boost::asio::ip::udp::v4());
|
||||
|
||||
BOOST_CHECK(bt::is_stream_handle(socket_to_handle(tcp_socket.native_handle()), ec)); BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
BOOST_CHECK(bt::is_stream_handle(socket_to_handle(udp_socket.native_handle()), ec)); BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
BOOST_CHECK(bt::is_stream_handle(std::move(ap).sink(). native_handle(), ec)); BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
BOOST_CHECK(bt::is_stream_handle(std::move(ap).source().native_handle(), ec)); BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
}
|
||||
|
||||
struct on_setup_t
|
||||
{
|
||||
std::vector<bt::native_handle_type> &res;
|
||||
|
||||
on_setup_t(std::vector<bt::native_handle_type> & res) : res(res) {}
|
||||
template<typename Executor>
|
||||
void operator()(Executor & e)
|
||||
{
|
||||
bp::extend::foreach_used_handle(e, [this](bt::native_handle_type handle)
|
||||
{
|
||||
res.push_back(handle);
|
||||
std::cout << "Pushing " << handle << std::endl;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_CASE(iterate_handles, *boost::unit_test::timeout(5))
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
|
||||
std::vector<bt::native_handle_type> res;
|
||||
|
||||
bp::pipe p_in;
|
||||
bp::pipe p_out;
|
||||
|
||||
auto source = p_in.native_source();
|
||||
auto sink = p_out.native_sink();
|
||||
std::error_code ec;
|
||||
|
||||
BOOST_WARN_NE(source, sink); //Sanity check
|
||||
|
||||
const auto ret = bp::system(master_test_suite().argv[1], "--exit-code" , "42",
|
||||
bp::std_in < p_out,
|
||||
bp::std_out > p_in,
|
||||
bp::extend::on_setup(on_setup_t(res)), ec);
|
||||
|
||||
BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
|
||||
BOOST_CHECK_EQUAL(ret, 42);
|
||||
BOOST_CHECK_EQUAL(std::count(res.begin(), res.end(), p_in. native_sink()), 0);
|
||||
BOOST_CHECK_EQUAL(std::count(res.begin(), res.end(), p_out.native_source()), 0);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(limit_fd, *boost::unit_test::timeout(5))
|
||||
{
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
const auto get_handle = [](FILE * f){return std::to_string(_get_osfhandle(_fileno(f)));};
|
||||
#else
|
||||
const auto get_handle = [](FILE * f){return std::to_string(fileno(f));};
|
||||
#endif
|
||||
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
BOOST_CHECK_EQUAL(bp::system(master_test_suite().argv[1], "--has-handle", get_handle(stdout), bp::std_err > stderr), EXIT_SUCCESS);
|
||||
BOOST_CHECK_EQUAL(bp::system(master_test_suite().argv[1], "--has-handle", get_handle(stderr), bp::std_err > stderr), EXIT_SUCCESS);
|
||||
|
||||
|
||||
BOOST_CHECK_EQUAL(bp::system(master_test_suite().argv[1], "--has-handle", get_handle(stdout), bp::std_err > stderr, bp::limit_handles), EXIT_FAILURE);
|
||||
BOOST_CHECK_EQUAL(bp::system(master_test_suite().argv[1], "--has-handle", get_handle(stderr), bp::std_err > stderr, bp::limit_handles), EXIT_SUCCESS);
|
||||
|
||||
}
|
||||
@@ -235,37 +235,4 @@ BOOST_AUTO_TEST_CASE(coverage, *boost::unit_test::timeout(5))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(stream_close, *boost::unit_test::timeout(5))
|
||||
{
|
||||
bp::pipe p;
|
||||
int i = 1234, j = 0;
|
||||
bp::opstream op{p};
|
||||
bp::ipstream ip{p};
|
||||
p.close();
|
||||
|
||||
op << i << " ";
|
||||
op.close();
|
||||
|
||||
ip >> j;
|
||||
|
||||
BOOST_CHECK_EQUAL(i, j);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(stream_close_scope, *boost::unit_test::timeout(5))
|
||||
{
|
||||
bp::pipe p;
|
||||
int i = 1234, j = 0;
|
||||
bp::ipstream ip;
|
||||
|
||||
{
|
||||
bp::opstream op{ip.pipe()};
|
||||
op << i << " ";
|
||||
}
|
||||
ip >> j;
|
||||
|
||||
BOOST_CHECK_EQUAL(i, j);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END();
|
||||
@@ -17,7 +17,6 @@
|
||||
#include <boost/range/algorithm_ext/push_back.hpp>
|
||||
#include <boost/lambda/lambda.hpp>
|
||||
#include <boost/process/environment.hpp>
|
||||
#include <boost/process/handles.hpp>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iterator>
|
||||
@@ -58,7 +57,6 @@ int main(int argc, char *argv[])
|
||||
("pwd", bool_switch())
|
||||
("query", value<std::string>())
|
||||
("stdin-to-stdout", bool_switch())
|
||||
("has-handle", value<std::uintptr_t>())
|
||||
#if defined(BOOST_POSIX_API)
|
||||
("posix-echo-one", value<std::vector<std::string> >()->multitoken())
|
||||
("posix-echo-two", value<std::vector<std::string> >()->multitoken());
|
||||
@@ -225,15 +223,5 @@ int main(int argc, char *argv[])
|
||||
std::cout << si.dwFlags << std::endl;
|
||||
}
|
||||
#endif
|
||||
else if (vm.count("has-handle"))
|
||||
{
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
const auto handle = reinterpret_cast<boost::this_process::native_handle_type>(vm["has-handle"].as<std::uintptr_t>());
|
||||
#else
|
||||
const auto handle = static_cast<boost::this_process::native_handle_type>(vm["has-handle"].as<std::uintptr_t>());
|
||||
#endif
|
||||
auto all_handles = boost::this_process::get_handles();
|
||||
return (std::find(all_handles.begin(), all_handles.end(), handle) != all_handles.end()) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -111,26 +111,4 @@ BOOST_AUTO_TEST_CASE(wait_until_ec)
|
||||
BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(wait_for_exit_before_timeout)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
|
||||
std::error_code ec;
|
||||
|
||||
auto launch_time = std::chrono::system_clock::now();
|
||||
bp::child c(
|
||||
master_test_suite().argv[1],
|
||||
bp::args+={"test", "--wait", "1"},
|
||||
ec
|
||||
);
|
||||
BOOST_REQUIRE(!ec);
|
||||
|
||||
BOOST_CHECK(c.wait_for(std::chrono::seconds(20)));
|
||||
|
||||
auto timeout_t = std::chrono::system_clock::now();
|
||||
|
||||
// check that we didn't wait the entire timeout period
|
||||
BOOST_CHECK_LT(std::chrono::duration_cast<std::chrono::seconds>(timeout_t - launch_time).count(), 20);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END();
|
||||
|
||||
Reference in New Issue
Block a user