2
0
mirror of https://github.com/boostorg/process.git synced 2026-01-20 04:42:24 +00:00

Compare commits

..

12 Commits

Author SHA1 Message Date
Klemens Morgenstern
9ed2fef8cd Fixed wrong type in probe_on_error on windows.
Closes #491.
2025-05-24 09:40:16 +08:00
Klemens Morgenstern
cd1621b197 fixed major resume/suspend typo
Closes #481.
2025-04-28 23:57:20 +08:00
Klemens Morgenstern
1baccf76cd pipe bindings use a type_trait. 2025-04-15 00:31:56 +08:00
Klemens Morgenstern
06595a2070 added BOOST_PROCESS_V2_DISABLE_SIGNALSET option 2025-04-14 23:55:23 +08:00
Klemens Morgenstern
7e712985c1 added BOOST_PROCESS_V2_PIPEFORK option 2025-04-14 23:55:23 +08:00
Klemens Morgenstern
da08060021 Set ENOTSUP when PROC_PPID_ONLY is undefined
closes #452
2025-04-14 23:54:14 +08:00
Klemens Morgenstern
afdbab734e Removed char_count
Closes #473
2025-04-14 23:53:30 +08:00
Klemens Morgenstern
9dcd1a2775 added duplication check for SIGINFO
Closes #474
2025-04-14 23:51:35 +08:00
Osyotr
5756891558 Fix wide strings conversion on POSIX
This commit effectively reverts #179 which shouldn't have been merged in the first place. See https://github.com/boostorg/filesystem/pull/163#issuecomment-786794483 for more info.
2025-04-14 23:49:00 +08:00
RK-BFX
1d6c9ed0ec Fix conflicting pipe name in independent plug-in DLLs
Include numerical representation of local static variable's address into the pipe name to discriminate Boost.Process instances in independent DLLs.

Fixes #476

Also (auto-)remove excessive concurrent empty lines.
2025-04-14 23:48:00 +08:00
Yury Bura
a941c8e89c Add BOOST_PROCESS_USE_STD_FS option 2025-04-14 23:46:36 +08:00
Klemens Morgenstern
89d2cc325a Update index.html
Fixes #479
2025-04-11 23:31:02 +08:00
20 changed files with 358 additions and 104 deletions

View File

@@ -7,6 +7,8 @@ cmake_minimum_required(VERSION 3.5...3.16)
project(boost_process VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
option(BOOST_PROCESS_USE_STD_FS "Use std::filesystem instead of Boost.Filesystem" OFF)
add_library(boost_process
src/detail/environment_posix.cpp
src/detail/environment_win.cpp
@@ -49,13 +51,14 @@ target_compile_definitions(boost_process
PRIVATE BOOST_PROCESS_SOURCE=1
)
if (BOOST_PROCESS_USE_STD_FS)
target_compile_definitions(boost_process PUBLIC BOOST_PROCESS_USE_STD_FS=1 )
if(BOOST_PROCESS_USE_STD_FS)
target_compile_definitions(boost_process PUBLIC BOOST_PROCESS_USE_STD_FS)
target_compile_features(boost_process PUBLIC cxx_std_17)
else()
target_link_libraries(boost_process PUBLIC Boost::filesystem)
endif()
if (WIN32)
if(WIN32)
target_link_libraries(boost_process PUBLIC ntdll shell32 advapi32 user32 ws2_32)
endif()

View File

@@ -31,6 +31,8 @@ inline std::string make_pipe_name()
static std::atomic_size_t cnt{0};
name += std::to_string(pid);
name += "_";
name += std::to_string(intptr_t(&cnt)); // to unclash Boost instances in plug-in DLLs
name += "_";
name += std::to_string(cnt++);
return name;
@@ -60,8 +62,6 @@ public:
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(const async_pipe& rhs);
async_pipe(async_pipe&& rhs) : _source(std::move(rhs._source)), _sink(std::move(rhs._sink))
{
@@ -153,7 +153,6 @@ public:
return _sink.write_some(buffers);
}
template<typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
{
@@ -281,7 +280,6 @@ async_pipe::async_pipe(const async_pipe& p) :
_sink. assign(sink);
}
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)
@@ -298,7 +296,6 @@ async_pipe::async_pipe(boost::asio::io_context & ios_source,
| FILE_FLAG_OVERLAPPED_, //write flag
0, private_ ? 1 : ::boost::winapi::PIPE_UNLIMITED_INSTANCES_, 8192, 8192, 0, nullptr);
if (source == boost::winapi::INVALID_HANDLE_VALUE_)
::boost::process::v1::detail::throw_last_error("create_named_pipe(" + name + ") failed");

View File

@@ -78,8 +78,9 @@ inline std::locale default_locale()
std::locale global_loc = std::locale();
return std::locale(global_loc, new std::codecvt_utf8<wchar_t>);
# else // Other POSIX
// Return a default locale object.
return std::locale();
// ISO C calls std::locale("") "the locale-specific native environment", and this
// locale is the default for many POSIX-based operating systems such as Linux.
return std::locale("");
# endif
}

