mirror of
https://github.com/boostorg/process.git
synced 2026-01-23 05:42:28 +00:00
Compare commits
50 Commits
noexcept
...
cmd-empty-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
743f0cca35 | ||
|
|
81ad643b00 | ||
|
|
6fd1200ab7 | ||
|
|
c7bdccd57e | ||
|
|
d6bcb0014a | ||
|
|
e5f0f245bd | ||
|
|
a4a3770501 | ||
|
|
1e5892b8fb | ||
|
|
85b29d6442 | ||
|
|
b9ee759365 | ||
|
|
f3b163a933 | ||
|
|
be2ae2c3cf | ||
|
|
b2f5ebc760 | ||
|
|
e34557faa0 | ||
|
|
a9f083f45c | ||
|
|
b5ab94c932 | ||
|
|
9ceda79fa2 | ||
|
|
68cbeae491 | ||
|
|
ae778f36a8 | ||
|
|
0671e4a133 | ||
|
|
cbf944c57b | ||
|
|
5f2b8c53f4 | ||
|
|
dac3614a38 | ||
|
|
2fc71ca0a3 | ||
|
|
404682d75d | ||
|
|
9fbbdc3421 | ||
|
|
3df0009a2f | ||
|
|
ecb384b253 | ||
|
|
05bce942c1 | ||
|
|
dcf5d8ce41 | ||
|
|
4209f8ee6e | ||
|
|
d9513269cc | ||
|
|
293f28dab6 | ||
|
|
fe1b629b5d | ||
|
|
278fa57214 | ||
|
|
1addfba12e | ||
|
|
4cc469b2a4 | ||
|
|
6e4d1e29d2 | ||
|
|
dada865fd0 | ||
|
|
380dd1b00f | ||
|
|
7832cb6af3 | ||
|
|
68f4c50be9 | ||
|
|
cd226a7616 | ||
|
|
4243ce72f8 | ||
|
|
9065833e61 | ||
|
|
7cb7af6c8b | ||
|
|
90cbe7cec0 | ||
|
|
df33c1ad7b | ||
|
|
bbabea30dd | ||
|
|
8a61f8daa3 |
@@ -7,11 +7,8 @@
|
|||||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_SIGCHLD_SERVICE_HPP_
|
#ifndef BOOST_PROCESS_DETAIL_POSIX_SIGCHLD_SERVICE_HPP_
|
||||||
#define BOOST_PROCESS_DETAIL_POSIX_SIGCHLD_SERVICE_HPP_
|
#define BOOST_PROCESS_DETAIL_POSIX_SIGCHLD_SERVICE_HPP_
|
||||||
|
|
||||||
#include <boost/asio/bind_executor.hpp>
|
|
||||||
#include <boost/asio/dispatch.hpp>
|
#include <boost/asio/dispatch.hpp>
|
||||||
#include <boost/asio/post.hpp>
|
#include <boost/asio/post.hpp>
|
||||||
#include <boost/asio/consign.hpp>
|
|
||||||
#include <boost/asio/append.hpp>
|
|
||||||
#include <boost/asio/signal_set.hpp>
|
#include <boost/asio/signal_set.hpp>
|
||||||
#include <boost/asio/strand.hpp>
|
#include <boost/asio/strand.hpp>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
@@ -29,43 +26,6 @@ class sigchld_service : public boost::asio::detail::service_base<sigchld_service
|
|||||||
|
|
||||||
std::list<std::pair<::pid_t, std::function<void(int, std::error_code)>>> _receivers;
|
std::list<std::pair<::pid_t, std::function<void(int, std::error_code)>>> _receivers;
|
||||||
inline void _handle_signal(const boost::system::error_code & ec);
|
inline void _handle_signal(const boost::system::error_code & ec);
|
||||||
|
|
||||||
struct initiate_async_wait_op
|
|
||||||
{
|
|
||||||
sigchld_service * self;
|
|
||||||
template<typename Initiation>
|
|
||||||
void operator()(Initiation && init, ::pid_t pid)
|
|
||||||
{
|
|
||||||
// check if the child actually is running first
|
|
||||||
int status;
|
|
||||||
auto pid_res = ::waitpid(pid, &status, WNOHANG);
|
|
||||||
if (pid_res < 0)
|
|
||||||
{
|
|
||||||
auto ec = get_last_error();
|
|
||||||
boost::asio::post(
|
|
||||||
self->_strand,
|
|
||||||
asio::append(std::forward<Initiation>(init), pid_res, ec));
|
|
||||||
}
|
|
||||||
else if ((pid_res == pid) && (WIFEXITED(status) || WIFSIGNALED(status)))
|
|
||||||
boost::asio::post(
|
|
||||||
self->_strand,
|
|
||||||
boost::asio::append(std::forward<Initiation>(init), status, std::error_code{}));
|
|
||||||
else //still running
|
|
||||||
{
|
|
||||||
sigchld_service * self_ = self;
|
|
||||||
if (self->_receivers.empty())
|
|
||||||
self->_signal_set.async_wait(
|
|
||||||
boost::asio::bind_executor(
|
|
||||||
self->_strand,
|
|
||||||
[self_](const boost::system::error_code &ec, int)
|
|
||||||
{
|
|
||||||
self_->_handle_signal(ec);
|
|
||||||
}));
|
|
||||||
self->_receivers.emplace_back(pid, init);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
sigchld_service(boost::asio::io_context & io_context)
|
sigchld_service(boost::asio::io_context & io_context)
|
||||||
: boost::asio::detail::service_base<sigchld_service>(io_context)
|
: boost::asio::detail::service_base<sigchld_service>(io_context)
|
||||||
@@ -77,10 +37,47 @@ public:
|
|||||||
void (int, std::error_code))
|
void (int, std::error_code))
|
||||||
async_wait(::pid_t pid, SignalHandler && handler)
|
async_wait(::pid_t pid, SignalHandler && handler)
|
||||||
{
|
{
|
||||||
return boost::asio::async_initiate<
|
boost::asio::async_completion<
|
||||||
SignalHandler,
|
SignalHandler, void(boost::system::error_code)> init{handler};
|
||||||
void(int, std::error_code)>(
|
|
||||||
initiate_async_wait_op{this}, handler, pid);
|
auto & h = init.completion_handler;
|
||||||
|
boost::asio::dispatch(
|
||||||
|
_strand,
|
||||||
|
[this, pid, h]
|
||||||
|
{
|
||||||
|
//check if the child actually is running first
|
||||||
|
int status;
|
||||||
|
auto pid_res = ::waitpid(pid, &status, WNOHANG);
|
||||||
|
if (pid_res < 0)
|
||||||
|
{
|
||||||
|
auto ec = get_last_error();
|
||||||
|
boost::asio::post(
|
||||||
|
_strand,
|
||||||
|
[pid_res, ec, h]
|
||||||
|
{
|
||||||
|
h(pid_res, ec);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if ((pid_res == pid) && (WIFEXITED(status) || WIFSIGNALED(status)))
|
||||||
|
boost::asio::post(
|
||||||
|
_strand,
|
||||||
|
[status, h]
|
||||||
|
{
|
||||||
|
h(status, {}); //successfully exited already
|
||||||
|
});
|
||||||
|
else //still running
|
||||||
|
{
|
||||||
|
if (_receivers.empty())
|
||||||
|
_signal_set.async_wait(
|
||||||
|
[this](const boost::system::error_code &ec, int)
|
||||||
|
{
|
||||||
|
boost::asio::dispatch(_strand, [this, ec]{this->_handle_signal(ec);});
|
||||||
|
});
|
||||||
|
_receivers.emplace_back(pid, h);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return init.result.get();
|
||||||
}
|
}
|
||||||
void shutdown() override
|
void shutdown() override
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -488,7 +488,7 @@ struct key
|
|||||||
using string_type = std::basic_string<char_type, traits_type>;
|
using string_type = std::basic_string<char_type, traits_type>;
|
||||||
using string_view_type = basic_string_view<char_type, traits_type>;
|
using string_view_type = basic_string_view<char_type, traits_type>;
|
||||||
|
|
||||||
key() {}
|
key() noexcept = default;
|
||||||
key( const key& p ) = default;
|
key( const key& p ) = default;
|
||||||
key( key&& p ) noexcept = default;
|
key( key&& p ) noexcept = default;
|
||||||
key( const string_type& source ) : value_(source) {}
|
key( const string_type& source ) : value_(source) {}
|
||||||
@@ -524,11 +524,7 @@ struct key
|
|||||||
~key() = default;
|
~key() = default;
|
||||||
|
|
||||||
key& operator=( const key& p ) = default;
|
key& operator=( const key& p ) = default;
|
||||||
key& operator=( key&& p )
|
key& operator=( key&& p ) noexcept(std::is_nothrow_move_constructible<string_type>::value) = default;
|
||||||
{
|
|
||||||
value_ = std::move(p.value_);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
key& operator=( string_type&& source )
|
key& operator=( string_type&& source )
|
||||||
{
|
{
|
||||||
value_ = std::move(source);
|
value_ = std::move(source);
|
||||||
@@ -712,7 +708,7 @@ struct value
|
|||||||
using string_type = std::basic_string<char_type, traits_type>;
|
using string_type = std::basic_string<char_type, traits_type>;
|
||||||
using string_view_type = basic_cstring_ref<char_type, traits_type>;
|
using string_view_type = basic_cstring_ref<char_type, traits_type>;
|
||||||
|
|
||||||
value() {}
|
value() noexcept = default;
|
||||||
value( const value& p ) = default;
|
value( const value& p ) = default;
|
||||||
|
|
||||||
value( const string_type& source ) : value_(source) {}
|
value( const string_type& source ) : value_(source) {}
|
||||||
@@ -746,11 +742,7 @@ struct value
|
|||||||
~value() = default;
|
~value() = default;
|
||||||
|
|
||||||
value& operator=( const value& p ) = default;
|
value& operator=( const value& p ) = default;
|
||||||
value& operator=( value&& p )
|
value& operator=( value&& p ) noexcept(std::is_nothrow_move_constructible<string_type>::value) = default;
|
||||||
{
|
|
||||||
value_ = std::move(p.value_);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
value& operator=( string_type&& source )
|
value& operator=( string_type&& source )
|
||||||
{
|
{
|
||||||
value_ = std::move(source);
|
value_ = std::move(source);
|
||||||
@@ -943,7 +935,7 @@ struct key_value_pair
|
|||||||
using string_type = std::basic_string<char_type>;
|
using string_type = std::basic_string<char_type>;
|
||||||
using string_view_type = basic_cstring_ref<char_type>;
|
using string_view_type = basic_cstring_ref<char_type>;
|
||||||
|
|
||||||
key_value_pair() {}
|
key_value_pair() noexcept = default;
|
||||||
key_value_pair( const key_value_pair& p ) = default;
|
key_value_pair( const key_value_pair& p ) = default;
|
||||||
key_value_pair( key_value_pair&& p ) noexcept = default;
|
key_value_pair( key_value_pair&& p ) noexcept = default;
|
||||||
key_value_pair(key_view key, value_view value) : value_(key.basic_string<char_type, traits_type>() + equality_sign +
|
key_value_pair(key_view key, value_view value) : value_(key.basic_string<char_type, traits_type>() + equality_sign +
|
||||||
@@ -1007,11 +999,7 @@ struct key_value_pair
|
|||||||
~key_value_pair() = default;
|
~key_value_pair() = default;
|
||||||
|
|
||||||
key_value_pair& operator=( const key_value_pair& p ) = default;
|
key_value_pair& operator=( const key_value_pair& p ) = default;
|
||||||
key_value_pair& operator=( key_value_pair&& p )
|
key_value_pair& operator=( key_value_pair&& p ) noexcept(std::is_nothrow_move_constructible<string_type>::value) = default;
|
||||||
{
|
|
||||||
value_ = std::move(p.value_);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
key_value_pair& operator=( string_type&& source )
|
key_value_pair& operator=( string_type&& source )
|
||||||
{
|
{
|
||||||
value_ = std::move(source);
|
value_ = std::move(source);
|
||||||
|
|||||||
@@ -147,14 +147,15 @@ std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec)
|
|||||||
std::vector<pid_type> all_pids(boost::system::error_code & ec)
|
std::vector<pid_type> all_pids(boost::system::error_code & ec)
|
||||||
{
|
{
|
||||||
std::vector<pid_type> vec;
|
std::vector<pid_type> vec;
|
||||||
vec.resize(proc_listpids(PROC_ALL_PIDS, 0, nullptr, 0) / sizeof(pid_type));
|
vec.reserve(proc_listpids(PROC_ALL_PIDS, 0, nullptr, 0));
|
||||||
const auto sz = proc_listpids(PROC_ALL_PIDS, 0, &vec[0], sizeof(pid_type) * vec.size());
|
if (proc_listpids(PROC_ALL_PIDS, 0, &vec[0], sizeof(pid_type) * vec.size()))
|
||||||
if (sz < 0)
|
|
||||||
{
|
{
|
||||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
vec.resize(sz);
|
auto itr = std::partition(vec.begin(), vec.end(), [](pid_type pt) {return pt != 0;});
|
||||||
|
vec.erase(itr, vec.end());
|
||||||
|
std::reverse(vec.begin(), vec.end());
|
||||||
return vec;
|
return vec;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,14 +176,15 @@ pid_type parent_pid(pid_type pid, boost::system::error_code & ec)
|
|||||||
std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec)
|
std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec)
|
||||||
{
|
{
|
||||||
std::vector<pid_type> vec;
|
std::vector<pid_type> vec;
|
||||||
vec.resize(proc_listpids(PROC_PPID_ONLY, (uint32_t)pid, nullptr, 0) / sizeof(pid_type));
|
vec.reserve(proc_listpids(PROC_PPID_ONLY, (uint32_t)pid, nullptr, 0));
|
||||||
const auto sz = proc_listpids(PROC_PPID_ONLY, (uint32_t)pid, &vec[0], sizeof(pid_type) * vec.size());
|
if (proc_listpids(PROC_PPID_ONLY, (uint32_t)pid, &vec[0], sizeof(pid_type) * vec.size()))
|
||||||
if (sz < 0)
|
|
||||||
{
|
{
|
||||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
vec.resize(sz);
|
auto itr = std::partition(vec.begin(), vec.end(), [](pid_type pt) {return pt != 0;});
|
||||||
|
vec.erase(itr, vec.end());
|
||||||
|
std::reverse(vec.begin(), vec.end());
|
||||||
return vec;
|
return vec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ BOOST_AUTO_TEST_CASE(multithreaded_async_pipe)
|
|||||||
asio::io_context ioc;
|
asio::io_context ioc;
|
||||||
|
|
||||||
std::vector<std::thread> threads;
|
std::vector<std::thread> threads;
|
||||||
for (auto i = 0u; i < std::thread::hardware_concurrency(); i++)
|
for (int i = 0; i < std::thread::hardware_concurrency(); i++)
|
||||||
{
|
{
|
||||||
threads.emplace_back([&ioc]
|
threads.emplace_back([&ioc]
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(wait_group_test, *boost::unit_test::timeout(5))
|
|||||||
BOOST_CHECK_MESSAGE(!ec, ec.message());
|
BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||||
BOOST_REQUIRE(c2.in_group(ec));
|
BOOST_REQUIRE(c2.in_group(ec));
|
||||||
BOOST_CHECK_MESSAGE(!ec, ec.message());
|
BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||||
g.wait(ec);
|
g.wait();
|
||||||
|
|
||||||
BOOST_CHECK(!c1.running());
|
BOOST_CHECK(!c1.running());
|
||||||
BOOST_CHECK(!c2.running());
|
BOOST_CHECK(!c2.running());
|
||||||
|
|||||||
@@ -59,11 +59,11 @@ test-suite standalone :
|
|||||||
[ run utf8.cpp test_impl ]
|
[ run utf8.cpp test_impl ]
|
||||||
[ run cstring_ref.cpp test_impl ]
|
[ run cstring_ref.cpp test_impl ]
|
||||||
[ run environment.cpp test_impl ]
|
[ run environment.cpp test_impl ]
|
||||||
|
[ run pid.cpp test_impl : : : <target-os>darwin:<build>no ]
|
||||||
[ run shell.cpp test_impl ]
|
[ run shell.cpp test_impl ]
|
||||||
;
|
;
|
||||||
|
|
||||||
test-suite with_target :
|
test-suite with_target :
|
||||||
[ run pid.cpp test_impl : --log_level=all --catch_system_errors=no -- : target ]
|
|
||||||
[ run process.cpp test_impl : --log_level=all --catch_system_errors=no -- : target ]
|
[ run process.cpp test_impl : --log_level=all --catch_system_errors=no -- : target ]
|
||||||
[ run windows.cpp test_impl : --log_level=all --catch_system_errors=no -- : target : <build>no <target-os>windows:<build>yes <target-os>windows:<source>Advapi32 ]
|
[ run windows.cpp test_impl : --log_level=all --catch_system_errors=no -- : target : <build>no <target-os>windows:<build>yes <target-os>windows:<source>Advapi32 ]
|
||||||
[ run ext.cpp test_impl : --log_level=all --catch_system_errors=no -- : target : <target-os>darwin:<build>no ]
|
[ run ext.cpp test_impl : --log_level=all --catch_system_errors=no -- : target : <target-os>darwin:<build>no ]
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ BOOST_AUTO_TEST_CASE(cmd_exe)
|
|||||||
BOOST_CHECK_EQUAL(bp2::detail::conv_string<char>(ref.data(), ref.size()), pth);
|
BOOST_CHECK_EQUAL(bp2::detail::conv_string<char>(ref.data(), ref.size()), pth);
|
||||||
|
|
||||||
BOOST_REQUIRE_EQUAL(cm.argc(), args.size() + 1);
|
BOOST_REQUIRE_EQUAL(cm.argc(), args.size() + 1);
|
||||||
for (auto i = 0u; i < args.size(); i++)
|
for (auto i = 0; i < args.size(); i++)
|
||||||
{
|
{
|
||||||
ref = cm.argv()[i + 1];
|
ref = cm.argv()[i + 1];
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,10 @@
|
|||||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
#include <boost/process/v2/pid.hpp>
|
#include <boost/process/v2/pid.hpp>
|
||||||
#include <boost/process/v2/process.hpp>
|
|
||||||
|
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <thread>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_pid)
|
BOOST_AUTO_TEST_CASE(test_pid)
|
||||||
@@ -24,30 +22,21 @@ BOOST_AUTO_TEST_CASE(test_pid)
|
|||||||
BOOST_CHECK_GT(all.size(), 0u);
|
BOOST_CHECK_GT(all.size(), 0u);
|
||||||
BOOST_CHECK(itr != all.end());
|
BOOST_CHECK(itr != all.end());
|
||||||
|
|
||||||
|
std::vector<bp2::pid_type> children, grand_children;
|
||||||
|
auto grand_child_pids = [](bp2::pid_type pid,
|
||||||
|
std::vector<bp2::pid_type> & children,
|
||||||
|
std::vector<bp2::pid_type> & grand_children)
|
||||||
|
{
|
||||||
|
children = bp2::child_pids(pid);
|
||||||
|
for (unsigned i = 0; i < children.size(); i++)
|
||||||
|
{
|
||||||
|
std::vector<bp2::pid_type> tmp1;
|
||||||
|
std::vector<bp2::pid_type> tmp2 = bp2::child_pids(children[i]);
|
||||||
|
tmp1.insert(std::end(tmp1), std::begin(tmp2), std::end(tmp2));
|
||||||
|
grand_children = tmp1;
|
||||||
|
}
|
||||||
|
return (!children.empty() || !grand_children.empty());
|
||||||
|
};
|
||||||
|
BOOST_CHECK_NE(grand_child_pids(bp2::root_pid, children, grand_children), false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(child_pid)
|
|
||||||
{
|
|
||||||
namespace bp2 = boost::process::v2;
|
|
||||||
|
|
||||||
using boost::unit_test::framework::master_test_suite;
|
|
||||||
const auto pth = bp2::filesystem::absolute(master_test_suite().argv[1]);
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
|
||||||
|
|
||||||
auto cs = bp2::child_pids(bp2::current_pid());
|
|
||||||
boost::asio::io_context ctx;
|
|
||||||
bp2::process proc(ctx, pth, {"sleep", "50000"});
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
|
||||||
auto c2 = bp2::child_pids(bp2::current_pid());
|
|
||||||
BOOST_CHECK_LT(cs.size(), c2.size());
|
|
||||||
BOOST_CHECK(std::find(cs.begin(), cs.end(), proc.id()) == cs.end());
|
|
||||||
BOOST_CHECK(std::find(c2.begin(), c2.end(), proc.id()) != c2.end());
|
|
||||||
proc.terminate();
|
|
||||||
proc.wait();
|
|
||||||
|
|
||||||
auto c3 = bp2::child_pids(bp2::current_pid());
|
|
||||||
BOOST_CHECK(std::find(c3.begin(), c3.end(), proc.id()) == c3.end());
|
|
||||||
BOOST_CHECK_LT(c3.size(), c2.size());
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user