Added thirdparty: boost library

This commit is contained in:
Viacheslav Demydiuk
2024-01-06 19:55:56 +02:00
parent bf49f439e1
commit bccd1e7051
15683 changed files with 3239840 additions and 0 deletions
+180
View File
@@ -0,0 +1,180 @@
// 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_ASIO_NAMESPACE asio
#define BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(Sig) ASIO_COMPLETION_TOKEN_FOR(Sig)
#define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(Executor) ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)
#define BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(Token, Signature) ASIO_INITFN_AUTO_RESULT_TYPE(Token, Signature)
#define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN(Executor) ASIO_DEFAULT_COMPLETION_TOKEN(Executor)
#define BOOST_PROCESS_V2_INITFN_DEDUCED_RESULT_TYPE(x,y,z) ASIO_INITFN_DEDUCED_RESULT_TYPE(x,y,z)
#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
// Windows: suppress definition of "min" and "max" macros.
#if !defined(NOMINMAX)
# define NOMINMAX 1
#endif
#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
#else
#define BOOST_PROCESS_V2_ASIO_NAMESPACE boost::asio
#define BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(Sig) BOOST_ASIO_COMPLETION_TOKEN_FOR(Sig)
#define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(Executor) BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)
#define BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(Token, Signature) BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(Token, Signature)
#define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN(Executor) BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor)
#define BOOST_PROCESS_V2_INITFN_DEDUCED_RESULT_TYPE(x,y,z) BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE(x,y,z)
#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
// Windows: suppress definition of "min" and "max" macros.
#if !defined(NOMINMAX)
# define NOMINMAX 1
#endif
#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
#define BOOST_PROCESS_V2_BEGIN_NAMESPACE namespace boost { namespace process { namespace v2 {
#define BOOST_PROCESS_V2_END_NAMESPACE } } }
#define BOOST_PROCESS_V2_NAMESPACE boost::process::v2
#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_RETURN_EC(ev) \
return ::BOOST_PROCESS_V2_NAMESPACE::error_code(ev, ::BOOST_PROCESS_V2_NAMESPACE::system_category()); \
#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_RETURN_EC(ev) \
{ \
static constexpr auto loc##__LINE__((BOOST_CURRENT_LOCATION)); \
return ::BOOST_PROCESS_V2_NAMESPACE::error_code(ev, ::BOOST_PROCESS_V2_NAMESPACE::system_category(), &loc##__LINE__); \
}
#define BOOST_PROCESS_V2_ASSIGN_EC(ec, ...) \
{ \
static constexpr auto loc##__LINE__((BOOST_CURRENT_LOCATION)); \
ec.assign(__VA_ARGS__, &loc##__LINE__); \
}
#define BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) \
{ \
static constexpr auto loc##__LINE__((BOOST_CURRENT_LOCATION)); \
ec.assign(::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error(), &loc##__LINE__); \
}
#endif
BOOST_PROCESS_V2_END_NAMESPACE
#ifndef BOOST_PROCESS_V2_HEADER_ONLY
# ifndef BOOST_PROCESS_V2_SEPARATE_COMPILATION
# define BOOST_PROCESS_V2_HEADER_ONLY 1
# endif
#endif
#if BOOST_PROCESS_V2_DOXYGEN
# define BOOST_PROCESS_V2_DECL
#elif defined(BOOST_PROCESS_V2_HEADER_ONLY)
# define BOOST_PROCESS_V2_DECL inline
#else
# define BOOST_PROCESS_V2_DECL
#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)
#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
+80
View File
@@ -0,0 +1,80 @@
//
// 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__) || 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 is_executable(const filesystem::path & pth, error_code & ec);
}
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif
+212
View File
@@ -0,0 +1,212 @@
//
// 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_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;
}
BOOST_CONSTEXPR static size_t length(const char* s) BOOST_NOEXCEPT { return std::strlen(s); }
BOOST_CONSTEXPR static size_t length(const wchar_t* s) BOOST_NOEXCEPT { return std::wcslen(s); }
BOOST_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_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);
}
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_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_executable(const filesystem::path & pth, error_code & ec);
}
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_DETAIL_ENVIRONMENT_WIN_HPP
+18
View File
@@ -0,0 +1,18 @@
// 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_IMPL_ENVIRONMENT_IPP
#define BOOST_PROCESS_V2_DETAIL_IMPL_ENVIRONMENT_IPP
#include <boost/process/v2/detail/config.hpp>
#if defined(BOOST_PROCESS_V2_WINDOWS)
#include <boost/process/v2/detail/impl/environment_win.ipp>
#elif defined(BOOST_PROCESS_V2_POSIX)
#include <boost/process/v2/detail/impl/environment_posix.ipp>
#else
#error Operating System not supported.
#endif
#endif //BOOST_PROCESS_V2_DETAIL_IMPL_ENVIRONMENT_IPP
+81
View File
@@ -0,0 +1,81 @@
//
// process/this_process/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_WIN_HPP
#define BOOST_PROCESS_V2_DETAIL_ENVIRONMENT_WIN_HPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/last_error.hpp>
#include <boost/process/v2/environment.hpp>
#include <boost/process/v2/cstring_ref.hpp>
#include <unistd.h>
#include <cstring>
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace environment
{
namespace detail
{
basic_cstring_ref<char_type, value_char_traits<char>> get(
basic_cstring_ref<char_type, key_char_traits<char_type>> key,
error_code & ec)
{
auto res = ::getenv(key.c_str());
if (res == nullptr)
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOENT, system_category())
return {};
}
return res;
}
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)
{
if (::setenv(key.c_str(), value.c_str(), true))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
void unset(basic_cstring_ref<char_type, key_char_traits<char_type>> key, error_code & ec)
{
if (::unsetenv(key.c_str()))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
native_handle_type load_native_handle() { return ::environ; }
native_iterator next(native_iterator nh)
{
return nh + 1;
}
native_iterator find_end(native_handle_type nh)
{
while (*nh != nullptr)
nh++;
return nh;
}
bool is_executable(const filesystem::path & p, error_code & ec)
{
return filesystem::is_regular_file(p, ec) && (::access(p.c_str(), X_OK) == 0);
}
}
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_DETAIL_ENVIRONMENT_WIN_HPP
+142
View File
@@ -0,0 +1,142 @@
//
// process/this_process/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_IMPL_ENVIRONMENT_WIN_IPP
#define BOOST_PROCESS_V2_DETAIL_IMPL_ENVIRONMENT_WIN_IPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/environment_win.hpp>
#include <boost/process/v2/detail/impl/environment.ipp>
#include <boost/process/v2/detail/last_error.hpp>
#include <algorithm>
#include <cwctype>
#include <cstring>
#include <shellapi.h>
#include <boost/process/v2/cstring_ref.hpp>
#include <boost/process/v2/error.hpp>
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace environment
{
namespace detail
{
std::basic_string<char_type, value_char_traits<char_type>> get(
basic_cstring_ref<char_type, key_char_traits<char_type>> key,
error_code & ec)
{
std::basic_string<char_type, value_char_traits<char_type>> buf;
std::size_t size = 0u;
do
{
buf.resize(buf.size() + 4096);
size = ::GetEnvironmentVariableW(key.c_str(), &buf.front(), static_cast<DWORD>(buf.size()));
}
while (size == buf.size());
buf.resize(size);
if (buf.size() == 0)
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
return buf;
}
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)
{
if (!::SetEnvironmentVariableW(key.c_str(), value.c_str()))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
void unset(basic_cstring_ref<char_type, key_char_traits<char_type>> key,
error_code & ec)
{
if (!::SetEnvironmentVariableW(key.c_str(), nullptr))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
std::basic_string<char, value_char_traits<char>> get(
basic_cstring_ref<char, key_char_traits<char>> key,
error_code & ec)
{
std::basic_string<char, value_char_traits<char>> buf;
std::size_t size = 0u;
do
{
buf.resize(buf.size() + 4096);
size = ::GetEnvironmentVariableA(key.c_str(), &buf.front(), static_cast<DWORD>(buf.size()));
}
while (size == buf.size());
buf.resize(size);
if (buf.size() == 0)
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
return buf;
}
void set(basic_cstring_ref<char, key_char_traits<char>> key,
basic_cstring_ref<char, value_char_traits<char>> value,
error_code & ec)
{
if (!::SetEnvironmentVariableA(key.c_str(), value.c_str()))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
void unset(basic_cstring_ref<char, key_char_traits<char>> key,
error_code & ec)
{
if (!::SetEnvironmentVariableA(key.c_str(), nullptr))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
native_handle_type load_native_handle() { return ::GetEnvironmentStringsW(); }
void native_handle_deleter::operator()(native_handle_type nh) const
{
::FreeEnvironmentStringsW(nh);
}
native_iterator next(native_iterator nh)
{
while (*nh != L'\0')
nh++;
return ++nh;
}
native_iterator find_end(native_handle_type nh)
{
while ((*nh != L'\0') || (*std::next(nh) != L'\0'))
nh++;
return ++nh;
}
bool is_executable(const filesystem::path & pth, error_code & ec)
{
return filesystem::is_regular_file(pth, ec) && SHGetFileInfoW(pth.native().c_str(), 0,0,0, SHGFI_EXETYPE);
}
}
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_DETAIL_IMPL_ENVIRONMENT_WIN_IPP
+34
View File
@@ -0,0 +1,34 @@
// 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_IMPL_LAST_ERROR_IPP
#define BOOST_PROCESS_V2_DETAIL_IMPL_LAST_ERROR_IPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/last_error.hpp>
#if defined(BOOST_PROCESS_V2_WINDOWS)
#include <windows.h>
#else
#include <cerrno>
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
{
error_code get_last_error()
{
#if defined(BOOST_PROCESS_V2_WINDOWS)
return error_code(::GetLastError(), system_category());
#else
return error_code(errno, system_category());
#endif
}
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_DETAIL_IMPL_LAST_ERROR_IPP
@@ -0,0 +1,169 @@
// 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_IMPL_PROCESS_HANDLE_WINDOWS_IPP
#define BOOST_PROCESS_V2_DETAIL_IMPL_PROCESS_HANDLE_WINDOWS_IPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/last_error.hpp>
#include <boost/process/v2/detail/throw_error.hpp>
#include <boost/process/v2/detail/process_handle_windows.hpp>
#include <boost/process/v2/ext/detail/proc_info.hpp>
#include <windows.h>
#if !defined(BOOST_PROCESS_V2_DISABLE_UNDOCUMENTED_API)
extern "C"
{
LONG WINAPI NtResumeProcess(HANDLE ProcessHandle);
LONG WINAPI NtSuspendProcess(HANDLE ProcessHandle);
}
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
{
void get_exit_code_(
HANDLE handle,
native_exit_code_type & exit_code,
error_code & ec)
{
if (!::GetExitCodeProcess(handle, &exit_code))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
HANDLE open_process_(DWORD pid)
{
auto proc = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, FALSE, pid);
if (proc == nullptr)
{
error_code ec;
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
throw system_error(ec, "open_process()");
}
return proc;
}
void terminate_if_running_(HANDLE handle)
{
DWORD exit_code = 0u;
if (handle == INVALID_HANDLE_VALUE)
return ;
if (::GetExitCodeProcess(handle, &exit_code))
if (exit_code == STILL_ACTIVE)
::TerminateProcess(handle, 260);
}
bool check_handle_(HANDLE handle, error_code & ec)
{
if (handle == INVALID_HANDLE_VALUE)
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, ERROR_INVALID_HANDLE_STATE, system_category())
return false;
}
return true;
}
bool check_pid_(pid_type pid_, error_code & ec)
{
if (pid_ == 0)
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, ERROR_INVALID_HANDLE_STATE, system_category())
return false;
}
return true;
}
struct enum_windows_data_t
{
error_code &ec;
pid_type pid;
};
static BOOL CALLBACK enum_window(HWND hwnd, LPARAM param)
{
auto data = reinterpret_cast<enum_windows_data_t*>(param);
DWORD pid{0u};
GetWindowThreadProcessId(hwnd, &pid);
if (pid != data->pid)
return TRUE;
LRESULT res = ::SendMessageW(hwnd, WM_CLOSE, 0, 0);
if (res)
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(data->ec)
return res == 0;
}
void request_exit_(pid_type pid_, error_code & ec)
{
enum_windows_data_t data{ec, pid_};
if (!::EnumWindows(enum_window, reinterpret_cast<LONG_PTR>(&data)))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
void interrupt_(pid_type pid_, error_code & ec)
{
if (!::GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid_))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
void terminate_(HANDLE handle, error_code & ec, DWORD & exit_status)
{
if (!::TerminateProcess(handle, 260))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
void check_running_(HANDLE handle, error_code & ec, DWORD & exit_status)
{
if (!::GetExitCodeProcess(handle, &exit_status))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
#if !defined(BOOST_PROCESS_V2_DISABLE_UNDOCUMENTED_API)
void suspend_(HANDLE handle, error_code & ec)
{
auto nt_err = NtSuspendProcess(handle);
ULONG dos_err = RtlNtStatusToDosError(nt_err);
if (dos_err)
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
void resume_(HANDLE handle, error_code & ec)
{
auto nt_err = NtResumeProcess(handle);
ULONG dos_err = RtlNtStatusToDosError(nt_err);
if (dos_err)
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
#else
void suspend_(HANDLE, error_code & ec)
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, ERROR_CALL_NOT_IMPLEMENTED, system_category())
}
void resume_(HANDLE handle, error_code & ec)
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, ERROR_CALL_NOT_IMPLEMENTED, system_category())
}
#endif
#if !defined(BOOST_PROCESS_V2_HEADER_ONLY)
template struct basic_process_handle_win<>;
#endif
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_DETAIL_IMPL_PROCESS_HANDLE_WINDOWS_IPP
+31
View File
@@ -0,0 +1,31 @@
// 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_IMPL_THROW_ERROR_IPP
#define BOOST_PROCESS_V2_DETAIL_IMPL_THROW_ERROR_IPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/throw_error.hpp>
#include <boost/process/v2/detail/throw_exception.hpp>
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
{
void do_throw_error(const error_code& err)
{
system_error e(err);
throw_exception(e);
}
void do_throw_error(const error_code& err, const char* location)
{
system_error e(err, location);
throw_exception(e);
}
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_DETAIL_IMPL_THROW_ERROR_IPP
+379
View File
@@ -0,0 +1,379 @@
// 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_IMPL_UTF8_HPP
#define BOOST_PROCESS_V2_DETAIL_IMPL_UTF8_HPP
#include <boost/process/v2/detail/utf8.hpp>
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/last_error.hpp>
#include <boost/process/v2/error.hpp>
#if defined(BOOST_PROCESS_V2_WINDOWS)
#include <Windows.h>
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
{
#if defined(BOOST_PROCESS_V2_WINDOWS)
inline void handle_error(error_code & ec)
{
const auto err = ::GetLastError();
switch (err)
{
case ERROR_INSUFFICIENT_BUFFER:
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::utf8_category)
break;
case ERROR_NO_UNICODE_TRANSLATION:
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::invalid_character, error::utf8_category)
break;
default:
BOOST_PROCESS_V2_ASSIGN_EC(ec, err, system_category())
}
}
std::size_t size_as_utf8(const wchar_t * in, std::size_t size, error_code & ec)
{
auto res = WideCharToMultiByte(
CP_UTF8, // CodePage,
0, // dwFlags,
in, // lpWideCharStr,
static_cast<int>(size), // cchWideChar,
nullptr, // lpMultiByteStr,
0, // cbMultiByte,
nullptr, // lpDefaultChar,
FALSE); // lpUsedDefaultChar
if (res == 0u)
handle_error(ec);
return static_cast<std::size_t>(res);
}
std::size_t size_as_wide(const char * in, std::size_t size, error_code & ec)
{
auto res = ::MultiByteToWideChar(
CP_UTF8, // CodePage
0, // dwFlags
in, // lpMultiByteStr
static_cast<int>(size), // cbMultiByte
nullptr, // lpWideCharStr
0); // cchWideChar
if (res == 0u)
handle_error(ec);
return static_cast<std::size_t>(res);
}
std::size_t convert_to_utf8(const wchar_t *in, std::size_t size, char * out,
std::size_t max_size, error_code & ec)
{
auto res = ::WideCharToMultiByte(
CP_UTF8, // CodePage
0, // dwFlags
in, // lpWideCharStr
static_cast<int>(size), // cchWideChar
out, // lpMultiByteStr
static_cast<int>(max_size), // cbMultiByte
nullptr, // lpDefaultChar
FALSE); // lpUsedDefaultChar
if (res == 0u)
handle_error(ec);
return static_cast<std::size_t>(res);
}
std::size_t convert_to_wide(const char *in, std::size_t size, wchar_t * out,
std::size_t max_size, error_code & ec)
{
auto res = ::MultiByteToWideChar(
CP_UTF8, // CodePage
0, // dwFlags
in, // lpMultiByteStr
static_cast<int>(size), // cbMultiByte
out, // lpWideCharStr
static_cast<int>(max_size)); // cchWideChar
if (res == 0u)
handle_error(ec);
return static_cast<std::size_t>(res);
}
#else
template<std::size_t s>
inline int get_cont_octet_out_count_impl(wchar_t word) {
if (word < 0x80) {
return 0;
}
if (word < 0x800) {
return 1;
}
return 2;
}
template<>
inline int get_cont_octet_out_count_impl<4>(wchar_t word) {
if (word < 0x80) {
return 0;
}
if (word < 0x800) {
return 1;
}
// Note that the following code will generate warnings on some platforms
// where wchar_t is defined as UCS2. The warnings are superfluous as the
// specialization is never instantiated with such compilers, but this
// can cause problems if warnings are being treated as errors, so we guard
// against that. Including <boost/detail/utf8_codecvt_facet.hpp> as we do
// should be enough to get WCHAR_MAX defined.
#if !defined(WCHAR_MAX)
# error WCHAR_MAX not defined!
#endif
// cope with VC++ 7.1 or earlier having invalid WCHAR_MAX
#if defined(_MSC_VER) && _MSC_VER <= 1310 // 7.1 or earlier
return 2;
#elif WCHAR_MAX > 0x10000
if (word < 0x10000) {
return 2;
}
if (word < 0x200000) {
return 3;
}
if (word < 0x4000000) {
return 4;
}
return 5;
#else
return 2;
#endif
}
inline int get_cont_octet_out_count(wchar_t word)
{
return detail::get_cont_octet_out_count_impl<sizeof(wchar_t)>(word);
}
// copied from boost/detail/utf8_codecvt_facet.ipp
// Copyright (c) 2001 Ronald Garcia, Indiana University (garcia@osl.iu.edu)
// Andrew Lumsdaine, Indiana University (lums@osl.iu.edu).
inline unsigned int get_octet_count(unsigned char lead_octet)
{
// if the 0-bit (MSB) is 0, then 1 character
if (lead_octet <= 0x7f) return 1;
// Otherwise the count number of consecutive 1 bits starting at MSB
// assert(0xc0 <= lead_octet && lead_octet <= 0xfd);
if (0xc0 <= lead_octet && lead_octet <= 0xdf) return 2;
else if (0xe0 <= lead_octet && lead_octet <= 0xef) return 3;
else if (0xf0 <= lead_octet && lead_octet <= 0xf7) return 4;
else if (0xf8 <= lead_octet && lead_octet <= 0xfb) return 5;
else return 6;
}
inline bool invalid_continuing_octet(unsigned char octet_1) {
return (octet_1 < 0x80|| 0xbf< octet_1);
}
inline unsigned int get_cont_octet_count(unsigned char lead_octet)
{
return get_octet_count(lead_octet) - 1;
}
inline const wchar_t * get_octet1_modifier_table() noexcept
{
static const wchar_t octet1_modifier_table[] = {
0x00, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc
};
return octet1_modifier_table;
}
std::size_t size_as_utf8(const wchar_t * in, std::size_t size, error_code & ec)
{
std::size_t res = 0u;
const auto from_end = in + size;
for (auto from = in; from != from_end; from++)
res += get_cont_octet_out_count(*from) + 1;
return res;
}
std::size_t size_as_wide(const char * in, std::size_t size, error_code & ec)
{
const auto from = in;
const auto from_end = from + size;
const char * from_next = from;
for (std::size_t char_count = 0u; 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))
break;
from_next += octet_count;
}
return from_next - from;
}
std::size_t convert_to_utf8(const wchar_t * in, std::size_t size,
char * out, std::size_t max_size, error_code & ec)
{
const wchar_t * from = in;
const wchar_t * from_end = from + size;
const wchar_t * & from_next = from;
char * to = out;
char * to_end = out + max_size;
char * & to_next = to;
const wchar_t * const octet1_modifier_table = get_octet1_modifier_table();
wchar_t max_wchar = (std::numeric_limits<wchar_t>::max)();
while (from != from_end && to != to_end) {
// Check for invalid UCS-4 character
if (*from > max_wchar) {
from_next = from;
to_next = to;
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::invalid_character, error::get_utf8_category())
return 0u;
}
int cont_octet_count = get_cont_octet_out_count(*from);
// RG - comment this formula better
int shift_exponent = cont_octet_count * 6;
// Process the first character
*to++ = static_cast<char>(octet1_modifier_table[cont_octet_count] +
(unsigned char)(*from / (1 << shift_exponent)));
// Process the continuation characters
// Invariants: At the start of the loop:
// 1) 'i' continuing octets have been generated
// 2) '*to' points to the next location to place an octet
// 3) shift_exponent is 6 more than needed for the next octet
int i = 0;
while (i != cont_octet_count && to != to_end) {
shift_exponent -= 6;
*to++ = static_cast<char>(0x80 + ((*from / (1 << shift_exponent)) % (1 << 6)));
++i;
}
// If we filled up the out buffer before encoding the character
if (to == to_end && i != cont_octet_count) {
from_next = from;
to_next = to - (i + 1);
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::get_utf8_category())
return 0u;
}
++from;
}
from_next = from;
to_next = to;
// Were we done or did we run out of destination space
if (from != from_end)
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::get_utf8_category())
return to_next - out;
}
inline bool invalid_leading_octet(unsigned char octet_1) {
return (0x7f < octet_1 && octet_1 < 0xc0) ||
(octet_1 > 0xfd);
}
std::size_t convert_to_wide(const char * in, std::size_t size,
wchar_t * out, std::size_t max_size, error_code & ec)
{
const char * from = in;
const char * from_end = from + size;
const char * & from_next = from;
wchar_t * to = out;
wchar_t * to_end = out + max_size;
wchar_t * & to_next = to;
// Basic algorithm: The first octet determines how many
// octets total make up the UCS-4 character. The remaining
// "continuing octets" all begin with "10". To convert, subtract
// the amount that specifies the number of octets from the first
// octet. Subtract 0x80 (1000 0000) from each continuing octet,
// then mash the whole lot together. Note that each continuing
// octet only uses 6 bits as unique values, so only shift by
// multiples of 6 to combine.
const wchar_t * const octet1_modifier_table = detail::get_octet1_modifier_table();
while (from != from_end && to != to_end) {
// Error checking on the first octet
if (invalid_leading_octet(*from)) {
from_next = from;
to_next = to;
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::invalid_character, error::get_utf8_category())
return 0u;
}
// The first octet is adjusted by a value dependent upon
// the number of "continuing octets" encoding the character
const int cont_octet_count = get_cont_octet_count(*from);
// The unsigned char conversion is necessary in case char is
// signed (I learned this the hard way)
wchar_t ucs_result =
(unsigned char)(*from++) - octet1_modifier_table[cont_octet_count];
// Invariants:
// 1) At the start of the loop, 'i' continuing characters have been
// processed
// 2) *from points to the next continuing character to be processed.
int i = 0;
while (i != cont_octet_count && from != from_end) {
// Error checking on continuing characters
if (invalid_continuing_octet(*from)) {
from_next = from;
to_next = to;
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::invalid_character, error::get_utf8_category())
return 0u;
}
ucs_result *= (1 << 6);
// each continuing character has an extra (10xxxxxx)b attached to
// it that must be removed.
ucs_result += (unsigned char)(*from++) - 0x80;
++i;
}
// If the buffer ends with an incomplete unicode character...
if (from == from_end && i != cont_octet_count) {
// rewind "from" to before the current character translation
from_next = from - (i + 1);
to_next = to;
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::get_utf8_category())
return 0u;
}
*to++ = ucs_result;
}
from_next = from;
to_next = to;
if (from != from_end)
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::get_utf8_category())
return to_next - out;
}
#endif
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_DETAIL_IMPL_UTF8_HPP
+28
View File
@@ -0,0 +1,28 @@
// 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
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
#include <boost/process/v2/detail/impl/last_error.ipp>
#endif
#endif //BOOST_PROCESS_V2_DETAIL_LAST_ERROR_HPP
+355
View 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 = BOOST_PROCESS_V2_ASIO_NAMESPACE::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 &,
BOOST_PROCESS_V2_ASIO_NAMESPACE::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))
{
}
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();
}
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();
if (res == 0)
return true;
else
{
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;
}
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, native_exit_code_type))
WaitHandler BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (error_code, native_exit_code_type))
async_wait(WaitHandler &&handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return BOOST_PROCESS_V2_ASIO_NAMESPACE::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
async_wait_op_{descriptor_, pid_}, handler, descriptor_);
}
private:
template<typename>
friend
struct basic_process_handle_fd;
pid_type pid_ = -1;
BOOST_PROCESS_V2_ASIO_NAMESPACE::posix::basic_stream_descriptor<Executor> descriptor_;
struct async_wait_op_
{
BOOST_PROCESS_V2_ASIO_NAMESPACE::posix::basic_descriptor<Executor> &descriptor;
pid_type pid_;
template<typename Self>
void operator()(Self &&self)
{
error_code ec;
native_exit_code_type exit_code{};
int wait_res = -1;
if (pid_ <= 0) // error, complete early
ec = BOOST_PROCESS_V2_ASIO_NAMESPACE::error::bad_descriptor;
else
{
wait_res = ::waitpid(pid_, &exit_code, WNOHANG);
if (wait_res == -1)
ec = get_last_error();
}
if (!ec && (wait_res == 0))
{
descriptor.async_wait(
BOOST_PROCESS_V2_ASIO_NAMESPACE::posix::descriptor_base::wait_read, std::move(self));
return;
}
struct completer
{
error_code ec;
native_exit_code_type code;
typename std::decay<Self>::type self;
void operator()()
{
self.complete(ec, code);
}
};
BOOST_PROCESS_V2_ASIO_NAMESPACE::post(descriptor.get_executor(),
completer{ec, exit_code, std::move(self)});
}
template<typename Self>
void operator()(Self &&self, error_code ec, int = 0)
{
native_exit_code_type exit_code{};
if (!ec)
if (::waitpid(pid_, &exit_code, 0) == -1)
ec = get_last_error();
std::move(self).complete(ec, exit_code);
}
};
};
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_HANDLE_FD_OR_SIGNAL_HPP
@@ -0,0 +1,383 @@
// 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/compose.hpp>
#include <asio/dispatch.hpp>
#include <asio/posix/basic_stream_descriptor.hpp>
#include <asio/post.hpp>
#include <asio/windows/signal_set.hpp>
#else
#include <boost/asio/any_io_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>
#include <boost/asio/signal_set.hpp>
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
{
template<typename Executor = BOOST_PROCESS_V2_ASIO_NAMESPACE::any_io_executor>
struct basic_process_handle_fd_or_signal
{
using native_handle_type = int;
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_fd_or_signal<Executor1> other;
};
template<typename ExecutionContext>
basic_process_handle_fd_or_signal(ExecutionContext &context,
typename std::enable_if<
std::is_convertible<ExecutionContext &,
BOOST_PROCESS_V2_ASIO_NAMESPACE::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 &,
BOOST_PROCESS_V2_ASIO_NAMESPACE::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 &,
BOOST_PROCESS_V2_ASIO_NAMESPACE::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();
}
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
ec.clear();
if (process_is_running(res))
return true;
else
{
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;
}
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, int))
WaitHandler BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (error_code, native_exit_code_type))
async_wait(WaitHandler &&handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return BOOST_PROCESS_V2_ASIO_NAMESPACE::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
async_wait_op_{descriptor_, signal_set_, pid_}, handler, descriptor_);
}
private:
template<typename>
friend
struct basic_process_handle_fd_or_signal;
pid_type pid_ = -1;
BOOST_PROCESS_V2_ASIO_NAMESPACE::posix::basic_stream_descriptor<Executor> descriptor_;
BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_signal_set<Executor> signal_set_{descriptor_.get_executor(), SIGCHLD};
struct async_wait_op_
{
BOOST_PROCESS_V2_ASIO_NAMESPACE::posix::basic_descriptor<Executor> &descriptor;
BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_signal_set<Executor> &handle;
pid_type pid_;
bool needs_post = true;
template<typename Self>
void operator()(Self &&self, error_code ec = {}, int = 0)
{
native_exit_code_type exit_code{};
int wait_res = -1;
if (pid_ <= 0) // error, complete early
ec = BOOST_PROCESS_V2_ASIO_NAMESPACE::error::bad_descriptor;
else
{
wait_res = ::waitpid(pid_, &exit_code, WNOHANG);
if (wait_res == -1)
ec = get_last_error();
}
if (!ec && (wait_res == 0))
{
needs_post = false;
if (descriptor.is_open())
descriptor.async_wait(
BOOST_PROCESS_V2_ASIO_NAMESPACE::posix::descriptor_base::wait_read,
std::move(self));
else
handle.async_wait(std::move(self));
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();
completer cpl{ec, exit_code, std::move(self)};
if (needs_post)
BOOST_PROCESS_V2_ASIO_NAMESPACE::post(exec, std::move(cpl));
else
BOOST_PROCESS_V2_ASIO_NAMESPACE::dispatch(exec, std::move(cpl));
}
};
};
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_HANDLE_FD_OR_SIGNAL_HPP
+350
View File
@@ -0,0 +1,350 @@
// 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/compose.hpp>
#include <asio/dispatch.hpp>
#include <asio/post.hpp>
#include <asio/signal_set.hpp>
#else
#include <boost/asio/any_io_executor.hpp>
#include <boost/asio/compose.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/signal_set.hpp>
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
{
template<typename Executor = BOOST_PROCESS_V2_ASIO_NAMESPACE::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 &,
BOOST_PROCESS_V2_ASIO_NAMESPACE::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();
signal_set_.~basic_signal_set();
using ss = BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_signal_set<Executor>;
new (&signal_set_) ss(handle.get_executor(), SIGCHLD);
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_, SIGTERM) == -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_, SIGCONT) == -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_, SIGTERM) == -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();
}
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();
if (res == 0)
return true;
else
{
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;
}
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, int))
WaitHandler BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (error_code, native_exit_code_type))
async_wait(WaitHandler &&handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return BOOST_PROCESS_V2_ASIO_NAMESPACE::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
async_wait_op_{signal_set_, pid_}, handler, signal_set_);
}
private:
template<typename>
friend struct basic_process_handle_signal;
pid_type pid_ = -1;
BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_signal_set<Executor> signal_set_;
struct async_wait_op_
{
BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_signal_set<Executor> &handle;
pid_type pid_;
template<typename Self>
void operator()(Self &&self)
{
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 == BOOST_PROCESS_V2_ASIO_NAMESPACE::error::operation_aborted &&
self.get_cancellation_state().cancelled()
== BOOST_PROCESS_V2_ASIO_NAMESPACE::cancellation_type::none)
ec.clear();
native_exit_code_type exit_code = -1;
int wait_res = -1;
if (pid_ <= 0) // error, complete early
ec = BOOST_PROCESS_V2_ASIO_NAMESPACE::error::bad_descriptor;
else if (!ec)
{
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;
}
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();
BOOST_PROCESS_V2_ASIO_NAMESPACE::dispatch(exec, completer{ec, exit_code, std::move(self)});
}
};
};
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_SIGNAL_HPP
+305
View File
@@ -0,0 +1,305 @@
// 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 = BOOST_PROCESS_V2_ASIO_NAMESPACE::any_io_executor>
struct basic_process_handle_win
{
typedef BOOST_PROCESS_V2_ASIO_NAMESPACE::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 &,
BOOST_PROCESS_V2_ASIO_NAMESPACE::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> && handle)
: pid_(handle.pid_), handle_(std::move(handle.handle_))
{
}
basic_process_handle_win(basic_process_handle_win && handle)
: pid_(handle.id()), handle_(std::move(handle.handle_))
{
handle.pid_ = static_cast<DWORD>(-1);
}
basic_process_handle_win& operator=(basic_process_handle_win && handle)
{
pid_ = handle.pid_;
handle_ = std::move(handle.handle_);
handle.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;
suspend(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<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, native_exit_code_type))
WaitHandler BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (error_code, native_exit_code_type))
async_wait(WaitHandler &&handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return BOOST_PROCESS_V2_ASIO_NAMESPACE::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
async_wait_op_{handle_}, handler, handle_
);
}
template<typename>
friend struct basic_process_handle_win;
private:
pid_type pid_;
handle_type handle_;
struct async_wait_op_
{
handle_type &handle;
template<typename Self>
void operator()(Self &&self)
{
handle.async_wait(std::move(self));
}
template<typename Self>
void operator()(Self &&self, error_code ec)
{
native_exit_code_type exit_code{};
if (!ec)
detail::get_exit_code_(handle.native_handle(), exit_code, ec);
std::move(self).complete(ec, exit_code);
}
};
};
#if !defined(BOOST_PROCESS_V2_HEADER_ONLY)
extern template struct basic_process_handle_win<>;
#endif
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_WINDOWS_HPP
+38
View File
@@ -0,0 +1,38 @@
// 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
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
#include <boost/process/v2/detail/impl/throw_error.ipp>
#endif
#endif //BOOST_PROCESS_V2_DETAIL_THROW_ERROR_HPP
+39
View 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
+95
View File
@@ -0,0 +1,95 @@
// 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>
BOOST_PROCESS_V2_DECL
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>
BOOST_PROCESS_V2_DECL
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);
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>
BOOST_PROCESS_V2_DECL
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);
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
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
#include <boost/process/v2/detail/impl/utf8.ipp>
#endif
#endif //BOOST_PROCESS_V2_DETAIL_UTF8_HPP