View File

@@ -18,6 +18,8 @@
#else
#if defined(BOOST_PROCESS_V2_PDFORK)
#include <boost/process/v2/posix/pdfork_launcher.hpp>
#elif defined(BOOST_PROCESS_V2_PIPEFORK)
#include <boost/process/v2/posix/pipe_fork_launcher.hpp>
#else
#include <boost/process/v2/posix/default_launcher.hpp>
#endif
@@ -48,6 +50,8 @@ typedef windows::default_launcher default_process_launcher;
#else
#if defined(BOOST_PROCESS_V2_PDFORK)
typedef posix::pdfork_launcher default_process_launcher;
#elif defined(BOOST_PROCESS_V2_PIPEFORK)
typedef posix::pipe_fork_launcher default_process_launcher;
#else
typedef posix::default_launcher default_process_launcher;
#endif

View File

@@ -165,7 +165,7 @@ BOOST_PROCESS_V2_END_NAMESPACE
#include <sys/syscall.h>
#if defined(SYS_pidfd_open)
#if defined(SYS_pidfd_open) && !defined(BOOST_PROCESS_V2_DISABLE_PIDFD_OPEN)
#define BOOST_PROCESS_V2_PIDFD_OPEN 1
#define BOOST_PROCESS_V2_HAS_PROCESS_HANDLE 1
#endif

View File

@@ -255,7 +255,7 @@ struct basic_process_handle_fd
ec.clear();
exit_code = code;
}
return false;
return false;
}
bool running(native_exit_code_type &exit_code)

View File

