整理
This commit is contained in:
182
include/boost/process/v2/detail/config.hpp
Normal file
182
include/boost/process/v2/detail/config.hpp
Normal file
@@ -0,0 +1,182 @@
|
||||
// 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_DETAIL_CONFIG_HPP
|
||||
#define BOOST_PROCESS_V2_DETAIL_CONFIG_HPP
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_STANDALONE)
|
||||
|
||||
#define BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(Sig) ASIO_COMPLETION_TOKEN_FOR(Sig)
|
||||
|
||||
#include <asio/detail/config.hpp>
|
||||
#include <system_error>
|
||||
#include <filesystem>
|
||||
#include <string_view>
|
||||
#include <iomanip>
|
||||
#include <optional>
|
||||
|
||||
#if defined(ASIO_WINDOWS)
|
||||
#define BOOST_PROCESS_V2_WINDOWS 1
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(ASIO_HAS_UNISTD_H)
|
||||
#define BOOST_PROCESS_V2_POSIX 1
|
||||
#endif
|
||||
|
||||
#define BOOST_PROCESS_V2_BEGIN_NAMESPACE namespace process_v2 {
|
||||
#define BOOST_PROCESS_V2_END_NAMESPACE }
|
||||
#define BOOST_PROCESS_V2_NAMESPACE process_v2
|
||||
|
||||
namespace asio {}
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
namespace net = ::asio;
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(Sig) BOOST_ASIO_COMPLETION_TOKEN_FOR(Sig)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/io/quoted.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/system/system_category.hpp>
|
||||
#include <boost/system/system_error.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
#define BOOST_PROCESS_V2_WINDOWS 1
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#define BOOST_PROCESS_V2_POSIX 1
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_PROCESS_V2_WINDOWS) && !defined(BOOST_POSIX_API)
|
||||
#error Unsupported operating system
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_PROCESS_USE_STD_FS)
|
||||
#include <filesystem>
|
||||
#else
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(BOOST_PROCESS_VERSION)
|
||||
#define BOOST_PROCESS_VERSION 2
|
||||
#endif
|
||||
|
||||
|
||||
#if BOOST_PROCESS_VERSION == 1
|
||||
#define BOOST_PROCESS_V2_BEGIN_NAMESPACE namespace boost { namespace process { namespace v2 {
|
||||
#else
|
||||
#define BOOST_PROCESS_V2_BEGIN_NAMESPACE namespace boost { namespace process { inline namespace v2 {
|
||||
#endif
|
||||
|
||||
#define BOOST_PROCESS_V2_END_NAMESPACE } } }
|
||||
#define BOOST_PROCESS_V2_NAMESPACE boost::process::v2
|
||||
|
||||
namespace boost { namespace asio {} }
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
namespace net = ::boost::asio;
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
#if defined(BOOST_PROCESS_STANDALONE)
|
||||
|
||||
using std::error_code ;
|
||||
using std::error_category ;
|
||||
using std::system_category ;
|
||||
using std::system_error ;
|
||||
namespace filesystem = std::filesystem;
|
||||
using std::quoted;
|
||||
using std::optional;
|
||||
|
||||
#define BOOST_PROCESS_V2_ASSIGN_EC(ec, ...) ec.assign(__VA_ARGS__);
|
||||
#define BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) \
|
||||
ec.assign(::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error()); \
|
||||
|
||||
|
||||
#else
|
||||
|
||||
using boost::system::error_code ;
|
||||
using boost::system::error_category ;
|
||||
using boost::system::system_category ;
|
||||
using boost::system::system_error ;
|
||||
using boost::io::quoted;
|
||||
using boost::optional;
|
||||
|
||||
#ifdef BOOST_PROCESS_USE_STD_FS
|
||||
namespace filesystem = std::filesystem;
|
||||
#else
|
||||
namespace filesystem = boost::filesystem;
|
||||
#endif
|
||||
|
||||
#define BOOST_PROCESS_V2_ASSIGN_EC(ec, ...) \
|
||||
do \
|
||||
{ \
|
||||
static constexpr auto loc##__LINE__((BOOST_CURRENT_LOCATION)); \
|
||||
ec.assign(__VA_ARGS__, &loc##__LINE__); \
|
||||
} \
|
||||
while (false)
|
||||
|
||||
#define BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) \
|
||||
do \
|
||||
{ \
|
||||
static constexpr auto loc##__LINE__((BOOST_CURRENT_LOCATION)); \
|
||||
ec.assign(::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error(), &loc##__LINE__); \
|
||||
} \
|
||||
while (false)
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_PROCESS_DYN_LINK)
|
||||
#if defined(BOOST_PROCESS_SOURCE)
|
||||
#define BOOST_PROCESS_V2_DECL BOOST_SYMBOL_EXPORT
|
||||
#else
|
||||
#define BOOST_PROCESS_V2_DECL BOOST_SYMBOL_IMPORT
|
||||
#endif
|
||||
#else
|
||||
#define BOOST_PROCESS_V2_DECL
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_PROCESS_SOURCE) && !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_PROCESS_NO_LIB)
|
||||
#define BOOST_LIB_NAME boost_process
|
||||
#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_PROCESS_DYN_LINK)
|
||||
#define BOOST_DYN_LINK
|
||||
#endif
|
||||
#include <boost/config/auto_link.hpp>
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_POSIX)
|
||||
|
||||
#if defined(__linux__) && !defined(BOOST_PROCESS_V2_DISABLE_PIDFD_OPEN)
|
||||
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#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
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__) && defined(BOOST_PROCESS_V2_ENABLE_PDFORK)
|
||||
#define BOOST_PROCESS_V2_PDFORK 1
|
||||
#define BOOST_PROCESS_V2_HAS_PROCESS_HANDLE 1
|
||||
#endif
|
||||
#else
|
||||
#define BOOST_PROCESS_V2_HAS_PROCESS_HANDLE 1
|
||||
#endif
|
||||
|
||||
#endif //BOOST_PROCESS_V2_DETAIL_CONFIG_HPP
|
||||
90
include/boost/process/v2/detail/environment_posix.hpp
Normal file
90
include/boost/process/v2/detail/environment_posix.hpp
Normal file
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// process/environment/detail/environment_posix.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2021 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
|
||||
//
|
||||
// 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_DETAIL_ENVIRONMENT_POSIX_HPP
|
||||
#define BOOST_PROCESS_V2_DETAIL_ENVIRONMENT_POSIX_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/cstring_ref.hpp>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# include <crt_externs.h>
|
||||
# if !defined(environ)
|
||||
# define environ (*_NSGetEnviron())
|
||||
# endif
|
||||
#elif defined(__MACH__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__sun)
|
||||
extern "C" { extern char **environ; }
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace environment
|
||||
{
|
||||
|
||||
using char_type = char;
|
||||
|
||||
template<typename Char>
|
||||
using key_char_traits = std::char_traits<Char>;
|
||||
|
||||
template<typename Char>
|
||||
using value_char_traits = std::char_traits<Char>;
|
||||
|
||||
|
||||
constexpr char_type equality_sign = '=';
|
||||
constexpr char_type delimiter = ':';
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
BOOST_PROCESS_V2_DECL
|
||||
basic_cstring_ref<char_type, value_char_traits<char>>
|
||||
get(basic_cstring_ref<char_type, key_char_traits<char_type>> key, error_code & ec);
|
||||
|
||||
BOOST_PROCESS_V2_DECL
|
||||
void set(basic_cstring_ref<char_type, key_char_traits<char_type>> key,
|
||||
basic_cstring_ref<char_type, value_char_traits<char_type>> value,
|
||||
error_code & ec);
|
||||
|
||||
BOOST_PROCESS_V2_DECL
|
||||
void unset(basic_cstring_ref<char_type, key_char_traits<char_type>> key,
|
||||
error_code & ec);
|
||||
}
|
||||
|
||||
|
||||
using native_handle_type = const char * const *;
|
||||
using native_iterator = native_handle_type;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
BOOST_PROCESS_V2_DECL native_handle_type load_native_handle();
|
||||
struct native_handle_deleter
|
||||
{
|
||||
void operator()(native_handle_type) const {}
|
||||
};
|
||||
|
||||
BOOST_PROCESS_V2_DECL native_iterator next(native_handle_type nh);
|
||||
BOOST_PROCESS_V2_DECL native_iterator find_end(native_handle_type nh);
|
||||
inline const char_type * dereference(native_iterator iterator) {return *iterator;}
|
||||
|
||||
BOOST_PROCESS_V2_DECL bool has_x_access(const char * pth);
|
||||
|
||||
inline bool is_executable(const filesystem::path & pth, error_code & ec)
|
||||
{
|
||||
return filesystem::is_regular_file(pth, ec) && has_x_access(pth.c_str());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif
|
||||
220
include/boost/process/v2/detail/environment_win.hpp
Normal file
220
include/boost/process/v2/detail/environment_win.hpp
Normal file
@@ -0,0 +1,220 @@
|
||||
//
|
||||
// process/environment/detail/environment_win.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2021 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
|
||||
//
|
||||
// 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_DETAIL_ENVIRONMENT_WIN_HPP
|
||||
#define BOOST_PROCESS_V2_DETAIL_ENVIRONMENT_WIN_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/cstring_ref.hpp>
|
||||
|
||||
#include <cwctype>
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace environment
|
||||
{
|
||||
|
||||
using char_type = wchar_t;
|
||||
|
||||
template<typename Char>
|
||||
struct key_char_traits
|
||||
{
|
||||
typedef Char char_type;
|
||||
typedef typename std::char_traits<char_type>::int_type int_type;
|
||||
typedef typename std::char_traits<char_type>::off_type off_type;
|
||||
typedef typename std::char_traits<char_type>::pos_type pos_type;
|
||||
typedef typename std::char_traits<char_type>::state_type state_type;
|
||||
|
||||
BOOST_CONSTEXPR static char to_lower(char c) {return std::tolower(to_int_type(c));}
|
||||
BOOST_CONSTEXPR static wchar_t to_lower(wchar_t c) {return std::towlower(to_int_type(c));}
|
||||
|
||||
BOOST_CONSTEXPR static int_type to_lower(int_type i, char ) {return std::tolower(i);}
|
||||
BOOST_CONSTEXPR static int_type to_lower(int_type i, wchar_t) {return std::towlower(i);}
|
||||
|
||||
|
||||
BOOST_CONSTEXPR static
|
||||
void assign(char_type& c1, const char_type& c2) BOOST_NOEXCEPT
|
||||
{
|
||||
c1 = c2;
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR static
|
||||
bool eq(char_type c1, char_type c2) BOOST_NOEXCEPT
|
||||
{
|
||||
return to_lower(c1) == to_lower(c2);
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR static
|
||||
bool lt(char_type c1, char_type c2) BOOST_NOEXCEPT
|
||||
{
|
||||
return to_lower(c1) < to_lower(c2);
|
||||
}
|
||||
|
||||
BOOST_CXX14_CONSTEXPR static
|
||||
int compare(const char_type* s1, const char_type* s2, size_t n) BOOST_NOEXCEPT
|
||||
{
|
||||
auto itrs = std::mismatch(s1, s1 + n, s2, &eq);
|
||||
if (itrs.first == (s1 + n))
|
||||
return 0;
|
||||
auto c1 = to_lower(*itrs.first);
|
||||
auto c2 = to_lower(*itrs.second);
|
||||
|
||||
return (c1 < c2 ) ? -1 : 1;
|
||||
}
|
||||
|
||||
static size_t length(const char* s) BOOST_NOEXCEPT { return std::strlen(s); }
|
||||
static size_t length(const wchar_t* s) BOOST_NOEXCEPT { return std::wcslen(s); }
|
||||
|
||||
BOOST_CXX14_CONSTEXPR static
|
||||
const char_type* find(const char_type* s, size_t n, const char_type& a) BOOST_NOEXCEPT
|
||||
{
|
||||
const char_type u = to_lower(a);
|
||||
return std::find_if(s, s + n, [u](char_type c){return to_lower(c) == u;});
|
||||
}
|
||||
|
||||
BOOST_CXX14_CONSTEXPR static
|
||||
char_type* move(char_type* s1, const char_type* s2, size_t n) BOOST_NOEXCEPT
|
||||
{
|
||||
if (s1 < s2)
|
||||
return std::move(s2, s2 + n, s1);
|
||||
else
|
||||
return std::move_backward(s2, s2 + n, s1 + n);
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR static
|
||||
char_type* copy(char_type* s1, const char_type* s2, size_t n) BOOST_NOEXCEPT
|
||||
{
|
||||
return std::copy(s2, s2 + n, s1);
|
||||
}
|
||||
|
||||
BOOST_CXX14_CONSTEXPR static
|
||||
char_type* assign(char_type* s, size_t n, char_type a) BOOST_NOEXCEPT
|
||||
{
|
||||
std::fill(s, s + n, a);
|
||||
return s +n;
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR static
|
||||
int_type not_eof(int_type c) BOOST_NOEXCEPT
|
||||
{
|
||||
return eq_int_type(c, eof()) ? ~eof() : c;
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR static
|
||||
char_type to_char_type(int_type c) BOOST_NOEXCEPT
|
||||
{
|
||||
return char_type(c);
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR static
|
||||
int_type to_int_type(char c) BOOST_NOEXCEPT
|
||||
{
|
||||
return int_type((unsigned char)c);
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR static
|
||||
int_type to_int_type(wchar_t c) BOOST_NOEXCEPT
|
||||
{
|
||||
return int_type((wchar_t)c);
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR static
|
||||
bool eq_int_type(int_type c1, int_type c2) BOOST_NOEXCEPT
|
||||
{
|
||||
return to_lower(c1, char_type()) == to_lower(c2, char_type());
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR static inline int_type eof() BOOST_NOEXCEPT
|
||||
{
|
||||
return int_type(EOF);
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
|
||||
template<typename Char>
|
||||
std::size_t hash_step(std::size_t prev, Char c, key_char_traits<Char>)
|
||||
{
|
||||
return prev ^ (key_char_traits<Char>::to_lower(c) << 1);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
template<typename Char>
|
||||
using value_char_traits = std::char_traits<Char>;
|
||||
|
||||
BOOST_CONSTEXPR static char_type equality_sign = L'=';
|
||||
BOOST_CONSTEXPR static char_type delimiter = L';';
|
||||
|
||||
using native_handle_type = wchar_t*;
|
||||
using native_iterator = const wchar_t*;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
BOOST_PROCESS_V2_DECL
|
||||
std::basic_string<wchar_t, value_char_traits<wchar_t>> get(
|
||||
basic_cstring_ref<wchar_t, key_char_traits<wchar_t>> key,
|
||||
error_code & ec);
|
||||
|
||||
BOOST_PROCESS_V2_DECL
|
||||
void set(basic_cstring_ref<wchar_t, key_char_traits<wchar_t>> key,
|
||||
basic_cstring_ref<wchar_t, value_char_traits<wchar_t>> value,
|
||||
error_code & ec);
|
||||
|
||||
BOOST_PROCESS_V2_DECL
|
||||
void unset(basic_cstring_ref<wchar_t, key_char_traits<wchar_t>> key,
|
||||
error_code & ec);
|
||||
|
||||
|
||||
BOOST_PROCESS_V2_DECL
|
||||
std::basic_string<char, value_char_traits<char>> get(
|
||||
basic_cstring_ref<char, key_char_traits<char>> key,
|
||||
error_code & ec);
|
||||
|
||||
BOOST_PROCESS_V2_DECL
|
||||
void set(basic_cstring_ref<char, key_char_traits<char>> key,
|
||||
basic_cstring_ref<char, value_char_traits<char>> value,
|
||||
error_code & ec);
|
||||
|
||||
BOOST_PROCESS_V2_DECL
|
||||
void unset(basic_cstring_ref<char, key_char_traits<char>> key,
|
||||
error_code & ec);
|
||||
|
||||
BOOST_PROCESS_V2_DECL native_handle_type load_native_handle();
|
||||
struct native_handle_deleter
|
||||
{
|
||||
native_handle_deleter() = default;
|
||||
native_handle_deleter(const native_handle_deleter& ) = default;
|
||||
BOOST_PROCESS_V2_DECL void operator()(native_handle_type nh) const;
|
||||
|
||||
};
|
||||
|
||||
inline const char_type * dereference(native_iterator iterator) {return iterator;}
|
||||
BOOST_PROCESS_V2_DECL native_iterator next(native_iterator nh);
|
||||
BOOST_PROCESS_V2_DECL native_iterator find_end(native_handle_type nh);
|
||||
|
||||
|
||||
BOOST_PROCESS_V2_DECL bool is_exec_type(const wchar_t * pth);
|
||||
|
||||
inline bool is_executable(const filesystem::path & pth, error_code & ec)
|
||||
{
|
||||
return filesystem::is_regular_file(pth, ec) && is_exec_type(pth.c_str());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif //BOOST_PROCESS_V2_DETAIL_ENVIRONMENT_WIN_HPP
|
||||
22
include/boost/process/v2/detail/last_error.hpp
Normal file
22
include/boost/process/v2/detail/last_error.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
// 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_DETAIL_LAST_ERROR_HPP
|
||||
#define BOOST_PROCESS_V2_DETAIL_LAST_ERROR_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
BOOST_PROCESS_V2_DECL error_code get_last_error();
|
||||
|
||||
}
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
|
||||
#endif //BOOST_PROCESS_V2_DETAIL_LAST_ERROR_HPP
|
||||
355
include/boost/process/v2/detail/process_handle_fd.hpp
Normal file
355
include/boost/process/v2/detail/process_handle_fd.hpp
Normal file
@@ -0,0 +1,355 @@
|
||||
|
||||
// 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_DETAIL_PROCESS_HANDLE_FD_HPP
|
||||
#define BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_FD_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
#include <boost/process/v2/exit_code.hpp>
|
||||
#include <boost/process/v2/pid.hpp>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_STANDALONE)
|
||||
#include <asio/any_io_executor.hpp>
|
||||
#include <asio/compose.hpp>
|
||||
#include <asio/posix/basic_stream_descriptor.hpp>
|
||||
#include <asio/post.hpp>
|
||||
#else
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
#include <boost/asio/compose.hpp>
|
||||
#include <boost/asio/posix/basic_stream_descriptor.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename Executor = net::any_io_executor>
|
||||
struct basic_process_handle_fd
|
||||
{
|
||||
using native_handle_type = int;
|
||||
|
||||
typedef Executor executor_type;
|
||||
|
||||
executor_type get_executor()
|
||||
{ return descriptor_.get_executor(); }
|
||||
|
||||
/// Rebinds the process_handle to another executor.
|
||||
template<typename Executor1>
|
||||
struct rebind_executor
|
||||
{
|
||||
/// The socket type when rebound to the specified executor.
|
||||
typedef basic_process_handle_fd<Executor1> other;
|
||||
};
|
||||
|
||||
template<typename ExecutionContext>
|
||||
basic_process_handle_fd(ExecutionContext &context,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<ExecutionContext &,
|
||||
net::execution_context &>::value>::type * = nullptr)
|
||||
: pid_(-1), descriptor_(context)
|
||||
{
|
||||
}
|
||||
|
||||
basic_process_handle_fd(executor_type executor)
|
||||
: pid_(-1), descriptor_(executor)
|
||||
{
|
||||
}
|
||||
|
||||
basic_process_handle_fd(executor_type executor, pid_type pid)
|
||||
: pid_(pid), descriptor_(executor, syscall(SYS_pidfd_open, pid, 0))
|
||||
{
|
||||
if (descriptor_.native_handle() == -1)
|
||||
detail::throw_error(detail::get_last_error(), "wait(pid)");
|
||||
}
|
||||
|
||||
basic_process_handle_fd(executor_type executor, pid_type pid, native_handle_type process_handle)
|
||||
: pid_(pid), descriptor_(executor, process_handle)
|
||||
{
|
||||
}
|
||||
|
||||
basic_process_handle_fd(basic_process_handle_fd &&handle)
|
||||
: pid_(handle.pid_), descriptor_(std::move(handle.descriptor_))
|
||||
{
|
||||
handle.pid_ = -1;
|
||||
}
|
||||
|
||||
template<typename Executor1>
|
||||
basic_process_handle_fd(basic_process_handle_fd<Executor1> &&handle)
|
||||
: pid_(handle.pid_), descriptor_(std::move(handle.descriptor_))
|
||||
{
|
||||
handle.pid_ = -1;
|
||||
}
|
||||
|
||||
|
||||
basic_process_handle_fd& operator=(basic_process_handle_fd &&handle)
|
||||
{
|
||||
pid_ = handle.pid_;
|
||||
descriptor_ = std::move(handle.descriptor_);
|
||||
handle.pid_ = -1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
pid_type id() const
|
||||
{ return pid_; }
|
||||
|
||||
native_handle_type native_handle() {return pid_;}
|
||||
|
||||
void terminate_if_running(error_code &)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
if (::waitpid(pid_, nullptr, WNOHANG) == 0)
|
||||
{
|
||||
::kill(pid_, SIGKILL);
|
||||
::waitpid(pid_, nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void terminate_if_running()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
if (::waitpid(pid_, nullptr, WNOHANG) == 0)
|
||||
{
|
||||
::kill(pid_, SIGKILL);
|
||||
::waitpid(pid_, nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void wait(native_exit_code_type &exit_status, error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
while (::waitpid(pid_, &exit_status, 0) < 0)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
{
|
||||
ec = get_last_error();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wait(native_exit_code_type &exit_status)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
error_code ec;
|
||||
wait(exit_status, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "wait(pid)");
|
||||
}
|
||||
|
||||
void interrupt(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
if (::kill(pid_, SIGINT) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void interrupt()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
error_code ec;
|
||||
interrupt(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "interrupt");
|
||||
}
|
||||
|
||||
void request_exit(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
if (::kill(pid_, SIGTERM) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void request_exit()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
error_code ec;
|
||||
request_exit(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "request_exit");
|
||||
}
|
||||
|
||||
void suspend()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "suspend");
|
||||
}
|
||||
|
||||
void suspend(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
if (::kill(pid_, SIGSTOP) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void resume()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
error_code ec;
|
||||
resume(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "resume");
|
||||
}
|
||||
|
||||
void resume(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
if (::kill(pid_, SIGCONT) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
void terminate(native_exit_code_type &exit_status, error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
if (::kill(pid_, SIGKILL) == -1)
|
||||
ec = get_last_error();
|
||||
else
|
||||
wait(exit_status, ec);
|
||||
}
|
||||
|
||||
void terminate(native_exit_code_type &exit_status)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
error_code ec;
|
||||
terminate(exit_status, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "terminate");
|
||||
}
|
||||
|
||||
bool running(native_exit_code_type &exit_code, error_code & ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return false;
|
||||
int code = 0;
|
||||
int res = ::waitpid(pid_, &code, WNOHANG);
|
||||
if (res == -1)
|
||||
ec = get_last_error();
|
||||
else if (res == 0)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
ec.clear();
|
||||
exit_code = code;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool running(native_exit_code_type &exit_code)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return false;
|
||||
|
||||
error_code ec;
|
||||
bool res = running(exit_code, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "is_running");
|
||||
return res;
|
||||
}
|
||||
|
||||
bool is_open() const
|
||||
{
|
||||
return pid_ != -1;
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename>
|
||||
friend
|
||||
struct basic_process_handle_fd;
|
||||
pid_type pid_ = -1;
|
||||
net::posix::basic_stream_descriptor<Executor> descriptor_;
|
||||
|
||||
struct async_wait_op_
|
||||
{
|
||||
net::posix::basic_descriptor<Executor> &descriptor;
|
||||
pid_type pid_;
|
||||
native_exit_code_type & exit_code;
|
||||
template<typename Self>
|
||||
void operator()(Self &&self)
|
||||
{
|
||||
self.reset_cancellation_state(asio::enable_total_cancellation());
|
||||
error_code ec;
|
||||
int wait_res = -1;
|
||||
if (pid_ <= 0) // error, complete early
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, net::error::bad_descriptor);
|
||||
else if (process_is_running(exit_code))
|
||||
{
|
||||
wait_res = ::waitpid(pid_, &exit_code, WNOHANG);
|
||||
if (wait_res == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
if (!ec && (wait_res == 0))
|
||||
{
|
||||
descriptor.async_wait(net::posix::descriptor_base::wait_read, std::move(self));
|
||||
return;
|
||||
}
|
||||
|
||||
struct completer
|
||||
{
|
||||
error_code ec;
|
||||
typename std::decay<Self>::type self;
|
||||
|
||||
void operator()()
|
||||
{
|
||||
self.complete(ec);
|
||||
}
|
||||
};
|
||||
net::dispatch(
|
||||
net::get_associated_immediate_executor(self, descriptor.get_executor()),
|
||||
completer{ec, std::move(self)});
|
||||
|
||||
}
|
||||
|
||||
template<typename Self>
|
||||
void operator()(Self &&self, error_code ec, int = 0)
|
||||
{
|
||||
if (!ec && process_is_running(exit_code))
|
||||
if (::waitpid(pid_, &exit_code, 0) == -1)
|
||||
ec = get_last_error();
|
||||
std::move(self).complete(ec);
|
||||
}
|
||||
};
|
||||
public:
|
||||
|
||||
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code))
|
||||
WaitHandler = net::default_completion_token_t<executor_type>>
|
||||
auto async_wait(native_exit_code_type & exit_code,
|
||||
WaitHandler &&handler = net::default_completion_token_t<executor_type>())
|
||||
-> decltype(net::async_compose<WaitHandler, void(error_code)>(
|
||||
async_wait_op_{descriptor_, pid_, exit_code}, handler, descriptor_))
|
||||
{
|
||||
return net::async_compose<WaitHandler, void(error_code)>(
|
||||
async_wait_op_{descriptor_, pid_, exit_code}, handler, descriptor_);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif //BOOST_PROCESS_HANDLE_FD_OR_SIGNAL_HPP
|
||||
413
include/boost/process/v2/detail/process_handle_fd_or_signal.hpp
Normal file
413
include/boost/process/v2/detail/process_handle_fd_or_signal.hpp
Normal file
@@ -0,0 +1,413 @@
|
||||
|
||||
// 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_DETAIL_PROCESS_HANDLE_FD_OR_SIGNAL_HPP
|
||||
#define BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_FD_OR_SIGNAL_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
#include <boost/process/v2/exit_code.hpp>
|
||||
#include <boost/process/v2/pid.hpp>
|
||||
|
||||
#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>
|
||||
#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
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename Executor = net::any_io_executor>
|
||||
struct basic_process_handle_fd_or_signal
|
||||
{
|
||||
using native_handle_type = int;
|
||||
|
||||
typedef Executor executor_type;
|
||||
|
||||
executor_type get_executor()
|
||||
{ return descriptor_.get_executor(); }
|
||||
|
||||
/// Rebinds the process_handle to another executor.
|
||||
template<typename Executor1>
|
||||
struct rebind_executor
|
||||
{
|
||||
/// The socket type when rebound to the specified executor.
|
||||
typedef basic_process_handle_fd_or_signal<Executor1> other;
|
||||
};
|
||||
|
||||
template<typename ExecutionContext>
|
||||
basic_process_handle_fd_or_signal(ExecutionContext &context,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<ExecutionContext &,
|
||||
net::execution_context &>::value
|
||||
>::type * = nullptr)
|
||||
: pid_(-1), descriptor_(context)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename ExecutionContext>
|
||||
basic_process_handle_fd_or_signal(ExecutionContext &context,
|
||||
pid_type pid,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<ExecutionContext &,
|
||||
net::execution_context &>::value
|
||||
>::type * = nullptr)
|
||||
: pid_(pid), descriptor_(context)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename ExecutionContext>
|
||||
basic_process_handle_fd_or_signal(ExecutionContext &context,
|
||||
pid_type pid, native_handle_type process_handle,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<ExecutionContext &,
|
||||
net::execution_context &>::value
|
||||
>::type * = nullptr)
|
||||
: pid_(pid), descriptor_(context, process_handle)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
basic_process_handle_fd_or_signal(Executor executor)
|
||||
: pid_(-1), descriptor_(executor)
|
||||
{
|
||||
}
|
||||
|
||||
basic_process_handle_fd_or_signal(Executor executor, pid_type pid)
|
||||
: pid_(pid), descriptor_(executor)
|
||||
{
|
||||
}
|
||||
|
||||
basic_process_handle_fd_or_signal(Executor executor, pid_type pid, native_handle_type process_handle)
|
||||
: pid_(pid), descriptor_(executor, process_handle)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
basic_process_handle_fd_or_signal(basic_process_handle_fd_or_signal &&handle)
|
||||
: pid_(handle.pid_), descriptor_(std::move(handle.descriptor_))
|
||||
{
|
||||
handle.pid_ = -1;
|
||||
}
|
||||
// Warn: does not change the executor of the signal-set.
|
||||
basic_process_handle_fd_or_signal& operator=(basic_process_handle_fd_or_signal &&handle)
|
||||
{
|
||||
pid_ = handle.pid_;
|
||||
descriptor_ = std::move(handle.descriptor_);
|
||||
handle.pid_ = -1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
template<typename Executor1>
|
||||
basic_process_handle_fd_or_signal(basic_process_handle_fd_or_signal<Executor1> &&handle)
|
||||
: pid_(handle.pid_), descriptor_(std::move(handle.descriptor_))
|
||||
{
|
||||
handle.pid_ = -1;
|
||||
}
|
||||
|
||||
pid_type id() const
|
||||
{ return pid_; }
|
||||
native_handle_type native_handle() {return pid_;}
|
||||
|
||||
void terminate_if_running(error_code &)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
if (::waitpid(pid_, nullptr, WNOHANG) == 0)
|
||||
{
|
||||
::kill(pid_, SIGKILL);
|
||||
::waitpid(pid_, nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void terminate_if_running()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
if (::waitpid(pid_, nullptr, WNOHANG) == 0)
|
||||
{
|
||||
::kill(pid_, SIGKILL);
|
||||
::waitpid(pid_, nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void wait(native_exit_code_type &exit_status, error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
while (::waitpid(pid_, &exit_status, 0) < 0)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
{
|
||||
ec = get_last_error();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void wait(native_exit_code_type &exit_status)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
error_code ec;
|
||||
wait(exit_status, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "wait(pid)");
|
||||
}
|
||||
|
||||
void interrupt(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
if (::kill(pid_, SIGINT) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void interrupt()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
error_code ec;
|
||||
interrupt(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "interrupt");
|
||||
}
|
||||
|
||||
void request_exit(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
if (::kill(pid_, SIGTERM) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void request_exit()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
error_code ec;
|
||||
request_exit(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "request_exit");
|
||||
}
|
||||
|
||||
void suspend()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "suspend");
|
||||
}
|
||||
|
||||
void suspend(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
if (::kill(pid_, SIGSTOP) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void resume()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
error_code ec;
|
||||
resume(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "resume");
|
||||
}
|
||||
|
||||
void resume(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
if (::kill(pid_, SIGCONT) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void terminate(native_exit_code_type &exit_status, error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
if (::kill(pid_, SIGKILL) == -1)
|
||||
ec = get_last_error();
|
||||
else
|
||||
wait(exit_status, ec);
|
||||
}
|
||||
|
||||
void terminate(native_exit_code_type &exit_status)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
error_code ec;
|
||||
terminate(exit_status, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "terminate");
|
||||
}
|
||||
|
||||
bool running(native_exit_code_type &exit_code, error_code & ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return false;
|
||||
int code = 0;
|
||||
int res = ::waitpid(pid_, &code, WNOHANG);
|
||||
if (res == -1)
|
||||
ec = get_last_error();
|
||||
else if (res == 0)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
ec.clear();
|
||||
exit_code = code;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool running(native_exit_code_type &exit_code)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return false;
|
||||
|
||||
error_code ec;
|
||||
bool res = running(exit_code, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "is_running");
|
||||
return res;
|
||||
}
|
||||
|
||||
bool is_open() const
|
||||
{
|
||||
return pid_ != -1;
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename>
|
||||
friend
|
||||
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_;
|
||||
native_exit_code_type & exit_code;
|
||||
bool needs_post = true;
|
||||
|
||||
template<typename Self>
|
||||
void operator()(Self && self)
|
||||
{
|
||||
self.reset_cancellation_state(asio::enable_total_cancellation());
|
||||
(*this)(std::move(self), error_code{});
|
||||
}
|
||||
|
||||
template<typename Self>
|
||||
void operator()(Self &&self, error_code ec, int = 0)
|
||||
{
|
||||
int wait_res = -1;
|
||||
if (pid_ <= 0) // error, complete early
|
||||
ec = net::error::bad_descriptor;
|
||||
else if (process_is_running(exit_code))
|
||||
{
|
||||
wait_res = ::waitpid(pid_, &exit_code, WNOHANG);
|
||||
if (wait_res == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
if (!ec && (wait_res == 0))
|
||||
{
|
||||
if (descriptor.is_open())
|
||||
{
|
||||
needs_post = false;
|
||||
descriptor.async_wait(
|
||||
net::posix::descriptor_base::wait_read,
|
||||
std::move(self));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
#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
|
||||
}
|
||||
}
|
||||
|
||||
if (needs_post)
|
||||
{
|
||||
auto exec = net::get_associated_immediate_executor(self, descriptor.get_executor());
|
||||
net::dispatch(exec, net::append(std::move(self), exit_code, ec));
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
};
|
||||
public:
|
||||
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code))
|
||||
WaitHandler = net::default_completion_token_t<executor_type>>
|
||||
auto async_wait(native_exit_code_type & exit_code,
|
||||
WaitHandler &&handler = net::default_completion_token_t<executor_type>())
|
||||
-> decltype(net::async_compose<WaitHandler, void(error_code)>(
|
||||
async_wait_op_{descriptor_, signal_set_, pid_, exit_code}, handler, descriptor_))
|
||||
{
|
||||
return net::async_compose<WaitHandler, void(error_code)>(
|
||||
async_wait_op_{descriptor_, signal_set_, pid_, exit_code}, handler, descriptor_);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif //BOOST_PROCESS_HANDLE_FD_OR_SIGNAL_HPP
|
||||
387
include/boost/process/v2/detail/process_handle_signal.hpp
Normal file
387
include/boost/process/v2/detail/process_handle_signal.hpp
Normal file
@@ -0,0 +1,387 @@
|
||||
// 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_DETAIL_PROCESS_HANDLE_SIGNAL_HPP
|
||||
#define BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_SIGNAL_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
#include <boost/process/v2/exit_code.hpp>
|
||||
#include <boost/process/v2/pid.hpp>
|
||||
|
||||
#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
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename Executor = net::any_io_executor>
|
||||
struct basic_process_handle_signal
|
||||
{
|
||||
struct native_handle_type
|
||||
{
|
||||
native_handle_type() = delete;
|
||||
native_handle_type(const native_handle_type & ) = delete;
|
||||
~native_handle_type() = default;
|
||||
};
|
||||
|
||||
typedef Executor executor_type;
|
||||
|
||||
executor_type get_executor()
|
||||
{ return signal_set_.get_executor(); }
|
||||
|
||||
/// Rebinds the process_handle to another executor.
|
||||
template<typename Executor1>
|
||||
struct rebind_executor
|
||||
{
|
||||
/// The socket type when rebound to the specified executor.
|
||||
typedef basic_process_handle_signal<Executor1> other;
|
||||
};
|
||||
|
||||
template<typename ExecutionContext>
|
||||
basic_process_handle_signal(ExecutionContext &context,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<ExecutionContext &,
|
||||
net::execution_context &>::value
|
||||
>::type * = nullptr)
|
||||
: pid_(-1), signal_set_(context, SIGCHLD)
|
||||
{
|
||||
}
|
||||
|
||||
basic_process_handle_signal(Executor executor)
|
||||
: pid_(-1), signal_set_(executor, SIGCHLD)
|
||||
{
|
||||
}
|
||||
|
||||
basic_process_handle_signal(Executor executor, pid_type pid)
|
||||
: pid_(pid), signal_set_(executor, SIGCHLD)
|
||||
{
|
||||
}
|
||||
|
||||
basic_process_handle_signal(basic_process_handle_signal && handle)
|
||||
: pid_(handle.pid_), signal_set_(handle.signal_set_.get_executor(), SIGCHLD)
|
||||
{
|
||||
handle.pid_ = -1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
template<typename Executor1>
|
||||
basic_process_handle_signal(basic_process_handle_signal<Executor1> && handle)
|
||||
: pid_(handle.pid_), signal_set_(Executor1(handle.signal_set_.get_executor()), SIGCHLD)
|
||||
{
|
||||
handle.pid_ = -1;
|
||||
}
|
||||
|
||||
pid_type id() const { return pid_; }
|
||||
native_handle_type native_handle() {return {};}
|
||||
|
||||
void terminate_if_running(error_code &)
|
||||
{
|
||||
terminate_if_running();
|
||||
}
|
||||
|
||||
void terminate_if_running()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
if (::waitpid(pid_, nullptr, WNOHANG) == 0)
|
||||
{
|
||||
::kill(pid_, SIGKILL);
|
||||
::waitpid(pid_, nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void wait(native_exit_code_type &exit_status, error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
while (::waitpid(pid_, &exit_status, 0) < 0)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
{
|
||||
ec = get_last_error();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wait(native_exit_code_type &exit_status)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
error_code ec;
|
||||
wait(exit_status, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "wait(pid)");
|
||||
}
|
||||
|
||||
void interrupt(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
if (::kill(pid_, SIGINT) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void interrupt()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
error_code ec;
|
||||
interrupt(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "interrupt");
|
||||
}
|
||||
|
||||
void request_exit(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
if (::kill(pid_, SIGTERM) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void request_exit()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
error_code ec;
|
||||
request_exit(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "request_exit");
|
||||
}
|
||||
|
||||
void suspend()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "suspend");
|
||||
}
|
||||
|
||||
void suspend(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
if (::kill(pid_, SIGSTOP) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void resume()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
error_code ec;
|
||||
resume(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "resume");
|
||||
}
|
||||
|
||||
void resume(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
if (::kill(pid_, SIGCONT) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void terminate(native_exit_code_type &exit_status, error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
if (::kill(pid_, SIGKILL) == -1)
|
||||
ec = get_last_error();
|
||||
else
|
||||
wait(exit_status, ec);
|
||||
}
|
||||
|
||||
void terminate(native_exit_code_type &exit_status)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
error_code ec;
|
||||
terminate(exit_status, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "terminate");
|
||||
}
|
||||
|
||||
bool running(native_exit_code_type &exit_code, error_code & ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return false;
|
||||
int code = 0;
|
||||
int res = ::waitpid(pid_, &code, WNOHANG);
|
||||
if (res == -1)
|
||||
ec = get_last_error();
|
||||
else if (res == 0)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
ec.clear();
|
||||
exit_code = code;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool running(native_exit_code_type &exit_code)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return false;
|
||||
|
||||
error_code ec;
|
||||
bool res = running(exit_code, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "is_running");
|
||||
return res;
|
||||
}
|
||||
|
||||
bool is_open() const
|
||||
{
|
||||
return pid_ != -1;
|
||||
}
|
||||
|
||||
private:
|
||||
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_;
|
||||
native_exit_code_type & exit_code;
|
||||
|
||||
template<typename Self>
|
||||
void operator()(Self &&self)
|
||||
{
|
||||
self.reset_cancellation_state(asio::enable_total_cancellation());
|
||||
handle.async_wait(std::move(self));
|
||||
handle.cancel();
|
||||
// we cancel so we end up on the signal-sets executor
|
||||
}
|
||||
|
||||
template<typename Self>
|
||||
void operator()(Self &&self, error_code ec, int /*sig*/)
|
||||
{
|
||||
if (ec == net::error::operation_aborted &&
|
||||
self.get_cancellation_state().cancelled()
|
||||
== net::cancellation_type::none)
|
||||
ec.clear();
|
||||
|
||||
int wait_res = -1;
|
||||
|
||||
if (pid_ <= 0) // error, complete early
|
||||
ec = net::error::bad_descriptor;
|
||||
else if (!ec && process_is_running(exit_code))
|
||||
{
|
||||
wait_res = ::waitpid(pid_, &exit_code, WNOHANG);
|
||||
if (wait_res == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
if (!ec && (wait_res == 0))
|
||||
{
|
||||
handle.async_wait(std::move(self));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto exec = self.get_executor();
|
||||
net::dispatch(exec, net::append(std::move(self), 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, error_code ec)
|
||||
{
|
||||
self.complete(ec);
|
||||
}
|
||||
};
|
||||
public:
|
||||
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code))
|
||||
WaitHandler = net::default_completion_token_t<executor_type>>
|
||||
auto async_wait(native_exit_code_type & exit_code,
|
||||
WaitHandler &&handler = net::default_completion_token_t<executor_type>())
|
||||
-> decltype(net::async_compose<WaitHandler, void(error_code)>(
|
||||
async_wait_op_{signal_set_, pid_, exit_code}, handler, signal_set_))
|
||||
{
|
||||
return net::async_compose<WaitHandler, void(error_code)>(
|
||||
async_wait_op_{signal_set_, pid_, exit_code}, handler, signal_set_);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
|
||||
#endif //BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_SIGNAL_HPP
|
||||
326
include/boost/process/v2/detail/process_handle_windows.hpp
Normal file
326
include/boost/process/v2/detail/process_handle_windows.hpp
Normal file
@@ -0,0 +1,326 @@
|
||||
// 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_DETAIL_PROCESS_HANDLE_WINDOWS_HPP
|
||||
#define BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_WINDOWS_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
|
||||
#include <boost/process/v2/exit_code.hpp>
|
||||
#include <boost/process/v2/pid.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_STANDALONE)
|
||||
#include <asio/any_io_executor.hpp>
|
||||
#include <asio/compose.hpp>
|
||||
#include <asio/windows/basic_object_handle.hpp>
|
||||
#else
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
#include <boost/asio/compose.hpp>
|
||||
#include <boost/asio/windows/basic_object_handle.hpp>
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
BOOST_PROCESS_V2_DECL void get_exit_code_( void * handle, native_exit_code_type & exit_code, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void * open_process_(pid_type pid);
|
||||
BOOST_PROCESS_V2_DECL void terminate_if_running_(void * handle);
|
||||
BOOST_PROCESS_V2_DECL bool check_handle_(void* handle, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL bool check_pid_(pid_type pid_, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void interrupt_(pid_type pid_, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void suspend_(void * handle, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void resume_(void * handle, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void terminate_(void * handle, error_code & ec, native_exit_code_type & exit_code);
|
||||
BOOST_PROCESS_V2_DECL void request_exit_(pid_type pid_, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void check_running_(void* handle, error_code & ec, native_exit_code_type & exit_status);
|
||||
|
||||
template<typename Executor = net::any_io_executor>
|
||||
struct basic_process_handle_win
|
||||
{
|
||||
typedef net::windows::basic_object_handle<Executor> handle_type;
|
||||
typedef typename handle_type::native_handle_type native_handle_type;
|
||||
|
||||
typedef Executor executor_type;
|
||||
|
||||
executor_type get_executor()
|
||||
{ return handle_.get_executor(); }
|
||||
|
||||
/// Rebinds the process_handle to another executor.
|
||||
template<typename Executor1>
|
||||
struct rebind_executor
|
||||
{
|
||||
/// The socket type when rebound to the specified executor.
|
||||
typedef basic_process_handle_win<Executor1> other;
|
||||
};
|
||||
|
||||
template<typename ExecutionContext>
|
||||
basic_process_handle_win(ExecutionContext &context,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<ExecutionContext &,
|
||||
net::execution_context &>::value
|
||||
>::type = 0)
|
||||
: pid_(0), handle_(context)
|
||||
{
|
||||
}
|
||||
|
||||
basic_process_handle_win(Executor executor)
|
||||
: pid_(0), handle_(executor)
|
||||
{
|
||||
}
|
||||
|
||||
basic_process_handle_win(Executor executor, pid_type pid)
|
||||
: pid_(pid), handle_(executor, detail::open_process_(pid))
|
||||
{
|
||||
}
|
||||
|
||||
basic_process_handle_win(Executor executor, pid_type pid, native_handle_type process_handle)
|
||||
: pid_(pid), handle_(executor, process_handle)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
template<typename Executor1>
|
||||
basic_process_handle_win(basic_process_handle_win<Executor1> && other)
|
||||
: pid_(other.pid_), handle_(std::move(other.handle_))
|
||||
{
|
||||
other.pid_ = static_cast<DWORD>(-1);
|
||||
}
|
||||
|
||||
basic_process_handle_win(basic_process_handle_win && other)
|
||||
: pid_(other.pid_), handle_(std::move(other.handle_))
|
||||
{
|
||||
other.pid_ = static_cast<DWORD>(-1);
|
||||
}
|
||||
|
||||
basic_process_handle_win& operator=(basic_process_handle_win && other)
|
||||
{
|
||||
pid_ = other.pid_;
|
||||
handle_ = std::move(other.handle_);
|
||||
other.pid_ = static_cast<DWORD>(-1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Executor1>
|
||||
basic_process_handle_win& operator=(basic_process_handle_win<Executor1> && other)
|
||||
{
|
||||
pid_ = other.pid_;
|
||||
handle_ = std::move(other.handle_);
|
||||
other.pid_ = static_cast<DWORD>(-1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~basic_process_handle_win()
|
||||
{
|
||||
if (handle_.is_open())
|
||||
{
|
||||
error_code ec;
|
||||
handle_.close(ec);
|
||||
}
|
||||
}
|
||||
|
||||
native_handle_type native_handle()
|
||||
{ return handle_.native_handle(); }
|
||||
|
||||
pid_type id() const
|
||||
{ return pid_; }
|
||||
|
||||
void terminate_if_running(error_code &)
|
||||
{
|
||||
detail::terminate_if_running_(handle_.native_handle());
|
||||
}
|
||||
|
||||
void terminate_if_running()
|
||||
{
|
||||
detail::terminate_if_running_(handle_.native_handle());
|
||||
}
|
||||
|
||||
void wait(native_exit_code_type &exit_status, error_code &ec)
|
||||
{
|
||||
if (!detail::check_handle_(handle_.native_handle(), ec))
|
||||
return;
|
||||
|
||||
handle_.wait(ec);
|
||||
if (!ec)
|
||||
detail::get_exit_code_(handle_.native_handle(), exit_status, ec);
|
||||
}
|
||||
|
||||
|
||||
void wait(native_exit_code_type &exit_status)
|
||||
{
|
||||
error_code ec;
|
||||
wait(exit_status, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "wait(pid)");
|
||||
}
|
||||
|
||||
void interrupt(error_code &ec)
|
||||
{
|
||||
if (!detail::check_pid_(pid_, ec))
|
||||
return;
|
||||
|
||||
detail::interrupt_(pid_, ec);
|
||||
}
|
||||
|
||||
void interrupt()
|
||||
{
|
||||
error_code ec;
|
||||
interrupt(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "interrupt");
|
||||
}
|
||||
|
||||
void request_exit(error_code &ec)
|
||||
{
|
||||
if (!detail::check_pid_(pid_, ec))
|
||||
return;
|
||||
detail::request_exit_(pid_, ec);
|
||||
}
|
||||
|
||||
void request_exit()
|
||||
{
|
||||
error_code ec;
|
||||
request_exit(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "request_exit");
|
||||
}
|
||||
|
||||
void suspend(error_code &ec)
|
||||
{
|
||||
detail::suspend_(handle_.native_handle(), ec);
|
||||
}
|
||||
|
||||
void suspend()
|
||||
{
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "suspend");
|
||||
}
|
||||
|
||||
void resume(error_code &ec)
|
||||
{
|
||||
detail::resume_(handle_.native_handle(), ec);
|
||||
}
|
||||
|
||||
void resume()
|
||||
{
|
||||
error_code ec;
|
||||
resume(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "resume");
|
||||
}
|
||||
|
||||
void terminate(native_exit_code_type &exit_status, error_code &ec)
|
||||
{
|
||||
if (!detail::check_handle_(handle_.native_handle(), ec))
|
||||
return;
|
||||
|
||||
detail::terminate_(handle_.native_handle(), ec, exit_status);
|
||||
if (!ec)
|
||||
wait(exit_status, ec);
|
||||
|
||||
}
|
||||
|
||||
void terminate(native_exit_code_type &exit_status)
|
||||
{
|
||||
error_code ec;
|
||||
terminate(exit_status, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "terminate");
|
||||
}
|
||||
|
||||
bool running(native_exit_code_type &exit_code, error_code & ec)
|
||||
{
|
||||
if (!detail::check_handle_(handle_.native_handle(), ec))
|
||||
return false;
|
||||
|
||||
native_exit_code_type code;
|
||||
//single value, not needed in the winapi.
|
||||
detail::check_running_(handle_.native_handle(), ec, code);
|
||||
if (ec)
|
||||
return false;
|
||||
|
||||
if (process_is_running(code))
|
||||
return true;
|
||||
else
|
||||
exit_code = code;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool running(native_exit_code_type &exit_code)
|
||||
{
|
||||
error_code ec;
|
||||
bool res = running(exit_code, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "is_running");
|
||||
return res;
|
||||
}
|
||||
|
||||
bool is_open() const
|
||||
{
|
||||
return handle_.is_open();
|
||||
}
|
||||
|
||||
template<typename>
|
||||
friend struct basic_process_handle_win;
|
||||
private:
|
||||
pid_type pid_;
|
||||
handle_type handle_;
|
||||
|
||||
struct async_wait_op_
|
||||
{
|
||||
handle_type &handle;
|
||||
native_exit_code_type & exit_code;
|
||||
template<typename Self>
|
||||
void operator()(Self &&self)
|
||||
{
|
||||
|
||||
self.reset_cancellation_state(asio::enable_total_cancellation());
|
||||
auto sl = self.get_cancellation_state().slot();
|
||||
auto & h = handle;
|
||||
if (sl.is_connected())
|
||||
sl.assign(
|
||||
[&h](asio::cancellation_type ct)
|
||||
{
|
||||
error_code ec;
|
||||
h.cancel(ec);
|
||||
});
|
||||
handle.async_wait(std::move(self));
|
||||
}
|
||||
|
||||
template<typename Self>
|
||||
void operator()(Self &&self, error_code ec)
|
||||
{
|
||||
if (ec == asio::error::operation_aborted && !self.get_cancellation_state().cancelled())
|
||||
return handle.async_wait(std::move(self));
|
||||
|
||||
if (!ec && process_is_running(exit_code)) // exit_code could be set by another call to wait.
|
||||
detail::get_exit_code_(handle.native_handle(), exit_code, ec);
|
||||
std::move(self).complete(ec);
|
||||
}
|
||||
};
|
||||
public:
|
||||
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code))
|
||||
WaitHandler = net::default_completion_token_t<executor_type>>
|
||||
auto async_wait(native_exit_code_type & exit_code,
|
||||
WaitHandler &&handler = net::default_completion_token_t<executor_type>())
|
||||
-> decltype(net::async_compose<WaitHandler, void(error_code)>(
|
||||
async_wait_op_{handle_, exit_code}, handler, handle_))
|
||||
{
|
||||
return net::async_compose<WaitHandler, void(error_code)>(
|
||||
async_wait_op_{handle_, exit_code}, handler, handle_
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
|
||||
#endif //BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_WINDOWS_HPP
|
||||
33
include/boost/process/v2/detail/throw_error.hpp
Normal file
33
include/boost/process/v2/detail/throw_error.hpp
Normal file
@@ -0,0 +1,33 @@
|
||||
// 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_DETAIL_THROW_ERROR_HPP
|
||||
#define BOOST_PROCESS_V2_DETAIL_THROW_ERROR_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
namespace detail
|
||||
{
|
||||
|
||||
BOOST_PROCESS_V2_DECL void do_throw_error(const error_code& err);
|
||||
BOOST_PROCESS_V2_DECL void do_throw_error(const error_code& err, const char* location);
|
||||
|
||||
inline void throw_error(const error_code& err)
|
||||
{
|
||||
if (err)
|
||||
do_throw_error(err);
|
||||
}
|
||||
|
||||
inline void throw_error(const error_code& err, const char* location)
|
||||
{
|
||||
if (err)
|
||||
do_throw_error(err, location);
|
||||
}
|
||||
|
||||
}
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
|
||||
#endif //BOOST_PROCESS_V2_DETAIL_THROW_ERROR_HPP
|
||||
39
include/boost/process/v2/detail/throw_exception.hpp
Normal file
39
include/boost/process/v2/detail/throw_exception.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// 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_DETAIL_THROW_EXCEPTION_HPP
|
||||
#define BOOST_PROCESS_V2_DETAIL_THROW_EXCEPTION_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
|
||||
#if !defined(BOOST_PROCESS_V2_STANDALONE)
|
||||
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_STANDALONE)
|
||||
|
||||
template <typename Exception>
|
||||
inline void throw_exception(const Exception& e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
using boost::throw_exception;
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif //BOOST_PROCESS_V2_DETAIL_THROW_EXCEPTION_HPP
|
||||
94
include/boost/process/v2/detail/utf8.hpp
Normal file
94
include/boost/process/v2/detail/utf8.hpp
Normal file
@@ -0,0 +1,94 @@
|
||||
// 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_DETAIL_UTF8_HPP
|
||||
#define BOOST_PROCESS_V2_DETAIL_UTF8_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
BOOST_PROCESS_V2_DECL std::size_t size_as_utf8(const wchar_t * in, std::size_t size, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL std::size_t size_as_wide(const char * in, std::size_t size, error_code & ec);
|
||||
|
||||
BOOST_PROCESS_V2_DECL std::size_t convert_to_utf8(const wchar_t * in, std::size_t size,
|
||||
char * out, std::size_t max_size, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL std::size_t convert_to_wide(const char * in, std::size_t size,
|
||||
wchar_t * out, std::size_t max_size, error_code & ec);
|
||||
|
||||
template<typename CharOut, typename Traits = std::char_traits<CharOut>,
|
||||
typename Allocator = std::allocator<CharOut>, typename CharIn,
|
||||
typename = typename std::enable_if<std::is_same<CharOut, CharIn>::value>::type>
|
||||
std::basic_string<CharOut, Traits, Allocator> conv_string(
|
||||
const CharIn * data, std::size_t size,
|
||||
const Allocator allocator = Allocator{})
|
||||
{
|
||||
return std::basic_string<CharOut, Traits, Allocator>(data, size, allocator);
|
||||
}
|
||||
|
||||
|
||||
template<typename CharOut, typename Traits = std::char_traits<CharOut>,
|
||||
typename Allocator = std::allocator<CharOut>,
|
||||
typename = typename std::enable_if<std::is_same<CharOut, char>::value>::type>
|
||||
std::basic_string<CharOut, Traits, Allocator> conv_string(
|
||||
const wchar_t * data, std::size_t size,
|
||||
const Allocator allocator = Allocator{})
|
||||
{
|
||||
error_code ec;
|
||||
const auto req_size = size_as_utf8(data, size, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "size_as_utf8");
|
||||
|
||||
|
||||
std::basic_string<CharOut, Traits, Allocator> res(allocator);
|
||||
res.resize(req_size);
|
||||
|
||||
if (req_size == 0)
|
||||
return res;
|
||||
|
||||
|
||||
auto res_size = convert_to_utf8(data, size, &res.front(), req_size, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "convert_to_utf8");
|
||||
|
||||
res.resize(res_size);
|
||||
return res;
|
||||
}
|
||||
|
||||
template<typename CharOut, typename Traits = std::char_traits<CharOut>,
|
||||
typename Allocator = std::allocator<CharOut>,
|
||||
typename = typename std::enable_if<std::is_same<CharOut, wchar_t>::value>::type>
|
||||
std::basic_string<CharOut, Traits, Allocator> conv_string(
|
||||
const char * data, std::size_t size,
|
||||
const Allocator allocator = Allocator{})
|
||||
{
|
||||
error_code ec;
|
||||
const auto req_size = size_as_wide(data, size, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "size_as_wide");
|
||||
|
||||
std::basic_string<CharOut, Traits, Allocator> res(allocator);
|
||||
res.resize(req_size);
|
||||
|
||||
if (req_size == 0)
|
||||
return res;
|
||||
|
||||
auto res_size = convert_to_wide(data, size, &res.front(), req_size, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "convert_to_wide");
|
||||
|
||||
res.resize(res_size);
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
|
||||
#endif //BOOST_PROCESS_V2_DETAIL_UTF8_HPP
|
||||
Reference in New Issue
Block a user