@@ -18,19 +18,27 @@
#if defined(BOOST_PROCESS_V2_STANDALONE)
#include <asio/any_io_executor.hpp>
#include <asio/append.hpp>
#include <asio/associated_immediate_executor.hpp>
#include <asio/compose.hpp>
#include <asio/dispatch.hpp>
#include <asio/posix/basic_stream_descriptor.hpp>
#include <asio/post.hpp>
#include <asio/windows/signal_set.hpp>
#if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET)
#include <asio/signal_set.hpp>
#endif
#else
#include <boost/asio/any_io_executor.hpp>
#include <boost/asio/append.hpp>
#include <boost/asio/associated_immediate_executor.hpp>
#include <boost/asio/compose.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/asio/posix/basic_stream_descriptor.hpp>
#include <boost/asio/post.hpp>
#if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET)
#include <boost/asio/signal_set.hpp>
#endif
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
@@ -45,7 +53,7 @@ struct basic_process_handle_fd_or_signal
typedef Executor executor_type;
executor_type get_executor()
{ return signal_set_.get_executor(); }
{ return descriptor_.get_executor(); }
/// Rebinds the process_handle to another executor.
template<typename Executor1>
@@ -277,14 +285,13 @@ struct basic_process_handle_fd_or_signal
int res = ::waitpid(pid_, &code, WNOHANG);
if (res == -1)
ec = get_last_error();
else
ec.clear();
if (process_is_running(res))
else if (res == 0)
return true;
else
{
ec.clear();
exit_code = code;
}
return false;
}
@@ -311,12 +318,19 @@ struct basic_process_handle_fd_or_signal
struct basic_process_handle_fd_or_signal;
pid_type pid_ = -1;
net::posix::basic_stream_descriptor<Executor> descriptor_;
#if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET)
net::basic_signal_set<Executor> signal_set_{descriptor_.get_executor(), SIGCHLD};
#else
int signal_set_;
#endif
struct async_wait_op_
{
net::posix::basic_descriptor<Executor> &descriptor;
#if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET)
net::basic_signal_set<Executor> &handle;
#else
int dummy;
#endif
pid_type pid_;
bool needs_post = true;
@@ -343,35 +357,41 @@ struct basic_process_handle_fd_or_signal
if (!ec && (wait_res == 0))
{
needs_post = false;
if (descriptor.is_open())
descriptor.async_wait(
net::posix::descriptor_base::wait_read,
std::move(self));
{
needs_post = false;
descriptor.async_wait(
net::posix::descriptor_base::wait_read,
std::move(self));
return;
}
else
handle.async_wait(std::move(self));
return;
{
#if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET)
needs_post = false;
handle.async_wait(std::move(self));
return;
#else
BOOST_PROCESS_V2_ASSIGN_EC(ec, net::error::operation_not_supported);
#endif
}
}
struct completer
{
error_code ec;
native_exit_code_type code;
typename std::decay<Self>::type self;
void operator()()
{
self.complete(ec, code);
}
};
const auto exec = self.get_executor();
completer cpl{ec, exit_code, std::move(self)};
if (needs_post)
net::post(exec, std::move(cpl));
{
auto exec = net::get_associated_immediate_executor(self, descriptor.get_executor());
net::dispatch(exec, net::append(std::move(self), exit_code, ec));
}
else
net::dispatch(exec, std::move(cpl));
{
auto exec = net::get_associated_executor(self);
net::dispatch(exec, net::append(std::move(self), exit_code, ec));
}
}
template<typename Self>
void operator()(Self &&self, native_exit_code_type code, error_code ec)
{
self.complete(ec, code);
}
};
public:

View File

@@ -17,17 +17,25 @@
#if defined(BOOST_PROCESS_V2_STANDALONE)
#include <asio/any_io_executor.hpp>
#include <asio/append.hpp>
#include <asio/associated_immediate_executor.hpp>
#include <asio/compose.hpp>
#include <asio/dispatch.hpp>
#include <asio/post.hpp>
#if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET)
#include <asio/signal_set.hpp>
#endif
#else
#include <boost/asio/any_io_executor.hpp>
#include <boost/asio/append.hpp>
#include <boost/asio/associated_immediate_executor.hpp>
#include <boost/asio/compose.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/asio/post.hpp>
#if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET)
#include <boost/asio/signal_set.hpp>
#endif
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
@@ -86,9 +94,14 @@ struct basic_process_handle_signal
basic_process_handle_signal& operator=(basic_process_handle_signal && handle)
{
pid_ = handle.id();
#if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET)
signal_set_.~basic_signal_set();
using ss = net::basic_signal_set<Executor>;
new (&signal_set_) ss(handle.get_executor(), SIGCHLD);
#else
signal_set_.executor = handle.signal_set_.executor;
#endif
handle.pid_ = -1;
return *this;
}
@@ -244,11 +257,13 @@ struct basic_process_handle_signal
int res = ::waitpid(pid_, &code, WNOHANG);
if (res == -1)
ec = get_last_error();
if (res == 0)
else if (res == 0)
return true;
else
{
ec.clear();
exit_code = code;
}
return false;
}
@@ -273,10 +288,24 @@ struct basic_process_handle_signal
template<typename>
friend struct basic_process_handle_signal;
pid_type pid_ = -1;
#if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET)
net::basic_signal_set<Executor> signal_set_;
#else
struct signal_set_dummy_
{
signal_set_dummy_(signal_set_dummy_ &&) = default;
signal_set_dummy_(const signal_set_dummy_ &) = default;
Executor executor;
using executor_type = Executor;
executor_type get_executor() {return executor;}
signal_set_dummy_(Executor executor, int) : executor(std::move(executor)) {}
};
signal_set_dummy_ signal_set_;
#endif
struct async_wait_op_
{
#if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET)
net::basic_signal_set<Executor> &handle;
pid_type pid_;
@@ -315,20 +344,25 @@ struct basic_process_handle_signal
return;
}
struct completer
{
error_code ec;
native_exit_code_type code;
typename std::decay<Self>::type self;
void operator()()
{
self.complete(ec, code);
}
};
const auto exec = self.get_executor();
net::dispatch(exec, completer{ec, exit_code, std::move(self)});
net::dispatch(exec, net::append(std::move(self), exit_code, ec));
}
#else
signal_set_dummy_ dummy_;
pid_t pid;
template<typename Self>
void operator()(Self &&self)
{
auto exec = net::get_associated_immediate_executor(self, dummy_.get_executor());
error_code ec;
BOOST_PROCESS_V2_ASSIGN_EC(ec, net::error::operation_not_supported);
net::dispatch(exec, net::append(std::move(self), native_exit_code_type(), ec));
}
#endif
template<typename Self>
void operator()(Self &&self, native_exit_code_type code, error_code ec)
{
self.complete(ec, code);
}
};
public:

View File

@@ -0,0 +1,185 @@
// Copyright (c) 2022 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_V2_POSIX_PIPE_FORK_LAUNCHER_HPP
#define BOOST_PROCESS_V2_POSIX_PIPE_FORK_LAUNCHER_HPP
#include <boost/process/v2/posix/default_launcher.hpp>
#include <unistd.h>
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace posix
{
/// A launcher using `pipe_fork`. Default on FreeBSD
struct pipe_fork_launcher : default_launcher
{
/// The file descriptor of the subprocess. Set after fork.
pipe_fork_launcher() = default;
template<typename ExecutionContext, typename Args, typename ... Inits>
auto operator()(ExecutionContext & context,
const typename std::enable_if<is_convertible<
ExecutionContext&, net::execution_context&>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<typename ExecutionContext::executor_type>
{
error_code ec;
auto proc = (*this)(context, ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
if (ec)
v2::detail::throw_error(ec, "pipe_fork_launcher");
return proc;
}
template<typename ExecutionContext, typename Args, typename ... Inits>
auto operator()(ExecutionContext & context,
error_code & ec,
const typename std::enable_if<is_convertible<
ExecutionContext&, net::execution_context&>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<typename ExecutionContext::executor_type>
{
return (*this)(context.get_executor(), ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
}
template<typename Executor, typename Args, typename ... Inits>
auto operator()(Executor exec,
const typename std::enable_if<
net::execution::is_executor<Executor>::value ||
net::is_executor<Executor>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<Executor>
{
error_code ec;
auto proc = (*this)(std::move(exec), ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
if (ec)
v2::detail::throw_error(ec, "pipe_fork_launcher");
return proc;
}
template<typename Executor, typename Args, typename ... Inits>
auto operator()(Executor exec,
error_code & ec,
const typename std::enable_if<
net::execution::is_executor<Executor>::value ||
net::is_executor<Executor>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<Executor>
{
auto argv = this->build_argv_(executable, std::forward<Args>(args));
int fd = -1;
{
pipe_guard pg, pg_wait;
if (::pipe(pg.p))
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
return basic_process<Executor>{exec};
}
if (::fcntl(pg.p[1], F_SETFD, FD_CLOEXEC))
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
return basic_process<Executor>{exec};
}
if (::pipe(pg_wait.p))
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
return basic_process<Executor>{exec};
}
if (::fcntl(pg_wait.p[1], F_SETFD, FD_CLOEXEC))
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
return basic_process<Executor>{exec};
}
ec = detail::on_setup(*this, executable, argv, inits ...);
if (ec)
{
detail::on_error(*this, executable, argv, ec, inits...);
return basic_process<Executor>(exec);
}
fd_whitelist.push_back(pg.p[1]);
fd_whitelist.push_back(pg_wait.p[1]);
auto & ctx = net::query(
exec, net::execution::context);
ctx.notify_fork(net::execution_context::fork_prepare);
pid = ::fork();
if (pid == -1)
{
ctx.notify_fork(net::execution_context::fork_parent);
detail::on_fork_error(*this, executable, argv, ec, inits...);
detail::on_error(*this, executable, argv, ec, inits...);
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
return basic_process<Executor>{exec};
}
else if (pid == 0)
{
ctx.notify_fork(net::execution_context::fork_child);
::close(pg.p[0]);
ec = detail::on_exec_setup(*this, executable, argv, inits...);
if (!ec)
{
close_all_fds(ec);
}
if (!ec)
::execve(executable.c_str(), const_cast<char * const *>(argv), const_cast<char * const *>(env));
default_launcher::ignore_unused(::write(pg.p[1], &errno, sizeof(int)));
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
detail::on_exec_error(*this, executable, argv, ec, inits...);
::exit(EXIT_FAILURE);
return basic_process<Executor>{exec};
}
ctx.notify_fork(net::execution_context::fork_parent);
::close(pg.p[1]);
pg.p[1] = -1;
::close(pg_wait.p[1]);
pg_wait.p[1] = -1;
int child_error{0};
int count = -1;
while ((count = ::read(pg.p[0], &child_error, sizeof(child_error))) == -1)
{
int err = errno;
if ((err != EAGAIN) && (err != EINTR))
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, err, system_category());
break;
}
}
if (count != 0)
BOOST_PROCESS_V2_ASSIGN_EC(ec, child_error, system_category());
if (ec)
{
detail::on_error(*this, executable, argv, ec, inits...);
return basic_process<Executor>{exec};
}
std::swap(fd, pg_wait.p[0]);
}
basic_process<Executor> proc(exec, pid, fd);
detail::on_success(*this, executable, argv, ec, inits...);
return proc;
}
};
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_POSIX_PIPE_FORK_LAUNCHER_HPP

View File

@@ -231,7 +231,7 @@ struct basic_process
void resume()
{
error_code ec;
suspend(ec);
resume(ec);
if (ec)
detail::throw_error(ec, "resume");
}

View File

@@ -13,7 +13,7 @@
#if defined(BOOST_PROCESS_V2_PIDFD_OPEN)
#include <boost/process/v2/detail/process_handle_fd.hpp>
#elif defined(BOOST_PROCESS_V2_PDFORK)
#elif defined(BOOST_PROCESS_V2_PDFORK) || defined(BOOST_PROCESS_V2_PIPEFORK)
#include <boost/process/v2/detail/process_handle_fd_or_signal.hpp>
#else
// with asio support we could use EVFILT_PROC:NOTE_EXIT as well.
@@ -107,9 +107,9 @@ struct basic_process_handle
void request_exit()
/// Unconditionally terminates the process and stores the exit code in exit_status.
void terminate(native_exit_code_type &exit_status, error_code &ec);\
void terminate(native_exit_code_type &exit_status, error_code &ec);
/// Throwing @overload void terminate(native_exit_code_type &exit_code, error_code & ec)
void terminate(native_exit_code_type &exit_status);/
void terminate(native_exit_code_type &exit_status);
/// Checks if the current process is running.
/**If it has already completed, it assigns the exit code to `exit_code`.
@@ -137,7 +137,7 @@ using basic_process_handle = detail::basic_process_handle_win<Executor>;
#if defined(BOOST_PROCESS_V2_PIDFD_OPEN)
template<typename Executor = net::any_io_executor>
using basic_process_handle = detail::basic_process_handle_fd<Executor>;
#elif defined(BOOST_PROCESS_V2_PDFORK) || defined(BOOST_PROCESS_V2_PIPE_LAUNCHER)
#elif defined(BOOST_PROCESS_V2_PDFORK) || defined(BOOST_PROCESS_V2_PIPEFORK)
template<typename Executor = net::any_io_executor>
using basic_process_handle = detail::basic_process_handle_fd_or_signal<Executor>;
#else

View File

@@ -31,8 +31,33 @@
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
template<typename T>
struct is_readable_pipe : std::false_type
{
};
template<typename Executor>
struct is_readable_pipe<asio::basic_readable_pipe<Executor>> : std::true_type
{
};
template<typename T>
struct is_writable_pipe : std::false_type
{
};
template<typename Executor>
struct is_writable_pipe<asio::basic_writable_pipe<Executor>> : std::true_type
{
};
namespace detail
{
#if defined(BOOST_PROCESS_V2_WINDOWS)
struct handle_closer
@@ -104,16 +129,10 @@ struct process_io_binding
}
template<typename Executor>
process_io_binding(net::basic_readable_pipe<Executor> & pipe)
template<typename ReadablePipe>
process_io_binding(ReadablePipe & readable_pipe,
typename std::enable_if<is_readable_pipe<ReadablePipe>::value && Target != STDIN_FILENO>::type * = nullptr)
{
if (Target == STD_INPUT_HANDLE)
{
auto h_ = pipe.native_handle();
h = std::unique_ptr<void, handle_closer>{h_, get_flags(h_)};
return ;
}
net::detail::native_pipe_handle p[2];
error_code ec;
net::detail::create_pipe(p, ec);
@@ -125,15 +144,10 @@ struct process_io_binding
}
template<typename Executor>
process_io_binding(net::basic_writable_pipe<Executor> & pipe)
template<typename WritablePipe>
process_io_binding(WritablePipe & writable_pipe,
typename std::enable_if<is_writable_pipe<WritablePipe>::value && Target == STDIN_FILENO>::type * = nullptr)
{
if (Target != STD_INPUT_HANDLE)
{
auto h_ = pipe.native_handle();
h = std::unique_ptr<void, handle_closer>{h_, get_flags(h_)};
return ;
}
net::detail::native_pipe_handle p[2];
error_code ec;
net::detail::create_pipe(p, ec);
@@ -207,15 +221,10 @@ struct process_io_binding
{
}
template<typename Executor>
process_io_binding(net::basic_readable_pipe<Executor> & readable_pipe)
template<typename ReadablePipe>
process_io_binding(ReadablePipe & readable_pipe,
typename std::enable_if<is_readable_pipe<ReadablePipe>::value && Target != STDIN_FILENO>::type * = nullptr)
{
if (Target == STDIN_FILENO)
{
fd = readable_pipe.native_handle();
return ;
}
net::detail::native_pipe_handle p[2];
net::detail::create_pipe(p, ec);
if (ec)
@@ -232,15 +241,10 @@ struct process_io_binding
}
template<typename Executor>
process_io_binding(net::basic_writable_pipe<Executor> & writable_pipe)
template<typename WritablePipe>
process_io_binding(WritablePipe & writable_pipe,
typename std::enable_if<is_writable_pipe<WritablePipe>::value && Target == STDIN_FILENO>::type * = nullptr)
{
if (Target != STDIN_FILENO)
{
fd = writable_pipe.native_handle();
return ;
}
net::detail::native_pipe_handle p[2];
error_code ec;
net::detail::create_pipe(p, ec);

View File

@@ -109,7 +109,7 @@ inline std::false_type probe_on_error(
template<typename Launcher, typename Init>
inline auto probe_on_error(Launcher & launcher, Init && init, derived && )
-> std::is_same<error_code, decltype(init.on_error(launcher, std::declval<const filesystem::path &>(), std::declval<std::wstring &>(), std::declval<std::error_code&>()))>;
-> std::is_same<error_code, decltype(init.on_error(launcher, std::declval<const filesystem::path &>(), std::declval<std::wstring &>(), std::declval<error_code&>()))>;
template<typename Launcher, typename Init>
using has_on_error = decltype(probe_on_error(std::declval<Launcher&>(), std::declval<Init>(), derived{}));

View File

@@ -10,7 +10,7 @@
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="refresh" content="0; url=../../doc/html/process.html">
<meta http-equiv="refresh" content="0; url=doc/html/index.html">
<title>Boost.Process</title>
<style>
body {
@@ -26,7 +26,7 @@
<body>
<p>
Automatic redirection failed, please go to
<a href="../../doc/html/process.html">../../doc/html/process.html</a>
<a href="doc/html/index.html">doc/html/index.html</a>
</p>
<p>
&copy; 2016 Klemens D. Morgenstern

View File

@@ -210,10 +210,8 @@ std::size_t size_as_wide(const char * in, std::size_t size, error_code &)
const auto from = in;
const auto from_end = from + size;
const char * from_next = from;
std::size_t char_count = 0u;
while (from_next < from_end)
{
++char_count;
unsigned int octet_count = get_octet_count(*from_next);
// The buffer may represent incomplete characters, so terminate early if one is found
if (octet_count > static_cast<std::size_t>(from_end - from_next))

View File

@@ -100,7 +100,7 @@ struct exit_code_category final : public error_category
# if defined(SIGILL)
case SIGILL: return "SIGILL: Illegal Instruction";
# endif
# if defined(SIGINFO)
# if defined(SIGINFO) && SIGINFO != SIGPWR
case SIGINFO: return "SIGINFO: A synonym for SIGPWR";
# endif
# if defined(SIGINT)

View File

@@ -178,6 +178,8 @@ pid_type parent_pid(pid_type pid, error_code & ec)
std::vector<pid_type> child_pids(pid_type pid, error_code & ec)
{
std::vector<pid_type> vec;
#if defined(PROC_PPID_ONLY)
vec.resize(proc_listpids(PROC_PPID_ONLY, (uint32_t)pid, nullptr, 0) / sizeof(pid_type));
const auto sz = proc_listpids(PROC_PPID_ONLY, (uint32_t)pid, &vec[0], sizeof(pid_type) * vec.size());
if (sz < 0)
@@ -186,6 +188,9 @@ std::vector<pid_type> child_pids(pid_type pid, error_code & ec)
return {};
}
vec.resize(sz);
#else
BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOTSUP, system_category());
#endif
return vec;
}

View File

@@ -11,6 +11,7 @@
#include <boost/process/v2/pid.hpp>
#include <boost/process/v2/process.hpp>
#include <boost/process/v2/start_dir.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_SUITE(ext)

View File

@@ -7,6 +7,8 @@
#include <boost/process/v2/pid.hpp>
#include <boost/process/v2/process.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/test/unit_test.hpp>
#include <algorithm>

View File

@@ -725,7 +725,7 @@ BOOST_AUTO_TEST_CASE(async_cancel_wait)
proc.async_wait(asio::cancel_after(std::chrono::milliseconds(100),
[&](boost::system::error_code ec, int)
{
BOOST_CHECK(ec == asio::error::operation_aborted);
BOOST_CHECK_EQUAL(ec, asio::error::operation_aborted);
BOOST_CHECK(proc.running());
if (proc.running())
proc.terminate();