整理
This commit is contained in:
118
include/boost/process/v1/detail/async_handler.hpp
Normal file
118
include/boost/process/v1/detail/async_handler.hpp
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* async_handler.hpp
|
||||
*
|
||||
* Created on: 12.06.2016
|
||||
* Author: Klemens
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_ASYNC_HANDLER_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_ASYNC_HANDLER_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/v1/posix.hpp>
|
||||
#include <boost/process/v1/detail/posix/async_handler.hpp>
|
||||
#include <boost/process/v1/detail/posix/asio_fwd.hpp>
|
||||
#else
|
||||
#include <boost/process/v1/detail/windows/async_handler.hpp>
|
||||
#include <boost/process/v1/detail/windows/asio_fwd.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
|
||||
|
||||
namespace detail {
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
using ::boost::process::v1::detail::posix::is_async_handler;
|
||||
using ::boost::process::v1::detail::posix::does_require_io_context;
|
||||
#else
|
||||
using ::boost::process::v1::detail::windows::is_async_handler;
|
||||
using ::boost::process::v1::detail::windows::does_require_io_context;
|
||||
#endif
|
||||
|
||||
template<typename ...Args>
|
||||
struct has_io_context;
|
||||
|
||||
template<typename T, typename ...Args>
|
||||
struct has_io_context<T, Args...>
|
||||
{
|
||||
typedef typename has_io_context<Args...>::type next;
|
||||
typedef typename std::is_same<
|
||||
typename std::remove_reference<T>::type,
|
||||
boost::asio::io_context>::type is_ios;
|
||||
typedef typename std::conditional<is_ios::value,
|
||||
std::true_type,
|
||||
next>::type type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct has_io_context<T>
|
||||
{
|
||||
typedef typename std::is_same<
|
||||
typename std::remove_reference<T>::type,
|
||||
boost::asio::io_context>::type type;
|
||||
};
|
||||
|
||||
template<typename ...Args>
|
||||
using has_io_context_t = typename has_io_context<Args...>::type;
|
||||
|
||||
template<typename ...Args>
|
||||
struct has_async_handler;
|
||||
|
||||
template<typename T, typename ...Args>
|
||||
struct has_async_handler<T, Args...>
|
||||
{
|
||||
typedef typename has_async_handler<Args...>::type next;
|
||||
typedef typename is_async_handler<T>::type is_ios;
|
||||
typedef typename std::conditional<is_ios::value,
|
||||
std::true_type,
|
||||
next>::type type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct has_async_handler<T>
|
||||
{
|
||||
typedef typename is_async_handler<T>::type type;
|
||||
};
|
||||
|
||||
template<typename ...Args>
|
||||
struct needs_io_context;
|
||||
|
||||
template<typename T, typename ...Args>
|
||||
struct needs_io_context<T, Args...>
|
||||
{
|
||||
typedef typename needs_io_context<Args...>::type next;
|
||||
typedef typename does_require_io_context<T>::type is_ios;
|
||||
typedef typename std::conditional<is_ios::value,
|
||||
std::true_type,
|
||||
next>::type type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct needs_io_context<T>
|
||||
{
|
||||
typedef typename does_require_io_context<T>::type type;
|
||||
};
|
||||
|
||||
template<typename ...Args>
|
||||
boost::asio::io_context &get_io_context_var(boost::asio::io_context & f, Args&...)
|
||||
{
|
||||
return f;
|
||||
}
|
||||
|
||||
template<typename First, typename ...Args>
|
||||
boost::asio::io_context &get_io_context_var(First&, Args&...args)
|
||||
{
|
||||
return get_io_context_var(args...);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_ASYNC_HANDLER_HPP_ */
|
||||
292
include/boost/process/v1/detail/basic_cmd.hpp
Normal file
292
include/boost/process/v1/detail/basic_cmd.hpp
Normal file
@@ -0,0 +1,292 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_BASIC_CMD_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_BASIC_CMD_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
#include <boost/process/v1/detail/traits/cmd_or_exe.hpp>
|
||||
#include <boost/process/v1/detail/traits/wchar_t.hpp>
|
||||
|
||||
#if defined( BOOST_WINDOWS_API )
|
||||
#include <boost/process/v1/detail/windows/basic_cmd.hpp>
|
||||
#include <boost/process/v1/detail/windows/cmd.hpp>
|
||||
#elif defined( BOOST_POSIX_API )
|
||||
#include <boost/process/v1/detail/posix/basic_cmd.hpp>
|
||||
#include <boost/process/v1/detail/posix/cmd.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/process/v1/shell.hpp>
|
||||
|
||||
#include <iterator>
|
||||
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
|
||||
template<typename Char>
|
||||
struct exe_setter_
|
||||
{
|
||||
typedef Char value_type;
|
||||
typedef std::basic_string<Char> string_type;
|
||||
|
||||
string_type exe_;
|
||||
exe_setter_(string_type && str) : exe_(std::move(str)) {}
|
||||
exe_setter_(const string_type & str) : exe_(str) {}
|
||||
};
|
||||
|
||||
template<> struct is_wchar_t<exe_setter_<wchar_t>> : std::true_type {};
|
||||
|
||||
|
||||
template<>
|
||||
struct char_converter<char, exe_setter_<wchar_t>>
|
||||
{
|
||||
static exe_setter_<char> conv(const exe_setter_<wchar_t> & in)
|
||||
{
|
||||
return {::boost::process::v1::detail::convert(in.exe_)};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, exe_setter_<char>>
|
||||
{
|
||||
static exe_setter_<wchar_t> conv(const exe_setter_<char> & in)
|
||||
{
|
||||
return {::boost::process::v1::detail::convert(in.exe_)};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename Char, bool Append >
|
||||
struct arg_setter_
|
||||
{
|
||||
using value_type = Char;
|
||||
using string_type = std::basic_string<value_type>;
|
||||
std::vector<string_type> _args;
|
||||
|
||||
typedef typename std::vector<string_type>::iterator iterator;
|
||||
typedef typename std::vector<string_type>::const_iterator const_iterator;
|
||||
|
||||
template<typename Iterator>
|
||||
arg_setter_(Iterator && begin, Iterator && end) : _args(begin, end) {}
|
||||
|
||||
template<typename Range>
|
||||
arg_setter_(Range && str) :
|
||||
_args(std::begin(str),
|
||||
std::end(str)) {}
|
||||
|
||||
iterator begin() {return _args.begin();}
|
||||
iterator end() {return _args.end();}
|
||||
const_iterator begin() const {return _args.begin();}
|
||||
const_iterator end() const {return _args.end();}
|
||||
arg_setter_(string_type & str) : _args{{str}} {}
|
||||
arg_setter_(string_type && s) : _args({std::move(s)}) {}
|
||||
arg_setter_(const string_type & s) : _args({s}) {}
|
||||
arg_setter_(const value_type* s) : _args({std::move(s)}) {}
|
||||
|
||||
template<std::size_t Size>
|
||||
arg_setter_(const value_type (&s) [Size]) : _args({s}) {}
|
||||
};
|
||||
|
||||
template<> struct is_wchar_t<arg_setter_<wchar_t, true >> : std::true_type {};
|
||||
template<> struct is_wchar_t<arg_setter_<wchar_t, false>> : std::true_type {};
|
||||
|
||||
template<>
|
||||
struct char_converter<char, arg_setter_<wchar_t, true>>
|
||||
{
|
||||
static arg_setter_<char, true> conv(const arg_setter_<wchar_t, true> & in)
|
||||
{
|
||||
std::vector<std::string> vec(in._args.size());
|
||||
std::transform(in._args.begin(), in._args.end(), vec.begin(),
|
||||
[](const std::wstring & ws)
|
||||
{
|
||||
return ::boost::process::v1::detail::convert(ws);
|
||||
});
|
||||
return {vec};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, arg_setter_<char, true>>
|
||||
{
|
||||
static arg_setter_<wchar_t, true> conv(const arg_setter_<char, true> & in)
|
||||
{
|
||||
std::vector<std::wstring> vec(in._args.size());
|
||||
std::transform(in._args.begin(), in._args.end(), vec.begin(),
|
||||
[](const std::string & ws)
|
||||
{
|
||||
return ::boost::process::v1::detail::convert(ws);
|
||||
});
|
||||
|
||||
return {vec};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<char, arg_setter_<wchar_t, false>>
|
||||
{
|
||||
static arg_setter_<char, false> conv(const arg_setter_<wchar_t, false> & in)
|
||||
{
|
||||
std::vector<std::string> vec(in._args.size());
|
||||
std::transform(in._args.begin(), in._args.end(), vec.begin(),
|
||||
[](const std::wstring & ws)
|
||||
{
|
||||
return ::boost::process::v1::detail::convert(ws);
|
||||
});
|
||||
return {vec}; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, arg_setter_<char, false>>
|
||||
{
|
||||
static arg_setter_<wchar_t, false> conv(const arg_setter_<char, false> & in)
|
||||
{
|
||||
std::vector<std::wstring> vec(in._args.size());
|
||||
std::transform(in._args.begin(), in._args.end(), vec.begin(),
|
||||
[](const std::string & ws)
|
||||
{
|
||||
return ::boost::process::v1::detail::convert(ws);
|
||||
});
|
||||
return {vec};
|
||||
}
|
||||
};
|
||||
|
||||
using api::exe_cmd_init;
|
||||
|
||||
template<typename Char>
|
||||
struct exe_builder
|
||||
{
|
||||
//set by path, because that will not be interpreted as a cmd
|
||||
bool not_cmd = false;
|
||||
bool shell = false;
|
||||
using string_type = std::basic_string<Char>;
|
||||
string_type exe;
|
||||
std::vector<string_type> args;
|
||||
|
||||
void operator()(const boost::process::v1::filesystem::path & data)
|
||||
{
|
||||
not_cmd = true;
|
||||
if (exe.empty())
|
||||
exe = data.native();
|
||||
else
|
||||
args.push_back(data.native());
|
||||
}
|
||||
|
||||
void operator()(const string_type & data)
|
||||
{
|
||||
if (exe.empty())
|
||||
exe = data;
|
||||
else
|
||||
args.push_back(data);
|
||||
}
|
||||
void operator()(const Char* data)
|
||||
{
|
||||
if (exe.empty())
|
||||
exe = data;
|
||||
else
|
||||
args.push_back(data);
|
||||
}
|
||||
void operator()(shell_) {shell = true;}
|
||||
void operator()(std::vector<string_type> && data)
|
||||
{
|
||||
if (data.empty())
|
||||
return;
|
||||
|
||||
auto itr = std::make_move_iterator(data.begin());
|
||||
auto end = std::make_move_iterator(data.end());
|
||||
|
||||
if (exe.empty())
|
||||
{
|
||||
exe = *itr;
|
||||
itr++;
|
||||
}
|
||||
args.insert(args.end(), itr, end);
|
||||
}
|
||||
|
||||
void operator()(const std::vector<string_type> & data)
|
||||
{
|
||||
if (data.empty())
|
||||
return;
|
||||
|
||||
auto itr = data.begin();
|
||||
auto end = data.end();
|
||||
|
||||
if (exe.empty())
|
||||
{
|
||||
exe = *itr;
|
||||
itr++;
|
||||
}
|
||||
args.insert(args.end(), itr, end);
|
||||
}
|
||||
void operator()(exe_setter_<Char> && data)
|
||||
{
|
||||
not_cmd = true;
|
||||
exe = std::move(data.exe_);
|
||||
}
|
||||
void operator()(const exe_setter_<Char> & data)
|
||||
{
|
||||
not_cmd = true;
|
||||
exe = data.exe_;
|
||||
}
|
||||
void operator()(arg_setter_<Char, false> && data)
|
||||
{
|
||||
args.assign(
|
||||
std::make_move_iterator(data._args.begin()),
|
||||
std::make_move_iterator(data._args.end()));
|
||||
}
|
||||
void operator()(arg_setter_<Char, true> && data)
|
||||
{
|
||||
args.insert(args.end(),
|
||||
std::make_move_iterator(data._args.begin()),
|
||||
std::make_move_iterator(data._args.end()));
|
||||
}
|
||||
void operator()(const arg_setter_<Char, false> & data)
|
||||
{
|
||||
args.assign(data._args.begin(), data._args.end());
|
||||
}
|
||||
void operator()(const arg_setter_<Char, true> & data)
|
||||
{
|
||||
args.insert(args.end(), data._args.begin(), data._args.end());
|
||||
}
|
||||
|
||||
api::exe_cmd_init<Char> get_initializer()
|
||||
{
|
||||
if (not_cmd || !args.empty())
|
||||
{
|
||||
if (shell)
|
||||
return api::exe_cmd_init<Char>::exe_args_shell(std::move(exe), std::move(args));
|
||||
else
|
||||
return api::exe_cmd_init<Char>::exe_args(std::move(exe), std::move(args));
|
||||
}
|
||||
else
|
||||
if (shell)
|
||||
return api::exe_cmd_init<Char>::cmd_shell(std::move(exe));
|
||||
else
|
||||
return api::exe_cmd_init<Char>::cmd(std::move(exe));
|
||||
|
||||
}
|
||||
typedef api::exe_cmd_init<Char> result_type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct initializer_builder<cmd_or_exe_tag<char>>
|
||||
{
|
||||
typedef exe_builder<char> type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct initializer_builder<cmd_or_exe_tag<wchar_t>>
|
||||
{
|
||||
typedef exe_builder<wchar_t> type;
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_EXE_BUILDER_HPP_ */
|
||||
231
include/boost/process/v1/detail/child_decl.hpp
Normal file
231
include/boost/process/v1/detail/child_decl.hpp
Normal file
@@ -0,0 +1,231 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/**
|
||||
* \file boost/process/child.hpp
|
||||
*
|
||||
* Defines a child process class.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_CHILD_DECL_HPP
|
||||
#define BOOST_PROCESS_CHILD_DECL_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
#include <boost/none.hpp>
|
||||
#include <atomic>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/v1/detail/posix/child_handle.hpp>
|
||||
#include <boost/process/v1/detail/posix/terminate.hpp>
|
||||
#include <boost/process/v1/detail/posix/wait_for_exit.hpp>
|
||||
#include <boost/process/v1/detail/posix/is_running.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/v1/detail/windows/child_handle.hpp>
|
||||
#include <boost/process/v1/detail/windows/terminate.hpp>
|
||||
#include <boost/process/v1/detail/windows/wait_for_exit.hpp>
|
||||
#include <boost/process/v1/detail/windows/is_running.hpp>
|
||||
|
||||
#endif
|
||||
namespace boost {
|
||||
|
||||
namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
|
||||
|
||||
using ::boost::process::v1::detail::api::pid_t;
|
||||
|
||||
class child
|
||||
{
|
||||
::boost::process::v1::detail::api::child_handle _child_handle;
|
||||
std::shared_ptr<std::atomic<int>> _exit_status = std::make_shared<std::atomic<int>>(::boost::process::v1::detail::api::still_active);
|
||||
bool _attached = true;
|
||||
bool _terminated = false;
|
||||
|
||||
bool _exited()
|
||||
{
|
||||
return _terminated || !::boost::process::v1::detail::api::is_running(_exit_status->load());
|
||||
};
|
||||
public:
|
||||
typedef ::boost::process::v1::detail::api::child_handle child_handle;
|
||||
typedef child_handle::process_handle_t native_handle_t;
|
||||
explicit child(child_handle &&ch, std::shared_ptr<std::atomic<int>> &ptr) : _child_handle(std::move(ch)), _exit_status(ptr) {}
|
||||
explicit child(child_handle &&ch, const std::shared_ptr<std::atomic<int>> &ptr) : _child_handle(std::move(ch)), _exit_status(ptr) {}
|
||||
explicit child(child_handle &&ch) : _child_handle(std::move(ch)) {}
|
||||
|
||||
explicit child(pid_t pid) : _child_handle(pid), _attached(false) {};
|
||||
child(const child&) = delete;
|
||||
child(child && lhs) noexcept
|
||||
: _child_handle(std::move(lhs._child_handle)),
|
||||
_exit_status(std::move(lhs._exit_status)),
|
||||
_attached (lhs._attached),
|
||||
_terminated (lhs._terminated)
|
||||
{
|
||||
lhs._attached = false;
|
||||
}
|
||||
|
||||
template<typename ...Args>
|
||||
explicit child(Args&&...args);
|
||||
child() { } // Must be kept non defaulted for MSVC 14.1 & 14.2 #113
|
||||
child& operator=(const child&) = delete;
|
||||
child& operator=(child && lhs)
|
||||
{
|
||||
_child_handle= std::move(lhs._child_handle);
|
||||
_exit_status = std::move(lhs._exit_status);
|
||||
_attached = lhs._attached;
|
||||
_terminated = lhs._terminated;
|
||||
lhs._attached = false;
|
||||
return *this;
|
||||
};
|
||||
|
||||
void detach() {_attached = false; }
|
||||
void join() {wait();}
|
||||
bool joinable() { return _attached;}
|
||||
|
||||
~child()
|
||||
{
|
||||
std::error_code ec;
|
||||
if (_attached && !_exited() && running(ec))
|
||||
terminate(ec);
|
||||
}
|
||||
native_handle_t native_handle() const { return _child_handle.process_handle(); }
|
||||
|
||||
|
||||
int exit_code() const {return ::boost::process::v1::detail::api::eval_exit_status(_exit_status->load());}
|
||||
pid_t id() const {return _child_handle.id(); }
|
||||
|
||||
int native_exit_code() const {return _exit_status->load();}
|
||||
|
||||
bool running()
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = running(ec);
|
||||
boost::process::v1::detail::throw_error(ec, "running error");
|
||||
return b;
|
||||
}
|
||||
|
||||
void terminate()
|
||||
{
|
||||
std::error_code ec;
|
||||
terminate(ec);
|
||||
boost::process::v1::detail::throw_error(ec, "terminate error");
|
||||
}
|
||||
|
||||
void wait()
|
||||
{
|
||||
std::error_code ec;
|
||||
wait(ec);
|
||||
boost::process::v1::detail::throw_error(ec, "wait error");
|
||||
}
|
||||
|
||||
#if !defined(BOOST_PROCESS_NO_DEPRECATED)
|
||||
|
||||
template< class Rep, class Period >
|
||||
BOOST_DEPRECATED("wait_for is unreliable")
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = wait_for(rel_time, ec);
|
||||
boost::process::v1::detail::throw_error(ec, "wait_for error");
|
||||
return b;
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
BOOST_DEPRECATED("wait_until is unreliable")
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = wait_until(timeout_time, ec);
|
||||
boost::process::v1::detail::throw_error(ec, "wait_until error");
|
||||
return b;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool running(std::error_code & ec) noexcept
|
||||
{
|
||||
ec.clear();
|
||||
if (valid() && !_exited() && !ec)
|
||||
{
|
||||
int exit_code = 0;
|
||||
auto res = boost::process::v1::detail::api::is_running(_child_handle, exit_code, ec);
|
||||
if (!ec && !res && !_exited())
|
||||
_exit_status->store(exit_code);
|
||||
|
||||
return res;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void terminate(std::error_code & ec) noexcept
|
||||
{
|
||||
if (valid() && running(ec) && !ec)
|
||||
boost::process::v1::detail::api::terminate(_child_handle, ec);
|
||||
|
||||
if (!ec)
|
||||
_terminated = true;
|
||||
}
|
||||
|
||||
void wait(std::error_code & ec) noexcept
|
||||
{
|
||||
if (!_exited() && valid())
|
||||
{
|
||||
int exit_code = 0;
|
||||
boost::process::v1::detail::api::wait(_child_handle, exit_code, ec);
|
||||
if (!ec)
|
||||
_exit_status->store(exit_code);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(BOOST_PROCESS_NO_DEPRECATED)
|
||||
template< class Rep, class Period >
|
||||
BOOST_DEPRECATED("wait_for is unreliable")
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
|
||||
{
|
||||
return wait_until(std::chrono::steady_clock::now() + rel_time, ec);
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
BOOST_DEPRECATED("wait_until is unreliable")
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept
|
||||
{
|
||||
if (!_exited())
|
||||
{
|
||||
int exit_code = 0;
|
||||
auto b = boost::process::v1::detail::api::wait_until(_child_handle, exit_code, timeout_time, ec);
|
||||
if (!b || ec)
|
||||
return false;
|
||||
_exit_status->store(exit_code);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
return _child_handle.valid();
|
||||
}
|
||||
operator bool() const {return valid();}
|
||||
|
||||
bool in_group() const
|
||||
{
|
||||
return _child_handle.in_group();
|
||||
}
|
||||
bool in_group(std::error_code &ec) const noexcept
|
||||
{
|
||||
return _child_handle.in_group(ec);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
|
||||
139
include/boost/process/v1/detail/config.hpp
Normal file
139
include/boost/process/v1/detail/config.hpp
Normal file
@@ -0,0 +1,139 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/**
|
||||
* \file boost/process/config.hpp
|
||||
*
|
||||
* Defines various macros.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_CONFIG_HPP
|
||||
#define BOOST_PROCESS_DETAIL_CONFIG_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <system_error>
|
||||
#include <boost/system/api_config.hpp>
|
||||
|
||||
#if !defined(BOOST_PROCESS_VERSION)
|
||||
#define BOOST_PROCESS_VERSION 2
|
||||
#endif
|
||||
|
||||
#if BOOST_PROCESS_VERSION == 1
|
||||
#define BOOST_PROCESS_V1_INLINE inline
|
||||
#else
|
||||
#define BOOST_PROCESS_V1_INLINE
|
||||
#endif
|
||||
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/process/v1/exception.hpp>
|
||||
#include <boost/assert/source_location.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <errno.h>
|
||||
#if defined(__GLIBC__)
|
||||
#include <features.h>
|
||||
#else
|
||||
extern char **environ;
|
||||
#endif
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/winapi/get_last_error.hpp>
|
||||
#else
|
||||
#error "System API not supported by boost.process"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail
|
||||
{
|
||||
|
||||
#if !defined(BOOST_PROCESS_PIPE_SIZE)
|
||||
#define BOOST_PROCESS_PIPE_SIZE 1024
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
namespace posix {namespace extensions {}}
|
||||
namespace api = posix;
|
||||
|
||||
inline std::error_code get_last_error() noexcept
|
||||
{
|
||||
return std::error_code(errno, std::system_category());
|
||||
}
|
||||
|
||||
//copied from linux spec.
|
||||
#if (_XOPEN_SOURCE >= 500 || _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED) && !(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
|
||||
#define BOOST_POSIX_HAS_VFORK 1
|
||||
#endif
|
||||
|
||||
#if (_POSIX_C_SOURCE >= 199309L)
|
||||
#define BOOST_POSIX_HAS_SIGTIMEDWAIT 1
|
||||
#endif
|
||||
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
namespace windows {namespace extensions {}}
|
||||
namespace api = windows;
|
||||
|
||||
inline std::error_code get_last_error() noexcept
|
||||
{
|
||||
return std::error_code(::boost::winapi::GetLastError(), std::system_category());
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void throw_last_error(const std::string & msg, boost::source_location const & loc = boost::source_location())
|
||||
{
|
||||
boost::throw_exception(process_error(get_last_error(), msg), loc);
|
||||
}
|
||||
|
||||
inline void throw_last_error(const char * msg, boost::source_location const & loc = boost::source_location())
|
||||
{
|
||||
boost::throw_exception(process_error(get_last_error(), msg), loc);
|
||||
}
|
||||
|
||||
inline void throw_last_error(boost::source_location const & loc = boost::source_location())
|
||||
{
|
||||
boost::throw_exception(process_error(get_last_error()), loc);
|
||||
}
|
||||
|
||||
inline void throw_error(const std::error_code& ec,
|
||||
boost::source_location const & loc = boost::source_location())
|
||||
{
|
||||
if (ec)
|
||||
boost::throw_exception(process_error(ec), loc);
|
||||
}
|
||||
|
||||
inline void throw_error(const std::error_code& ec, const char* msg,
|
||||
boost::source_location const & loc = boost::source_location())
|
||||
{
|
||||
if (ec)
|
||||
boost::throw_exception(process_error(ec, msg), loc);
|
||||
}
|
||||
|
||||
template<typename Char> constexpr Char null_char();
|
||||
template<> constexpr char null_char<char> (){return '\0';}
|
||||
template<> constexpr wchar_t null_char<wchar_t> (){return L'\0';}
|
||||
|
||||
template<typename Char> constexpr Char equal_sign();
|
||||
template<> constexpr char equal_sign<char> () {return '='; }
|
||||
template<> constexpr wchar_t equal_sign<wchar_t> () {return L'='; }
|
||||
|
||||
template<typename Char> constexpr Char quote_sign();
|
||||
template<> constexpr char quote_sign<char> () {return '"'; }
|
||||
template<> constexpr wchar_t quote_sign<wchar_t> () {return L'"'; }
|
||||
|
||||
template<typename Char> constexpr Char space_sign();
|
||||
template<> constexpr char space_sign<char> () {return ' '; }
|
||||
template<> constexpr wchar_t space_sign<wchar_t> () {return L' '; }
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
283
include/boost/process/v1/detail/execute_impl.hpp
Normal file
283
include/boost/process/v1/detail/execute_impl.hpp
Normal file
@@ -0,0 +1,283 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/**
|
||||
* \file boost/process/execute.hpp
|
||||
*
|
||||
* Defines a function to execute a program.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_EXECUTE_HPP
|
||||
#define BOOST_PROCESS_EXECUTE_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/traits.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/v1/detail/posix/executor.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/v1/detail/windows/executor.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/process/v1/detail/basic_cmd.hpp>
|
||||
#include <boost/process/v1/detail/handler.hpp>
|
||||
|
||||
#include <boost/fusion/view.hpp>
|
||||
#include <boost/fusion/container.hpp>
|
||||
#include <boost/fusion/sequence.hpp>
|
||||
#include <boost/fusion/tuple.hpp>
|
||||
#include <boost/fusion/algorithm/transformation/filter_if.hpp>
|
||||
#include <boost/fusion/adapted/std_tuple.hpp>
|
||||
#include <boost/fusion/container/vector/convert.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
|
||||
|
||||
class child;
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
template<typename ...Args>
|
||||
struct has_wchar;
|
||||
|
||||
template<typename First, typename ...Args>
|
||||
struct has_wchar<First, Args...>
|
||||
{
|
||||
typedef has_wchar<Args...> next;
|
||||
typedef typename std::remove_cv<
|
||||
typename std::remove_reference<First>::type>::type res_type;
|
||||
|
||||
constexpr static bool my_value = is_wchar_t<res_type>::value;
|
||||
constexpr static bool value = my_value || next::value;
|
||||
|
||||
typedef std::integral_constant<bool, value> type;
|
||||
};
|
||||
|
||||
template<typename First>
|
||||
struct has_wchar<First>
|
||||
{
|
||||
typedef typename std::remove_cv<
|
||||
typename std::remove_reference<First>::type>::type res_type;
|
||||
|
||||
constexpr static bool value = is_wchar_t<res_type>::value;
|
||||
|
||||
typedef std::integral_constant<bool, value> type;
|
||||
};
|
||||
|
||||
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
//everything needs to be wchar_t
|
||||
#if defined(BOOST_NO_ANSI_APIS)
|
||||
template<bool has_wchar>
|
||||
struct required_char_type
|
||||
{
|
||||
typedef wchar_t type;
|
||||
};
|
||||
#else
|
||||
template<bool has_wchar> struct required_char_type;
|
||||
template<> struct required_char_type<true>
|
||||
{
|
||||
typedef wchar_t type;
|
||||
};
|
||||
template<> struct required_char_type<false>
|
||||
{
|
||||
typedef char type;
|
||||
};
|
||||
#endif
|
||||
|
||||
#elif defined(BOOST_POSIX_API)
|
||||
template<bool has_wchar>
|
||||
struct required_char_type
|
||||
{
|
||||
typedef char type;
|
||||
};
|
||||
#endif
|
||||
|
||||
template<typename ... Args>
|
||||
using required_char_type_t = typename required_char_type<
|
||||
has_wchar<Args...>::value>::type;
|
||||
|
||||
|
||||
template<typename Iterator, typename End, typename ...Args>
|
||||
struct make_builders_from_view
|
||||
{
|
||||
typedef boost::fusion::set<Args...> set;
|
||||
typedef typename boost::fusion::result_of::deref<Iterator>::type ref_type;
|
||||
typedef typename std::remove_reference<ref_type>::type res_type;
|
||||
typedef typename initializer_tag<res_type>::type tag;
|
||||
typedef typename initializer_builder<tag>::type builder_type;
|
||||
typedef typename boost::fusion::result_of::has_key<set, builder_type> has_key;
|
||||
|
||||
typedef typename boost::fusion::result_of::next<Iterator>::type next_itr;
|
||||
typedef typename make_builders_from_view<next_itr, End>::type next;
|
||||
|
||||
typedef typename
|
||||
std::conditional<has_key::value,
|
||||
typename make_builders_from_view<next_itr, End, Args...>::type,
|
||||
typename make_builders_from_view<next_itr, End, Args..., builder_type>::type
|
||||
>::type type;
|
||||
|
||||
};
|
||||
|
||||
template<typename Iterator, typename ...Args>
|
||||
struct make_builders_from_view<Iterator, Iterator, Args...>
|
||||
{
|
||||
typedef boost::fusion::set<Args...> type;
|
||||
};
|
||||
|
||||
template<typename Builders>
|
||||
struct builder_ref
|
||||
{
|
||||
Builders &builders;
|
||||
builder_ref(Builders & builders) : builders(builders) {};
|
||||
|
||||
template<typename T>
|
||||
void operator()(T && value) const
|
||||
{
|
||||
typedef typename initializer_tag<typename std::remove_reference<T>::type>::type tag;
|
||||
typedef typename initializer_builder<tag>::type builder_type;
|
||||
boost::fusion::at_key<builder_type>(builders)(std::forward<T>(value));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct get_initializers_result
|
||||
{
|
||||
typedef typename T::result_type type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct get_initializers_result<boost::fusion::void_>
|
||||
{
|
||||
typedef boost::fusion::void_ type;
|
||||
};
|
||||
|
||||
template<typename ...Args>
|
||||
struct helper_vector
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
template<typename T, typename ...Stack>
|
||||
struct invoke_get_initializer_collect_keys;
|
||||
|
||||
template<typename ...Stack>
|
||||
struct invoke_get_initializer_collect_keys<boost::fusion::vector<>, Stack...>
|
||||
{
|
||||
typedef helper_vector<Stack...> type;
|
||||
};
|
||||
|
||||
|
||||
template<typename First, typename ...Args, typename ...Stack>
|
||||
struct invoke_get_initializer_collect_keys<boost::fusion::vector<First, Args...>, Stack...>
|
||||
{
|
||||
typedef typename invoke_get_initializer_collect_keys<boost::fusion::vector<Args...>, Stack..., First>::type next;
|
||||
typedef helper_vector<Stack...> stack_t;
|
||||
|
||||
typedef typename std::conditional<std::is_same<boost::fusion::void_, First>::value,
|
||||
stack_t, next>::type type;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<typename Keys>
|
||||
struct invoke_get_initializer;
|
||||
|
||||
template<typename ...Args>
|
||||
struct invoke_get_initializer<helper_vector<Args...>>
|
||||
|
||||
{
|
||||
typedef boost::fusion::tuple<typename get_initializers_result<Args>::type...> result_type;
|
||||
|
||||
template<typename Sequence>
|
||||
static result_type call(Sequence & seq)
|
||||
{
|
||||
return result_type(boost::fusion::at_key<Args>(seq).get_initializer()...);;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename ...Args>
|
||||
inline boost::fusion::tuple<typename get_initializers_result<Args>::type...>
|
||||
get_initializers(boost::fusion::set<Args...> & builders)
|
||||
{
|
||||
//typedef boost::fusion::tuple<typename get_initializers_result<Args>::type...> return_type;
|
||||
typedef typename invoke_get_initializer_collect_keys<boost::fusion::vector<Args...>>::type keys;
|
||||
return invoke_get_initializer<keys>::call(builders);
|
||||
}
|
||||
|
||||
|
||||
template<typename Char, typename ... Args>
|
||||
inline child basic_execute_impl(Args && ... args)
|
||||
{
|
||||
//create a tuple from the argument list
|
||||
boost::fusion::tuple<typename std::remove_reference<Args>::type&...> tup(args...);
|
||||
|
||||
auto inits = boost::fusion::filter_if<
|
||||
boost::process::v1::detail::is_initializer<
|
||||
typename std::remove_reference<
|
||||
boost::mpl::_
|
||||
>::type
|
||||
>
|
||||
>(tup);
|
||||
|
||||
auto others = boost::fusion::filter_if<
|
||||
boost::mpl::not_<
|
||||
boost::process::v1::detail::is_initializer<
|
||||
typename std::remove_reference<
|
||||
boost::mpl::_
|
||||
>::type
|
||||
>
|
||||
>
|
||||
>(tup);
|
||||
|
||||
// typename detail::make_builders_from_view<decltype(others)>::type builders;
|
||||
|
||||
//typedef typename boost::fusion::result_of::as_vector<decltype(inits)>::type inits_t;
|
||||
typedef typename boost::fusion::result_of::as_vector<decltype(others)>::type others_t;
|
||||
// typedef decltype(others) others_t;
|
||||
typedef typename ::boost::process::v1::detail::make_builders_from_view<
|
||||
typename boost::fusion::result_of::begin<others_t>::type,
|
||||
typename boost::fusion::result_of::end <others_t>::type>::type builder_t;
|
||||
|
||||
builder_t builders;
|
||||
::boost::process::v1::detail::builder_ref<builder_t> builder_ref(builders);
|
||||
|
||||
boost::fusion::for_each(others, builder_ref);
|
||||
auto other_inits = ::boost::process::v1::detail::get_initializers(builders);
|
||||
|
||||
|
||||
boost::fusion::joint_view<decltype(other_inits), decltype(inits)> complete_inits(other_inits, inits);
|
||||
|
||||
auto exec = boost::process::v1::detail::api::make_executor<Char>(complete_inits);
|
||||
return exec();
|
||||
}
|
||||
|
||||
template<typename ...Args>
|
||||
inline child execute_impl(Args&& ... args)
|
||||
{
|
||||
typedef required_char_type_t<Args...> req_char_type;
|
||||
|
||||
return basic_execute_impl<req_char_type>(
|
||||
boost::process::v1::detail::char_converter_t<req_char_type, Args>::conv(
|
||||
std::forward<Args>(args))...
|
||||
);
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
73
include/boost/process/v1/detail/handler.hpp
Normal file
73
include/boost/process/v1/detail/handler.hpp
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_HANDLER_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_HANDLER_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/v1/detail/windows/handler.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
|
||||
//extended handler base.
|
||||
typedef api::handler_base_ext handler;
|
||||
|
||||
|
||||
template <class Handler>
|
||||
struct on_setup_ : handler
|
||||
{
|
||||
explicit on_setup_(Handler handler) : handler_(handler) {}
|
||||
|
||||
template <class Executor>
|
||||
void on_setup(Executor &e)
|
||||
{
|
||||
handler_(e);
|
||||
}
|
||||
private:
|
||||
Handler handler_;
|
||||
};
|
||||
|
||||
template <class Handler>
|
||||
struct on_error_ : handler
|
||||
{
|
||||
explicit on_error_(Handler handler) : handler_(handler) {}
|
||||
|
||||
template <class Executor>
|
||||
void on_error(Executor &e, const std::error_code &ec)
|
||||
{
|
||||
handler_(e, ec);
|
||||
}
|
||||
private:
|
||||
Handler handler_;
|
||||
};
|
||||
|
||||
template <class Handler>
|
||||
struct on_success_ : handler
|
||||
{
|
||||
explicit on_success_(Handler handler) : handler_(handler) {}
|
||||
|
||||
template <class Executor>
|
||||
void on_success(Executor &e)
|
||||
{
|
||||
handler_(e);
|
||||
}
|
||||
private:
|
||||
Handler handler_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */
|
||||
50
include/boost/process/v1/detail/handler_base.hpp
Normal file
50
include/boost/process/v1/detail/handler_base.hpp
Normal file
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_HANDLER_BASE_HPP
|
||||
#define BOOST_PROCESS_DETAIL_HANDLER_BASE_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <system_error>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
|
||||
template<template <class> class Template>
|
||||
struct make_handler_t
|
||||
{
|
||||
constexpr make_handler_t() {}
|
||||
template<typename Handler>
|
||||
constexpr Template<Handler> operator()(Handler handler) const {return Template<Handler>(handler);}
|
||||
template<typename Handler>
|
||||
constexpr Template<Handler> operator= (Handler handler) const {return Template<Handler>(handler);}
|
||||
template<typename Handler>
|
||||
constexpr Template<Handler> operator+=(Handler handler) const {return Template<Handler>(handler);}
|
||||
};
|
||||
|
||||
|
||||
struct handler_base
|
||||
{
|
||||
using resource_type = void;
|
||||
|
||||
template <class Executor>
|
||||
void on_setup(Executor&) const {}
|
||||
|
||||
template <class Executor>
|
||||
void on_error(Executor&, const std::error_code &) const {}
|
||||
|
||||
template <class Executor>
|
||||
void on_success(Executor&) const {}
|
||||
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
54
include/boost/process/v1/detail/on_exit.hpp
Normal file
54
include/boost/process/v1/detail/on_exit.hpp
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_ON_EXIT_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_ON_EXIT_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/v1/detail/posix/on_exit.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/v1/detail/windows/on_exit.hpp>
|
||||
#endif
|
||||
|
||||
#include <future>
|
||||
#include <memory>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
|
||||
inline std::function<void(int, const std::error_code &)> on_exit_from_future(std::future<int> &f)
|
||||
{
|
||||
std::shared_ptr<std::promise<int>> promise = std::make_shared<std::promise<int>>();
|
||||
f = promise->get_future();
|
||||
return [promise](int code, const std::error_code & ec)
|
||||
{
|
||||
if (ec)
|
||||
promise->set_exception(
|
||||
std::make_exception_ptr(process_error(ec, "on_exit failed with error"))
|
||||
);
|
||||
else
|
||||
promise->set_value(code);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
struct on_exit_
|
||||
{
|
||||
api::on_exit_ operator= (const std::function<void(int, const std::error_code&)> & f) const {return f;}
|
||||
api::on_exit_ operator()(const std::function<void(int, const std::error_code&)> & f) const {return f;}
|
||||
|
||||
api::on_exit_ operator= (std::future<int> &f) const {return on_exit_from_future(f);}
|
||||
api::on_exit_ operator()(std::future<int> &f) const {return on_exit_from_future(f);}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
constexpr static ::boost::process::v1::detail::on_exit_ on_exit{};
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_ */
|
||||
66
include/boost/process/v1/detail/posix/asio_fwd.hpp
Normal file
66
include/boost/process/v1/detail/posix/asio_fwd.hpp
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_ASIO_FWD_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_ASIO_FWD_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <boost/asio/ts/netfwd.hpp>
|
||||
|
||||
namespace boost { namespace asio {
|
||||
|
||||
class mutable_buffer;
|
||||
class mutable_buffers_1;
|
||||
|
||||
class const_buffer;
|
||||
class const_buffers_1;
|
||||
|
||||
template<typename Allocator>
|
||||
class basic_streambuf;
|
||||
|
||||
typedef basic_streambuf<std::allocator<char>> streambuf;
|
||||
|
||||
template <typename Executor>
|
||||
class basic_signal_set;
|
||||
typedef basic_signal_set<any_io_executor> signal_set;
|
||||
|
||||
template <typename Handler>
|
||||
class basic_yield_context;
|
||||
|
||||
namespace posix {
|
||||
|
||||
template <typename Executor>
|
||||
class basic_stream_descriptor;
|
||||
typedef basic_stream_descriptor<any_io_executor> stream_descriptor;
|
||||
|
||||
} //posix
|
||||
} //asio
|
||||
|
||||
namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
class async_pipe;
|
||||
|
||||
template<typename T>
|
||||
struct async_in_buffer;
|
||||
|
||||
template<int p1, int p2, typename Buffer>
|
||||
struct async_out_buffer;
|
||||
|
||||
template<int p1, int p2, typename Type>
|
||||
struct async_out_future;
|
||||
|
||||
} // posix
|
||||
} // detail
|
||||
|
||||
using ::boost::process::v1::detail::posix::async_pipe;
|
||||
|
||||
} // v1
|
||||
} // process
|
||||
} // boost
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_POSIX_ASIO_FWD_HPP_ */
|
||||
40
include/boost/process/v1/detail/posix/async_handler.hpp
Normal file
40
include/boost/process/v1/detail/posix/async_handler.hpp
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_POSIX_ASYNC_HANDLER_HPP_
|
||||
#define BOOST_PROCESS_POSIX_ASYNC_HANDLER_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
struct require_io_context {};
|
||||
|
||||
struct async_handler : handler_base_ext, require_io_context
|
||||
{
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct is_async_handler : std::is_base_of<async_handler, T> {};
|
||||
template<typename T>
|
||||
struct is_async_handler<T&> : std::is_base_of<async_handler, T> {};
|
||||
template<typename T>
|
||||
struct is_async_handler<const T&> : std::is_base_of<async_handler, T> {};
|
||||
|
||||
template<typename T>
|
||||
struct does_require_io_context : std::is_base_of<require_io_context, T> {};
|
||||
|
||||
template<typename T>
|
||||
struct does_require_io_context<T&> : std::is_base_of<require_io_context, T> {};
|
||||
|
||||
template<typename T>
|
||||
struct does_require_io_context<const T&> : std::is_base_of<require_io_context, T> {};
|
||||
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_ */
|
||||
111
include/boost/process/v1/detail/posix/async_in.hpp
Normal file
111
include/boost/process/v1/detail/posix/async_in.hpp
Normal file
@@ -0,0 +1,111 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_ASYNC_IN_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_ASYNC_IN_HPP
|
||||
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
#include <boost/process/v1/detail/posix/async_handler.hpp>
|
||||
#include <boost/asio/write.hpp>
|
||||
#include <boost/process/v1/async_pipe.hpp>
|
||||
#include <memory>
|
||||
#include <future>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
|
||||
template<typename Buffer>
|
||||
struct async_in_buffer : ::boost::process::v1::detail::posix::handler_base_ext,
|
||||
::boost::process::v1::detail::posix::require_io_context,
|
||||
::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
Buffer & buf;
|
||||
|
||||
std::shared_ptr<std::promise<void>> promise;
|
||||
async_in_buffer operator>(std::future<void> & fut)
|
||||
{
|
||||
promise = std::make_shared<std::promise<void>>();
|
||||
fut = promise->get_future(); return std::move(*this);
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<boost::process::v1::async_pipe> pipe;
|
||||
|
||||
async_in_buffer(Buffer & buf) : buf(buf)
|
||||
{
|
||||
}
|
||||
template <typename Executor>
|
||||
inline void on_success(Executor)
|
||||
{
|
||||
auto pipe_ = this->pipe;
|
||||
if (this->promise)
|
||||
{
|
||||
auto promise_ = this->promise;
|
||||
|
||||
boost::asio::async_write(*pipe_, buf,
|
||||
[pipe_, promise_](const boost::system::error_code & ec, std::size_t)
|
||||
{
|
||||
if (ec && (ec.value() != EBADF) && (ec.value() != EPERM) && (ec.value() != ENOENT))
|
||||
{
|
||||
std::error_code e(ec.value(), std::system_category());
|
||||
promise_->set_exception(std::make_exception_ptr(process_error(e)));
|
||||
}
|
||||
else
|
||||
promise_->set_value();
|
||||
});
|
||||
}
|
||||
else
|
||||
boost::asio::async_write(*pipe_, buf,
|
||||
[pipe_](const boost::system::error_code&, std::size_t){});
|
||||
|
||||
std::move(*pipe_).source().close();
|
||||
|
||||
this->pipe = nullptr;
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor &, const std::error_code &) const
|
||||
{
|
||||
std::move(*pipe).source().close();
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_setup(Executor & exec)
|
||||
{
|
||||
if (!pipe)
|
||||
pipe = std::make_shared<boost::process::v1::async_pipe>(get_io_context(exec.seq));
|
||||
}
|
||||
|
||||
std::array<int, 3> get_used_handles()
|
||||
{
|
||||
if (pipe)
|
||||
return {STDIN_FILENO, pipe->native_source(), pipe->native_sink()};
|
||||
else //if pipe is not constructed, limit_ds is invoked before -> this also means on_exec_setup gets invoked before.
|
||||
return {STDIN_FILENO, STDIN_FILENO, STDIN_FILENO};
|
||||
}
|
||||
|
||||
|
||||
template <typename Executor>
|
||||
void on_exec_setup(Executor &exec)
|
||||
{
|
||||
if (::dup2(pipe->native_source(), STDIN_FILENO) == -1)
|
||||
exec.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
if (pipe->native_source() != STDIN_FILENO)
|
||||
::close(pipe->native_source());
|
||||
::close(pipe->native_sink());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
190
include/boost/process/v1/detail/posix/async_out.hpp
Normal file
190
include/boost/process/v1/detail/posix/async_out.hpp
Normal file
@@ -0,0 +1,190 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_ASYNC_OUT_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_ASYNC_OUT_HPP
|
||||
|
||||
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <boost/asio/posix/stream_descriptor.hpp>
|
||||
#include <boost/asio/read.hpp>
|
||||
#include <boost/process/v1/async_pipe.hpp>
|
||||
#include <istream>
|
||||
#include <memory>
|
||||
#include <exception>
|
||||
#include <future>
|
||||
#include <array>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
|
||||
inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::integral_constant<int, -1>)
|
||||
{
|
||||
return ::dup2(handle, STDOUT_FILENO);
|
||||
}
|
||||
|
||||
inline int apply_out_handles(int handle, std::integral_constant<int, 2>, std::integral_constant<int, -1>)
|
||||
{
|
||||
return ::dup2(handle, STDERR_FILENO);
|
||||
}
|
||||
|
||||
inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::integral_constant<int, 2>)
|
||||
{
|
||||
if (::dup2(handle, STDOUT_FILENO) == -1)
|
||||
return -1;
|
||||
if (::dup2(handle, STDERR_FILENO) == -1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<int p1, int p2, typename Buffer>
|
||||
struct async_out_buffer : ::boost::process::v1::detail::posix::handler_base_ext,
|
||||
::boost::process::v1::detail::posix::require_io_context,
|
||||
::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
Buffer & buf;
|
||||
|
||||
std::shared_ptr<boost::process::v1::async_pipe> pipe;
|
||||
|
||||
std::array<int, 4> get_used_handles()
|
||||
{
|
||||
const auto pp1 = p1 != -1 ? p1 : p2;
|
||||
const auto pp2 = p2 != -1 ? p2 : p1;
|
||||
|
||||
if (pipe)
|
||||
return {pipe->native_source(), pipe->native_sink(), pp1, pp2};
|
||||
else //if pipe is not constructed, limit_ds is invoked before -> this also means on_exec_setup gets invoked before.
|
||||
return {pp1, pp2, pp1, pp2};
|
||||
}
|
||||
|
||||
|
||||
async_out_buffer(Buffer & buf) : buf(buf)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Executor>
|
||||
inline void on_success(Executor &)
|
||||
{
|
||||
auto pipe = this->pipe;
|
||||
boost::asio::async_read(*pipe, buf,
|
||||
[pipe](const boost::system::error_code&, std::size_t){});
|
||||
|
||||
this->pipe = nullptr;
|
||||
std::move(*pipe).sink().close();
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor &, const std::error_code &) const
|
||||
{
|
||||
std::move(*pipe).sink().close();
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_setup(Executor & exec)
|
||||
{
|
||||
pipe = std::make_shared<boost::process::v1::async_pipe>(get_io_context(exec.seq));
|
||||
}
|
||||
|
||||
|
||||
template <typename Executor>
|
||||
void on_exec_setup(Executor &exec)
|
||||
{
|
||||
int res = apply_out_handles(pipe->native_sink(),
|
||||
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
|
||||
if (res == -1)
|
||||
exec.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
::close(pipe->native_sink());
|
||||
::close(pipe->native_source());
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<int p1, int p2, typename Type>
|
||||
struct async_out_future : ::boost::process::v1::detail::posix::handler_base_ext,
|
||||
::boost::process::v1::detail::posix::require_io_context
|
||||
{
|
||||
std::shared_ptr<std::promise<Type>> promise = std::make_shared<std::promise<Type>>();
|
||||
|
||||
std::shared_ptr<boost::asio::streambuf> buffer = std::make_shared<boost::asio::streambuf>();
|
||||
|
||||
std::shared_ptr<boost::process::v1::async_pipe> pipe;
|
||||
|
||||
async_out_future(std::future<Type> & fut)
|
||||
{
|
||||
fut = promise->get_future();
|
||||
}
|
||||
template <typename Executor>
|
||||
inline void on_success(Executor &)
|
||||
{
|
||||
auto pipe_ = this->pipe;
|
||||
|
||||
auto buffer_ = this->buffer;
|
||||
auto promise_ = this->promise;
|
||||
|
||||
boost::asio::async_read(*pipe_, *buffer_,
|
||||
[pipe_, buffer_, promise_](const boost::system::error_code& ec, std::size_t)
|
||||
{
|
||||
if (ec && (ec.value() != ENOENT))
|
||||
{
|
||||
std::error_code e(ec.value(), std::system_category());
|
||||
promise_->set_exception(std::make_exception_ptr(process_error(e)));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::istream is (buffer_.get());
|
||||
Type arg;
|
||||
if (buffer_->size() > 0)
|
||||
{
|
||||
arg.resize(buffer_->size());
|
||||
is.read(&*arg.begin(), buffer_->size());
|
||||
}
|
||||
promise_->set_value(std::move(arg));
|
||||
}
|
||||
});
|
||||
|
||||
std::move(*pipe_).sink().close();
|
||||
this->pipe = nullptr;
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor &, const std::error_code &) const
|
||||
{
|
||||
std::move(*pipe).sink().close();
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_setup(Executor & exec)
|
||||
{
|
||||
pipe = std::make_shared<boost::process::v1::async_pipe>(get_io_context(exec.seq));
|
||||
}
|
||||
|
||||
template <typename Executor>
|
||||
void on_exec_setup(Executor &exec)
|
||||
{
|
||||
|
||||
int res = apply_out_handles(pipe->native_sink(),
|
||||
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
|
||||
if (res == -1)
|
||||
exec.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
::close(pipe->native_sink());
|
||||
::close(pipe->native_source());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
365
include/boost/process/v1/detail/posix/async_pipe.hpp
Normal file
365
include/boost/process/v1/detail/posix/async_pipe.hpp
Normal file
@@ -0,0 +1,365 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_ASYNC_PIPE_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_ASYNC_PIPE_HPP_
|
||||
|
||||
|
||||
#include <boost/process/v1/detail/posix/basic_pipe.hpp>
|
||||
#include <boost/asio/posix/stream_descriptor.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <system_error>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
class async_pipe
|
||||
{
|
||||
::boost::asio::posix::stream_descriptor _source;
|
||||
::boost::asio::posix::stream_descriptor _sink ;
|
||||
public:
|
||||
typedef int native_handle_type;
|
||||
typedef ::boost::asio::posix::stream_descriptor handle_type;
|
||||
typedef typename handle_type::executor_type executor_type;
|
||||
|
||||
executor_type get_executor()
|
||||
{
|
||||
return _source.get_executor();
|
||||
}
|
||||
|
||||
inline async_pipe(boost::asio::io_context & ios) : async_pipe(ios, ios) {}
|
||||
|
||||
inline async_pipe(boost::asio::io_context & ios_source,
|
||||
boost::asio::io_context & ios_sink) : _source(ios_source), _sink(ios_sink)
|
||||
{
|
||||
int fds[2];
|
||||
if (::pipe(fds) == -1)
|
||||
boost::process::v1::detail::throw_last_error("pipe(2) failed");
|
||||
|
||||
_source.assign(fds[0]);
|
||||
_sink .assign(fds[1]);
|
||||
};
|
||||
inline async_pipe(boost::asio::io_context & ios, const std::string & name)
|
||||
: async_pipe(ios, ios, name) {}
|
||||
|
||||
inline async_pipe(boost::asio::io_context & ios_source,
|
||||
boost::asio::io_context & io_sink, const std::string & name);
|
||||
inline async_pipe(const async_pipe& lhs);
|
||||
async_pipe(async_pipe&& lhs) : _source(std::move(lhs._source)), _sink(std::move(lhs._sink))
|
||||
{
|
||||
lhs._source = ::boost::asio::posix::stream_descriptor{lhs._source.get_executor()};
|
||||
lhs._sink = ::boost::asio::posix::stream_descriptor{lhs._sink. get_executor()};
|
||||
}
|
||||
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
explicit async_pipe(::boost::asio::io_context & ios_source,
|
||||
::boost::asio::io_context & ios_sink,
|
||||
const basic_pipe<CharT, Traits> & p)
|
||||
: _source(ios_source, p.native_source()), _sink(ios_sink, p.native_sink())
|
||||
{
|
||||
}
|
||||
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
explicit async_pipe(boost::asio::io_context & ios, const basic_pipe<CharT, Traits> & p)
|
||||
: async_pipe(ios, ios, p)
|
||||
{
|
||||
}
|
||||
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
inline async_pipe& operator=(const basic_pipe<CharT, Traits>& p);
|
||||
inline async_pipe& operator=(const async_pipe& rhs);
|
||||
|
||||
inline async_pipe& operator=(async_pipe&& lhs);
|
||||
|
||||
~async_pipe()
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
close(ec);
|
||||
}
|
||||
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
inline explicit operator basic_pipe<CharT, Traits>() const;
|
||||
|
||||
void cancel()
|
||||
{
|
||||
if (_sink.is_open())
|
||||
_sink.cancel();
|
||||
if (_source.is_open())
|
||||
_source.cancel();
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
if (_sink.is_open())
|
||||
_sink.close();
|
||||
if (_source.is_open())
|
||||
_source.close();
|
||||
}
|
||||
void close(boost::system::error_code & ec)
|
||||
{
|
||||
if (_sink.is_open())
|
||||
_sink.close(ec);
|
||||
if (_source.is_open())
|
||||
_source.close(ec);
|
||||
}
|
||||
|
||||
|
||||
bool is_open() const
|
||||
{
|
||||
return _sink.is_open() || _source.is_open();
|
||||
}
|
||||
void async_close()
|
||||
{
|
||||
if (_sink.is_open())
|
||||
boost::asio::post(_sink.get_executor(), [this]{_sink.close();});
|
||||
if (_source.is_open())
|
||||
boost::asio::post(_source.get_executor(), [this]{_source.close();});
|
||||
}
|
||||
|
||||
template<typename MutableBufferSequence>
|
||||
std::size_t read_some(const MutableBufferSequence & buffers)
|
||||
{
|
||||
return _source.read_some(buffers);
|
||||
}
|
||||
template<typename MutableBufferSequence>
|
||||
std::size_t write_some(const MutableBufferSequence & buffers)
|
||||
{
|
||||
return _sink.write_some(buffers);
|
||||
}
|
||||
|
||||
template<typename MutableBufferSequence>
|
||||
std::size_t read_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
|
||||
{
|
||||
return _source.read_some(buffers, ec);
|
||||
}
|
||||
template<typename MutableBufferSequence>
|
||||
std::size_t write_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
|
||||
{
|
||||
return _sink.write_some(buffers, ec);
|
||||
}
|
||||
|
||||
|
||||
native_handle_type native_source() const {return const_cast<boost::asio::posix::stream_descriptor&>(_source).native_handle();}
|
||||
native_handle_type native_sink () const {return const_cast<boost::asio::posix::stream_descriptor&>(_sink ).native_handle();}
|
||||
|
||||
template<typename MutableBufferSequence,
|
||||
typename ReadHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
ReadHandler, void(boost::system::error_code, std::size_t))
|
||||
async_read_some(
|
||||
const MutableBufferSequence & buffers,
|
||||
ReadHandler &&handler)
|
||||
{
|
||||
return _source.async_read_some(buffers, std::forward<ReadHandler>(handler));
|
||||
}
|
||||
|
||||
template<typename ConstBufferSequence,
|
||||
typename WriteHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
WriteHandler, void(boost::system::error_code, std::size_t))
|
||||
async_write_some(
|
||||
const ConstBufferSequence & buffers,
|
||||
WriteHandler&& handler)
|
||||
{
|
||||
return _sink.async_write_some(buffers, std::forward<WriteHandler>(handler));
|
||||
}
|
||||
|
||||
|
||||
const handle_type & sink () const & {return _sink;}
|
||||
const handle_type & source() const & {return _source;}
|
||||
|
||||
handle_type && sink() && { return std::move(_sink); }
|
||||
handle_type && source()&& { return std::move(_source); }
|
||||
|
||||
handle_type source(::boost::asio::io_context& ios) &&
|
||||
{
|
||||
::boost::asio::posix::stream_descriptor stolen(ios, _source.release());
|
||||
return stolen;
|
||||
}
|
||||
handle_type sink (::boost::asio::io_context& ios) &&
|
||||
{
|
||||
::boost::asio::posix::stream_descriptor stolen(ios, _sink.release());
|
||||
return stolen;
|
||||
}
|
||||
|
||||
handle_type source(::boost::asio::io_context& ios) const &
|
||||
{
|
||||
auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle();
|
||||
return ::boost::asio::posix::stream_descriptor(ios, ::dup(source_in));
|
||||
}
|
||||
handle_type sink (::boost::asio::io_context& ios) const &
|
||||
{
|
||||
auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle();
|
||||
return ::boost::asio::posix::stream_descriptor(ios, ::dup(sink_in));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
async_pipe::async_pipe(boost::asio::io_context & ios_source,
|
||||
boost::asio::io_context & ios_sink,
|
||||
const std::string & name) : _source(ios_source), _sink(ios_sink)
|
||||
{
|
||||
auto fifo = mkfifo(name.c_str(), 0666 );
|
||||
|
||||
if (fifo != 0)
|
||||
boost::process::v1::detail::throw_last_error("mkfifo() failed");
|
||||
|
||||
|
||||
int read_fd = open(name.c_str(), O_RDWR);
|
||||
|
||||
if (read_fd == -1)
|
||||
boost::process::v1::detail::throw_last_error();
|
||||
|
||||
int write_fd = dup(read_fd);
|
||||
|
||||
if (write_fd == -1)
|
||||
boost::process::v1::detail::throw_last_error();
|
||||
|
||||
_source.assign(read_fd);
|
||||
_sink .assign(write_fd);
|
||||
}
|
||||
|
||||
async_pipe::async_pipe(const async_pipe & p) :
|
||||
_source(const_cast<async_pipe&>(p)._source.get_executor()),
|
||||
_sink( const_cast<async_pipe&>(p)._sink.get_executor())
|
||||
{
|
||||
|
||||
//cannot get the handle from a const object.
|
||||
auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle();
|
||||
auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle();
|
||||
if (source_in == -1)
|
||||
_source.assign(-1);
|
||||
else
|
||||
{
|
||||
_source.assign(::dup(source_in));
|
||||
if (_source.native_handle()== -1)
|
||||
::boost::process::v1::detail::throw_last_error("dup()");
|
||||
}
|
||||
|
||||
if (sink_in == -1)
|
||||
_sink.assign(-1);
|
||||
else
|
||||
{
|
||||
_sink.assign(::dup(sink_in));
|
||||
if (_sink.native_handle() == -1)
|
||||
::boost::process::v1::detail::throw_last_error("dup()");
|
||||
}
|
||||
}
|
||||
|
||||
async_pipe& async_pipe::operator=(const async_pipe & p)
|
||||
{
|
||||
int source;
|
||||
int sink;
|
||||
|
||||
//cannot get the handle from a const object.
|
||||
auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(p._source).native_handle();
|
||||
auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(p._sink).native_handle();
|
||||
if (source_in == -1)
|
||||
source = -1;
|
||||
else
|
||||
{
|
||||
source = ::dup(source_in);
|
||||
if (source == -1)
|
||||
::boost::process::v1::detail::throw_last_error("dup()");
|
||||
}
|
||||
|
||||
if (sink_in == -1)
|
||||
sink = -1;
|
||||
else
|
||||
{
|
||||
sink = ::dup(sink_in);
|
||||
if (sink == -1)
|
||||
::boost::process::v1::detail::throw_last_error("dup()");
|
||||
}
|
||||
_source.assign(source);
|
||||
_sink. assign(sink);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
async_pipe& async_pipe::operator=(async_pipe && lhs)
|
||||
{
|
||||
std::swap(_source, lhs._source);
|
||||
std::swap(_sink, lhs._sink);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class CharT, class Traits>
|
||||
async_pipe::operator basic_pipe<CharT, Traits>() const
|
||||
{
|
||||
int source;
|
||||
int sink;
|
||||
|
||||
//cannot get the handle from a const object.
|
||||
auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle();
|
||||
auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle();
|
||||
|
||||
|
||||
if (source_in == -1)
|
||||
source = -1;
|
||||
else
|
||||
{
|
||||
source = ::dup(source_in);
|
||||
if (source == -1)
|
||||
::boost::process::v1::detail::throw_last_error("dup()");
|
||||
}
|
||||
|
||||
if (sink_in == -1)
|
||||
sink = -1;
|
||||
else
|
||||
{
|
||||
sink = ::dup(sink_in);
|
||||
if (sink == -1)
|
||||
::boost::process::v1::detail::throw_last_error("dup()");
|
||||
}
|
||||
|
||||
return basic_pipe<CharT, Traits>{source, sink};
|
||||
}
|
||||
|
||||
|
||||
inline bool operator==(const async_pipe & lhs, const async_pipe & rhs)
|
||||
{
|
||||
return compare_handles(lhs.native_source(), rhs.native_source()) &&
|
||||
compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
inline bool operator!=(const async_pipe & lhs, const async_pipe & rhs)
|
||||
{
|
||||
return !compare_handles(lhs.native_source(), rhs.native_source()) ||
|
||||
!compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
template<class Char, class Traits>
|
||||
inline bool operator==(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs)
|
||||
{
|
||||
return compare_handles(lhs.native_source(), rhs.native_source()) &&
|
||||
compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
template<class Char, class Traits>
|
||||
inline bool operator!=(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs)
|
||||
{
|
||||
return !compare_handles(lhs.native_source(), rhs.native_source()) ||
|
||||
!compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
template<class Char, class Traits>
|
||||
inline bool operator==(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs)
|
||||
{
|
||||
return compare_handles(lhs.native_source(), rhs.native_source()) &&
|
||||
compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
template<class Char, class Traits>
|
||||
inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs)
|
||||
{
|
||||
return !compare_handles(lhs.native_source(), rhs.native_source()) ||
|
||||
!compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif /* INCLUDE_BOOST_PIPE_DETAIL_WINDOWS_ASYNC_PIPE_HPP_ */
|
||||
182
include/boost/process/v1/detail/posix/basic_cmd.hpp
Normal file
182
include/boost/process/v1/detail/posix/basic_cmd.hpp
Normal file
@@ -0,0 +1,182 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_BASIC_CMD_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_BASIC_CMD_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/detail/posix/cmd.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/process/v1/shell.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace process
|
||||
{
|
||||
BOOST_PROCESS_V1_INLINE namespace v1
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace posix
|
||||
{
|
||||
|
||||
inline std::string build_cmd_shell(const std::string & exe, std::vector<std::string> && data)
|
||||
{
|
||||
std::string st = exe;
|
||||
for (auto & arg : data)
|
||||
{
|
||||
boost::replace_all(arg, "\"", "\\\"");
|
||||
|
||||
auto it = std::find(arg.begin(), arg.end(), ' ');//contains space?
|
||||
if (it != arg.end())//ok, contains spaces.
|
||||
{
|
||||
//the first one is put directly onto the output,
|
||||
//because then I don't have to copy the whole string
|
||||
arg.insert(arg.begin(), '"' );
|
||||
arg += '"'; //that is the post one.
|
||||
}
|
||||
|
||||
if (!st.empty())//first one does not need a preceding space
|
||||
st += ' ';
|
||||
|
||||
st += arg;
|
||||
}
|
||||
return st ;
|
||||
}
|
||||
|
||||
inline std::vector<std::string> build_args(const std::string & data)
|
||||
{
|
||||
std::vector<std::string> st;
|
||||
|
||||
typedef std::string::const_iterator itr_t;
|
||||
|
||||
//normal quotes outside can be stripped, inside ones marked as \" will be replaced.
|
||||
auto make_entry = [](const itr_t & begin, const itr_t & end)
|
||||
{
|
||||
std::string data;
|
||||
if ((*begin == '"') && (*(end-1) == '"'))
|
||||
data.assign(begin+1, end-1);
|
||||
else
|
||||
data.assign(begin, end);
|
||||
|
||||
boost::replace_all(data, "\\\"", "\"");
|
||||
return data;
|
||||
|
||||
};
|
||||
|
||||
bool in_quote = false;
|
||||
|
||||
auto part_beg = data.cbegin();
|
||||
auto itr = data.cbegin();
|
||||
|
||||
for (; itr != data.cend(); itr++)
|
||||
{
|
||||
if (*itr == '"')
|
||||
in_quote ^= true;
|
||||
|
||||
if (!in_quote && (*itr == ' '))
|
||||
{
|
||||
//alright, got a space
|
||||
|
||||
if ((itr != data.cbegin()) && (*(itr -1) != ' ' ))
|
||||
st.push_back(make_entry(part_beg, itr));
|
||||
|
||||
part_beg = itr+1;
|
||||
}
|
||||
}
|
||||
if (part_beg != itr)
|
||||
st.emplace_back(make_entry(part_beg, itr));
|
||||
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
template<typename Char>
|
||||
struct exe_cmd_init;
|
||||
|
||||
template<>
|
||||
struct exe_cmd_init<char> : boost::process::v1::detail::api::handler_base_ext
|
||||
{
|
||||
exe_cmd_init(const exe_cmd_init & ) = delete;
|
||||
exe_cmd_init(exe_cmd_init && ) = default;
|
||||
exe_cmd_init(std::string && exe, std::vector<std::string> && args)
|
||||
: exe(std::move(exe)), args(std::move(args)) {};
|
||||
template <class Executor>
|
||||
void on_setup(Executor& exec)
|
||||
{
|
||||
if (exe.empty()) //cmd style
|
||||
{
|
||||
if (args.empty())
|
||||
exec.exe = "";
|
||||
else
|
||||
exec.exe = args.front().c_str();
|
||||
exec.cmd_style = true;
|
||||
}
|
||||
else
|
||||
exec.exe = &exe.front();
|
||||
|
||||
cmd_impl = make_cmd();
|
||||
exec.cmd_line = cmd_impl.data();
|
||||
}
|
||||
static exe_cmd_init exe_args(std::string && exe, std::vector<std::string> && args) {return exe_cmd_init(std::move(exe), std::move(args));}
|
||||
static exe_cmd_init cmd (std::string && cmd)
|
||||
{
|
||||
auto args = build_args(cmd);
|
||||
return exe_cmd_init({}, std::move(args));
|
||||
}
|
||||
|
||||
static exe_cmd_init exe_args_shell(std::string&& exe, std::vector<std::string> && args)
|
||||
{
|
||||
auto cmd = build_cmd_shell(std::move(exe), std::move(args));
|
||||
|
||||
std::vector<std::string> args_ = {"-c", std::move(cmd)};
|
||||
std::string sh = shell().string();
|
||||
|
||||
return exe_cmd_init(std::move(sh), std::move(args_));
|
||||
}
|
||||
static exe_cmd_init cmd_shell(std::string&& cmd)
|
||||
{
|
||||
std::vector<std::string> args = {"-c", cmd};
|
||||
std::string sh = shell().string();
|
||||
|
||||
return exe_cmd_init(
|
||||
std::move(sh),
|
||||
{std::move(args)});
|
||||
}
|
||||
private:
|
||||
inline std::vector<char*> make_cmd();
|
||||
std::string exe;
|
||||
std::vector<std::string> args;
|
||||
std::vector<char*> cmd_impl;
|
||||
};
|
||||
|
||||
std::vector<char*> exe_cmd_init<char>::make_cmd()
|
||||
{
|
||||
// any string must be writable.
|
||||
static char empty_string[1] = "";
|
||||
std::vector<char*> vec;
|
||||
if (!exe.empty())
|
||||
vec.push_back(exe.empty() ? empty_string : &exe.front());
|
||||
|
||||
if (!args.empty()) {
|
||||
for (auto & v : args)
|
||||
vec.push_back(v.empty() ? empty_string : &v.front());
|
||||
}
|
||||
|
||||
vec.push_back(nullptr);
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
200
include/boost/process/v1/detail/posix/basic_pipe.hpp
Normal file
200
include/boost/process/v1/detail/posix/basic_pipe.hpp
Normal file
@@ -0,0 +1,200 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// 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_POSIX_PIPE_HPP
|
||||
#define BOOST_PROCESS_POSIX_PIPE_HPP
|
||||
|
||||
|
||||
#include <boost/process/v1/filesystem.hpp>
|
||||
#include <boost/process/v1/detail/posix/compare_handles.hpp>
|
||||
#include <system_error>
|
||||
#include <array>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <memory>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
class basic_pipe
|
||||
{
|
||||
int _source = -1;
|
||||
int _sink = -1;
|
||||
public:
|
||||
explicit basic_pipe(int source, int sink) : _source(source), _sink(sink) {}
|
||||
explicit basic_pipe(int source, int sink, const std::string&) : _source(source), _sink(sink) {}
|
||||
typedef CharT char_type ;
|
||||
typedef Traits traits_type;
|
||||
typedef typename Traits::int_type int_type ;
|
||||
typedef typename Traits::pos_type pos_type ;
|
||||
typedef typename Traits::off_type off_type ;
|
||||
typedef int native_handle_type;
|
||||
|
||||
basic_pipe()
|
||||
{
|
||||
int fds[2];
|
||||
if (::pipe(fds) == -1)
|
||||
boost::process::v1::detail::throw_last_error("pipe(2) failed");
|
||||
|
||||
_source = fds[0];
|
||||
_sink = fds[1];
|
||||
}
|
||||
inline basic_pipe(const basic_pipe& rhs);
|
||||
explicit inline basic_pipe(const std::string& name);
|
||||
basic_pipe(basic_pipe&& lhs) : _source(lhs._source), _sink(lhs._sink)
|
||||
{
|
||||
lhs._source = -1;
|
||||
lhs._sink = -1;
|
||||
}
|
||||
inline basic_pipe& operator=(const basic_pipe& );
|
||||
basic_pipe& operator=(basic_pipe&& lhs)
|
||||
{
|
||||
_source = lhs._source;
|
||||
_sink = lhs._sink ;
|
||||
|
||||
lhs._source = -1;
|
||||
lhs._sink = -1;
|
||||
|
||||
return *this;
|
||||
}
|
||||
~basic_pipe()
|
||||
{
|
||||
if (_sink != -1)
|
||||
::close(_sink);
|
||||
if (_source != -1)
|
||||
::close(_source);
|
||||
}
|
||||
native_handle_type native_source() const {return _source;}
|
||||
native_handle_type native_sink () const {return _sink;}
|
||||
|
||||
void assign_source(native_handle_type h) { _source = h;}
|
||||
void assign_sink (native_handle_type h) { _sink = h;}
|
||||
|
||||
int_type write(const char_type * data, int_type count)
|
||||
{
|
||||
ssize_t write_len;
|
||||
while ((write_len = ::write(_sink, data, count * sizeof(char_type))) == -1)
|
||||
{
|
||||
//Try again if interrupted
|
||||
auto err = errno;
|
||||
if (err != EINTR)
|
||||
::boost::process::v1::detail::throw_last_error();
|
||||
}
|
||||
return static_cast<int_type>(write_len);
|
||||
}
|
||||
int_type read(char_type * data, int_type count)
|
||||
{
|
||||
ssize_t read_len;
|
||||
while ((read_len = ::read(_source, data, count * sizeof(char_type))) == -1)
|
||||
{
|
||||
//Try again if interrupted
|
||||
auto err = errno;
|
||||
if (err != EINTR)
|
||||
::boost::process::v1::detail::throw_last_error();
|
||||
}
|
||||
return static_cast<int_type>(read_len);
|
||||
}
|
||||
|
||||
bool is_open() const
|
||||
{
|
||||
return (_source != -1) ||
|
||||
(_sink != -1);
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
if (_source != -1)
|
||||
::close(_source);
|
||||
if (_sink != -1)
|
||||
::close(_sink);
|
||||
_source = -1;
|
||||
_sink = -1;
|
||||
}
|
||||
};
|
||||
|
||||
template<class CharT, class Traits>
|
||||
basic_pipe<CharT, Traits>::basic_pipe(const basic_pipe & rhs)
|
||||
{
|
||||
if (rhs._source != -1)
|
||||
{
|
||||
_source = ::dup(rhs._source);
|
||||
if (_source == -1)
|
||||
::boost::process::v1::detail::throw_last_error("dup() failed");
|
||||
}
|
||||
if (rhs._sink != -1)
|
||||
{
|
||||
_sink = ::dup(rhs._sink);
|
||||
if (_sink == -1)
|
||||
::boost::process::v1::detail::throw_last_error("dup() failed");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
template<class CharT, class Traits>
|
||||
basic_pipe<CharT, Traits> &basic_pipe<CharT, Traits>::operator=(const basic_pipe & rhs)
|
||||
{
|
||||
if (rhs._source != -1)
|
||||
{
|
||||
_source = ::dup(rhs._source);
|
||||
if (_source == -1)
|
||||
::boost::process::v1::detail::throw_last_error("dup() failed");
|
||||
}
|
||||
if (rhs._sink != -1)
|
||||
{
|
||||
_sink = ::dup(rhs._sink);
|
||||
if (_sink == -1)
|
||||
::boost::process::v1::detail::throw_last_error("dup() failed");
|
||||
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
template<class CharT, class Traits>
|
||||
basic_pipe<CharT, Traits>::basic_pipe(const std::string & name)
|
||||
{
|
||||
auto fifo = mkfifo(name.c_str(), 0666 );
|
||||
|
||||
if (fifo != 0)
|
||||
boost::process::v1::detail::throw_last_error("mkfifo() failed");
|
||||
|
||||
|
||||
int read_fd = open(name.c_str(), O_RDWR);
|
||||
|
||||
if (read_fd == -1)
|
||||
boost::process::v1::detail::throw_last_error();
|
||||
|
||||
int write_fd = dup(read_fd);
|
||||
|
||||
if (write_fd == -1)
|
||||
boost::process::v1::detail::throw_last_error();
|
||||
|
||||
_sink = write_fd;
|
||||
_source = read_fd;
|
||||
::unlink(name.c_str());
|
||||
}
|
||||
|
||||
template<class Char, class Traits>
|
||||
inline bool operator==(const basic_pipe<Char, Traits> & lhs, const basic_pipe<Char, Traits> & rhs)
|
||||
{
|
||||
return compare_handles(lhs.native_source(), rhs.native_source()) &&
|
||||
compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
template<class Char, class Traits>
|
||||
inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const basic_pipe<Char, Traits> & rhs)
|
||||
{
|
||||
return !compare_handles(lhs.native_source(), rhs.native_source()) ||
|
||||
!compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
60
include/boost/process/v1/detail/posix/child_handle.hpp
Normal file
60
include/boost/process/v1/detail/posix/child_handle.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// 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_POSIX_CHILD_HPP
|
||||
#define BOOST_PROCESS_POSIX_CHILD_HPP
|
||||
|
||||
#include <utility>
|
||||
#include <system_error>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
typedef ::pid_t pid_t;
|
||||
|
||||
struct child_handle
|
||||
{
|
||||
int pid {-1};
|
||||
explicit child_handle(int pid) : pid(pid)
|
||||
{}
|
||||
|
||||
child_handle() = default;
|
||||
~child_handle() = default;
|
||||
|
||||
child_handle(const child_handle & c) = delete;
|
||||
child_handle(child_handle && c) : pid(c.pid)
|
||||
{
|
||||
c.pid = -1;
|
||||
}
|
||||
child_handle &operator=(const child_handle & c) = delete;
|
||||
child_handle &operator=(child_handle && c)
|
||||
{
|
||||
pid = c.pid;
|
||||
c.pid = -1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
int id() const
|
||||
{
|
||||
return pid;
|
||||
}
|
||||
bool in_group() const {return true;}
|
||||
bool in_group(std::error_code&) const noexcept {return true;}
|
||||
|
||||
typedef int process_handle_t;
|
||||
process_handle_t process_handle() const { return pid; }
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
return pid != -1;
|
||||
}
|
||||
};
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
34
include/boost/process/v1/detail/posix/close_in.hpp
Normal file
34
include/boost/process/v1/detail/posix/close_in.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// 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_WINDOWS_INITIALIZERS_CLOSE_IN_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_CLOSE_IN_HPP
|
||||
|
||||
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
struct close_in : handler_base_ext, ::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
template <class Executor>
|
||||
void on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::close(STDIN_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
|
||||
}
|
||||
|
||||
int get_used_handles() {return STDIN_FILENO;}
|
||||
|
||||
};
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
58
include/boost/process/v1/detail/posix/close_out.hpp
Normal file
58
include/boost/process/v1/detail/posix/close_out.hpp
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_CLOSE_OUT_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_CLOSE_OUT_HPP
|
||||
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
template<int p1, int p2>
|
||||
struct close_out : handler_base_ext
|
||||
{
|
||||
template <class Executor>
|
||||
inline void on_exec_setup(Executor &e) const;
|
||||
|
||||
std::array<int, 2> get_used_handles() {return {{p1 != -1 ? p1 : p2, p2 != -1 ? p2 : p1}};}
|
||||
};
|
||||
|
||||
template<>
|
||||
template<typename Executor>
|
||||
void close_out<1,-1>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::close(STDOUT_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename Executor>
|
||||
void close_out<2,-1>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::close(STDERR_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename Executor>
|
||||
void close_out<1,2>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::close(STDOUT_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
|
||||
|
||||
if (::close(STDERR_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
106
include/boost/process/v1/detail/posix/cmd.hpp
Normal file
106
include/boost/process/v1/detail/posix/cmd.hpp
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_CMD_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_CMD_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace process
|
||||
{
|
||||
BOOST_PROCESS_V1_INLINE namespace v1
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace posix
|
||||
{
|
||||
|
||||
|
||||
template<typename Char>
|
||||
inline std::vector<std::basic_string<Char>> build_cmd(const std::basic_string<Char> & value)
|
||||
{
|
||||
std::vector<std::basic_string<Char>> ret;
|
||||
|
||||
bool in_quotes = false;
|
||||
auto beg = value.begin();
|
||||
for (auto itr = value.begin(); itr != value.end(); itr++)
|
||||
{
|
||||
if (*itr == quote_sign<Char>())
|
||||
in_quotes = !in_quotes;
|
||||
|
||||
if (!in_quotes && (*itr == space_sign<Char>()))
|
||||
{
|
||||
if (itr != beg)
|
||||
{
|
||||
ret.emplace_back(beg, itr);
|
||||
beg = itr + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (beg != value.end())
|
||||
ret.emplace_back(beg, value.end());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename Char>
|
||||
struct cmd_setter_ : handler_base_ext
|
||||
{
|
||||
typedef Char value_type;
|
||||
typedef std::basic_string<value_type> string_type;
|
||||
|
||||
cmd_setter_(string_type && cmd_line) : _cmd_line(api::build_cmd(std::move(cmd_line))) {}
|
||||
cmd_setter_(const string_type & cmd_line) : _cmd_line(api::build_cmd(cmd_line)) {}
|
||||
template <class Executor>
|
||||
void on_setup(Executor& exec)
|
||||
{
|
||||
exec.exe = _cmd_impl.front();
|
||||
exec.cmd_line = &_cmd_impl.front();
|
||||
exec.cmd_style = true;
|
||||
}
|
||||
string_type str() const
|
||||
{
|
||||
string_type ret;
|
||||
std::size_t size = 0;
|
||||
for (auto & cmd : _cmd_line)
|
||||
size += cmd.size() + 1;
|
||||
ret.reserve(size -1);
|
||||
|
||||
for (auto & cmd : _cmd_line)
|
||||
{
|
||||
if (!ret.empty())
|
||||
ret += equal_sign<Char>();
|
||||
ret += cmd;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
private:
|
||||
static inline std::vector<Char*> make_cmd(std::vector<string_type> & args);
|
||||
std::vector<string_type> _cmd_line;
|
||||
std::vector<Char*> _cmd_impl = make_cmd(_cmd_line);
|
||||
};
|
||||
|
||||
template<typename Char>
|
||||
std::vector<Char*> cmd_setter_<Char>::make_cmd(std::vector<std::basic_string<Char>> & args)
|
||||
{
|
||||
std::vector<Char*> vec;
|
||||
|
||||
for (auto & v : args)
|
||||
vec.push_back(&v.front());
|
||||
|
||||
vec.push_back(nullptr);
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
42
include/boost/process/v1/detail/posix/compare_handles.hpp
Normal file
42
include/boost/process/v1/detail/posix/compare_handles.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_COMPARE_HANDLES_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_COMPARE_HANDLES_HPP_
|
||||
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
|
||||
inline bool compare_handles(int lhs, int rhs)
|
||||
{
|
||||
|
||||
if ((lhs == -1) || (rhs == -1))
|
||||
return false;
|
||||
|
||||
if (lhs == rhs)
|
||||
return true;
|
||||
|
||||
struct stat stat1, stat2;
|
||||
if(fstat(lhs, &stat1) < 0) ::boost::process::v1::detail::throw_last_error("fstat() failed");
|
||||
if(fstat(rhs, &stat2) < 0) ::boost::process::v1::detail::throw_last_error("fstat() failed");
|
||||
|
||||
return (stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}}}}}
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_POSIX_COMPARE_HANDLES_HPP_ */
|
||||
41
include/boost/process/v1/detail/posix/env_init.hpp
Normal file
41
include/boost/process/v1/detail/posix/env_init.hpp
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_ENV_INIT_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_ENV_INIT_HPP_
|
||||
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/environment.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
template<typename Char>
|
||||
struct env_init;
|
||||
|
||||
template<>
|
||||
struct env_init<char> : handler_base_ext
|
||||
{
|
||||
boost::process::v1::environment env;
|
||||
|
||||
env_init(boost::process::v1::environment && env) : env(std::move(env)) {};
|
||||
env_init(const boost::process::v1::environment & env) : env(env) {};
|
||||
|
||||
|
||||
template <class Executor>
|
||||
void on_setup(Executor &exec) const
|
||||
{
|
||||
exec.env = env._env_impl;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}}}}}
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_INIT_HPP_ */
|
||||
327
include/boost/process/v1/detail/posix/environment.hpp
Normal file
327
include/boost/process/v1/detail/posix/environment.hpp
Normal file
@@ -0,0 +1,327 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_ENVIRONMENT_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_ENVIRONMENT_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <boost/process/v1/locale.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
template<typename Char>
|
||||
class native_environment_impl
|
||||
{
|
||||
static std::vector<std::basic_string<Char>> _load()
|
||||
{
|
||||
std::vector<std::basic_string<Char>> val;
|
||||
auto p = environ;
|
||||
while (*p != nullptr)
|
||||
{
|
||||
std::string str = *p;
|
||||
val.push_back(::boost::process::v1::detail::convert(str));
|
||||
p++;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
static std::vector<Char*> _load_var(std::vector<std::basic_string<Char>> & vec)
|
||||
{
|
||||
std::vector<Char*> val;
|
||||
val.resize(vec.size() + 1);
|
||||
std::transform(vec.begin(), vec.end(), val.begin(),
|
||||
[](std::basic_string<Char> & str)
|
||||
{
|
||||
return &str.front();
|
||||
});
|
||||
val.back() = nullptr;
|
||||
return val;
|
||||
}
|
||||
std::vector<std::basic_string<Char>> _buffer = _load();
|
||||
std::vector<Char*> _impl = _load_var(_buffer);
|
||||
public:
|
||||
using char_type = Char;
|
||||
using pointer_type = const char_type*;
|
||||
using string_type = std::basic_string<char_type>;
|
||||
using native_handle_type = char_type **;
|
||||
|
||||
void reload()
|
||||
{
|
||||
_buffer = _load();
|
||||
_impl = _load_var(_buffer);
|
||||
_env_impl = _impl.data();
|
||||
}
|
||||
|
||||
string_type get(const pointer_type id) { return get(string_type(id)); }
|
||||
void set(const pointer_type id, const pointer_type value)
|
||||
{
|
||||
set(string_type(id), string_type(value));
|
||||
}
|
||||
void reset(const pointer_type id) { reset(string_type(id)); }
|
||||
|
||||
string_type get(const string_type & id)
|
||||
{
|
||||
std::string id_c = ::boost::process::v1::detail::convert(id);
|
||||
std::string g = ::getenv(id_c.c_str());
|
||||
return ::boost::process::v1::detail::convert(g.c_str());
|
||||
}
|
||||
void set(const string_type & id, const string_type & value)
|
||||
{
|
||||
std::string id_c = ::boost::process::v1::detail::convert(id.c_str());
|
||||
std::string value_c = ::boost::process::v1::detail::convert(value.c_str());
|
||||
auto res = ::setenv(id_c.c_str(), value_c.c_str(), true);
|
||||
if (res != 0)
|
||||
boost::process::v1::detail::throw_last_error();
|
||||
}
|
||||
void reset(const string_type & id)
|
||||
{
|
||||
std::string id_c = ::boost::process::v1::detail::convert(id.c_str());
|
||||
auto res = ::unsetenv(id_c.c_str());
|
||||
if (res != 0)
|
||||
::boost::process::v1::detail::throw_last_error();
|
||||
}
|
||||
|
||||
native_environment_impl() = default;
|
||||
native_environment_impl(const native_environment_impl& ) = delete;
|
||||
native_environment_impl(native_environment_impl && ) = default;
|
||||
native_environment_impl & operator=(const native_environment_impl& ) = delete;
|
||||
native_environment_impl & operator=(native_environment_impl && ) = default;
|
||||
native_handle_type _env_impl = _impl.data();
|
||||
|
||||
native_handle_type native_handle() const {return _env_impl;}
|
||||
};
|
||||
|
||||
template<>
|
||||
class native_environment_impl<char>
|
||||
{
|
||||
public:
|
||||
using char_type = char;
|
||||
using pointer_type = const char_type*;
|
||||
using string_type = std::basic_string<char_type>;
|
||||
using native_handle_type = char_type **;
|
||||
|
||||
void reload() {this->_env_impl = environ;}
|
||||
|
||||
string_type get(const pointer_type id) { return getenv(id); }
|
||||
void set(const pointer_type id, const pointer_type value)
|
||||
{
|
||||
auto res = ::setenv(id, value, 1);
|
||||
if (res != 0)
|
||||
boost::process::v1::detail::throw_last_error();
|
||||
reload();
|
||||
}
|
||||
void reset(const pointer_type id)
|
||||
{
|
||||
auto res = ::unsetenv(id);
|
||||
if (res != 0)
|
||||
boost::process::v1::detail::throw_last_error();
|
||||
reload();
|
||||
}
|
||||
|
||||
string_type get(const string_type & id) {return get(id.c_str());}
|
||||
void set(const string_type & id, const string_type & value) {set(id.c_str(), value.c_str()); }
|
||||
void reset(const string_type & id) {reset(id.c_str());}
|
||||
|
||||
native_environment_impl() = default;
|
||||
native_environment_impl(const native_environment_impl& ) = delete;
|
||||
native_environment_impl(native_environment_impl && ) = default;
|
||||
native_environment_impl & operator=(const native_environment_impl& ) = delete;
|
||||
native_environment_impl & operator=(native_environment_impl && ) = default;
|
||||
native_handle_type _env_impl = environ;
|
||||
|
||||
native_handle_type native_handle() const {return environ;}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename Char>
|
||||
struct basic_environment_impl
|
||||
{
|
||||
std::vector<std::basic_string<Char>> _data {};
|
||||
static std::vector<Char*> _load_var(std::vector<std::basic_string<Char>> & data);
|
||||
std::vector<Char*> _env_arr{_load_var(_data)};
|
||||
public:
|
||||
using char_type = Char;
|
||||
using pointer_type = const char_type*;
|
||||
using string_type = std::basic_string<char_type>;
|
||||
using native_handle_type = Char**;
|
||||
void reload()
|
||||
{
|
||||
_env_arr = _load_var(_data);
|
||||
_env_impl = _env_arr.data();
|
||||
}
|
||||
|
||||
string_type get(const pointer_type id) {return get(string_type(id));}
|
||||
void set(const pointer_type id, const pointer_type value) {set(string_type(id), value);}
|
||||
void reset(const pointer_type id) {reset(string_type(id));}
|
||||
|
||||
string_type get(const string_type & id);
|
||||
void set(const string_type & id, const string_type & value);
|
||||
void reset(const string_type & id);
|
||||
|
||||
basic_environment_impl(const native_environment_impl<Char> & nei);
|
||||
basic_environment_impl() = default;
|
||||
basic_environment_impl(const basic_environment_impl& rhs)
|
||||
: _data(rhs._data)
|
||||
{
|
||||
|
||||
}
|
||||
basic_environment_impl(basic_environment_impl && ) = default;
|
||||
basic_environment_impl & operator=(const basic_environment_impl& rhs)
|
||||
{
|
||||
_data = rhs._data;
|
||||
_env_arr = _load_var(_data);
|
||||
_env_impl = &*_env_arr.begin();
|
||||
return *this;
|
||||
}
|
||||
basic_environment_impl & operator=(basic_environment_impl && ) = default;
|
||||
|
||||
template<typename CharR>
|
||||
explicit inline basic_environment_impl(
|
||||
const basic_environment_impl<CharR>& rhs,
|
||||
const ::boost::process::v1::codecvt_type & cv = ::boost::process::v1::codecvt())
|
||||
: _data(rhs._data.size())
|
||||
{
|
||||
std::transform(rhs._data.begin(), rhs._data.end(), _data.begin(),
|
||||
[&](const std::basic_string<CharR> & st)
|
||||
{
|
||||
return ::boost::process::v1::detail::convert(st, cv);
|
||||
}
|
||||
|
||||
);
|
||||
reload();
|
||||
}
|
||||
|
||||
template<typename CharR>
|
||||
basic_environment_impl & operator=(const basic_environment_impl<CharR>& rhs)
|
||||
{
|
||||
_data = ::boost::process::v1::detail::convert(rhs._data);
|
||||
_env_arr = _load_var(&*_data.begin());
|
||||
_env_impl = &*_env_arr.begin();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Char ** _env_impl = &*_env_arr.data();
|
||||
|
||||
native_handle_type native_handle() const {return &_data.front();}
|
||||
};
|
||||
|
||||
|
||||
template<typename Char>
|
||||
basic_environment_impl<Char>::basic_environment_impl(const native_environment_impl<Char> & nei)
|
||||
{
|
||||
auto beg = nei.native_handle();
|
||||
|
||||
auto end = beg;
|
||||
while (*end != nullptr)
|
||||
end++;
|
||||
this->_data.assign(beg, end);
|
||||
reload();
|
||||
}
|
||||
|
||||
|
||||
template<typename Char>
|
||||
inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_type
|
||||
{
|
||||
auto itr = std::find_if(_data.begin(), _data.end(),
|
||||
[&](const string_type & st) -> bool
|
||||
{
|
||||
if (st.size() <= id.size())
|
||||
return false;
|
||||
return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign<Char>());
|
||||
}
|
||||
);
|
||||
|
||||
if (itr == _data.end())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
else return
|
||||
itr->data() + id.size(); //id=Thingy -> +2 points to T
|
||||
}
|
||||
|
||||
template<typename Char>
|
||||
inline void basic_environment_impl<Char>::set(const string_type &id, const string_type &value)
|
||||
{
|
||||
auto itr = std::find_if(_data.begin(), _data.end(),
|
||||
[&](const string_type & st) -> bool
|
||||
{
|
||||
if (st.size() <= id.size())
|
||||
return false;
|
||||
return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign<Char>());
|
||||
}
|
||||
);
|
||||
|
||||
if (itr != _data.end())
|
||||
*itr = id + equal_sign<Char>() + value;
|
||||
else
|
||||
_data.push_back(id + equal_sign<Char>() + value);
|
||||
|
||||
reload();
|
||||
}
|
||||
|
||||
template<typename Char>
|
||||
inline void basic_environment_impl<Char>::reset(const string_type &id)
|
||||
{
|
||||
auto itr = std::find_if(_data.begin(), _data.end(),
|
||||
[&](const string_type & st) -> bool
|
||||
{
|
||||
if (st.size() <= id.size())
|
||||
return false;
|
||||
return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign<Char>());
|
||||
}
|
||||
);
|
||||
if (itr != _data.end())
|
||||
{
|
||||
_data.erase(itr);//and remove it
|
||||
}
|
||||
|
||||
reload();
|
||||
|
||||
|
||||
}
|
||||
|
||||
template<typename Char>
|
||||
std::vector<Char*> basic_environment_impl<Char>::_load_var(std::vector<std::basic_string<Char>> & data)
|
||||
{
|
||||
std::vector<Char*> ret;
|
||||
ret.reserve(data.size() +1);
|
||||
|
||||
for (auto & val : data)
|
||||
{
|
||||
if (val.empty())
|
||||
val.push_back(0);
|
||||
ret.push_back(&val.front());
|
||||
}
|
||||
|
||||
ret.push_back(nullptr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T> constexpr T env_seperator();
|
||||
template<> constexpr char env_seperator() {return ':'; }
|
||||
template<> constexpr wchar_t env_seperator() {return L':'; }
|
||||
|
||||
|
||||
typedef int native_handle_t;
|
||||
|
||||
inline int get_id() {return getpid(); }
|
||||
inline int native_handle() {return getpid(); }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_ */
|
||||
39
include/boost/process/v1/detail/posix/exe.hpp
Normal file
39
include/boost/process/v1/detail/posix/exe.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_EXE_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_EXE_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace process
|
||||
{
|
||||
BOOST_PROCESS_V1_INLINE namespace v1
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace posix
|
||||
{
|
||||
|
||||
template<class StringType, class Executor>
|
||||
inline void apply_exe(const StringType & exe, Executor & e)
|
||||
{
|
||||
e.exe = exe.c_str();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ARGS_HPP_ */
|
||||
573
include/boost/process/v1/detail/posix/executor.hpp
Normal file
573
include/boost/process/v1/detail/posix/executor.hpp
Normal file
@@ -0,0 +1,573 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_EXECUTOR_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_EXECUTOR_HPP
|
||||
|
||||
#include <boost/process/v1/detail/child_decl.hpp>
|
||||
#include <boost/process/v1/error.hpp>
|
||||
#include <boost/process/v1/pipe.hpp>
|
||||
#include <boost/process/v1/detail/posix/basic_pipe.hpp>
|
||||
#include <boost/process/v1/detail/posix/use_vfork.hpp>
|
||||
#include <boost/fusion/algorithm/iteration/for_each.hpp>
|
||||
#include <cstdlib>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
template<typename Executor>
|
||||
struct on_setup_t
|
||||
{
|
||||
Executor & exec;
|
||||
on_setup_t(Executor & exec) : exec(exec) {};
|
||||
template<typename T>
|
||||
void operator()(T & t) const
|
||||
{
|
||||
if (!exec.error())
|
||||
t.on_setup(exec);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Executor>
|
||||
struct on_error_t
|
||||
{
|
||||
Executor & exec;
|
||||
const std::error_code & error;
|
||||
on_error_t(Executor & exec, const std::error_code & error) : exec(exec), error(error) {};
|
||||
template<typename T>
|
||||
void operator()(T & t) const
|
||||
{
|
||||
t.on_error(exec, error);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Executor>
|
||||
struct on_success_t
|
||||
{
|
||||
Executor & exec;
|
||||
on_success_t(Executor & exec) : exec(exec) {};
|
||||
template<typename T>
|
||||
void operator()(T & t) const {t.on_success(exec);}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
struct on_fork_error_t
|
||||
{
|
||||
Executor & exec;
|
||||
const std::error_code & error;
|
||||
on_fork_error_t(Executor & exec, const std::error_code & error) : exec(exec), error(error) {};
|
||||
|
||||
template<typename T>
|
||||
void operator()(T & t) const
|
||||
{
|
||||
t.on_fork_error(exec, error);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
struct on_exec_setup_t
|
||||
{
|
||||
Executor & exec;
|
||||
on_exec_setup_t(Executor & exec) : exec(exec) {};
|
||||
|
||||
template<typename T>
|
||||
void operator()(T & t) const
|
||||
{
|
||||
t.on_exec_setup(exec);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
struct on_exec_error_t
|
||||
{
|
||||
Executor & exec;
|
||||
const std::error_code &ec;
|
||||
on_exec_error_t(Executor & exec, const std::error_code & error) : exec(exec), ec(error) {};
|
||||
|
||||
template<typename T>
|
||||
void operator()(T & t) const
|
||||
{
|
||||
t.on_exec_error(exec, ec);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Executor>
|
||||
struct on_fork_success_t
|
||||
{
|
||||
Executor & exec;
|
||||
on_fork_success_t(Executor & exec) : exec(exec) {};
|
||||
|
||||
template<typename T>
|
||||
void operator()(T & t) const
|
||||
{
|
||||
t.on_fork_success(exec);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Executor> on_setup_t <Executor> call_on_setup (Executor & exec) {return exec;}
|
||||
template<typename Executor> on_error_t <Executor> call_on_error (Executor & exec, const std::error_code & ec)
|
||||
{
|
||||
return on_error_t<Executor> (exec, ec);
|
||||
}
|
||||
template<typename Executor> on_success_t<Executor> call_on_success(Executor & exec) {return exec;}
|
||||
|
||||
template<typename Executor> on_fork_error_t <Executor> call_on_fork_error (Executor & exec, const std::error_code & ec)
|
||||
{
|
||||
return on_fork_error_t<Executor> (exec, ec);
|
||||
}
|
||||
|
||||
|
||||
template<typename Executor> on_exec_setup_t <Executor> call_on_exec_setup (Executor & exec) {return exec;}
|
||||
template<typename Executor> on_exec_error_t <Executor> call_on_exec_error (Executor & exec, const std::error_code & ec)
|
||||
{
|
||||
return on_exec_error_t<Executor> (exec, ec);
|
||||
}
|
||||
|
||||
|
||||
template<typename Sequence>
|
||||
class executor
|
||||
{
|
||||
template<typename HasHandler, typename UseVFork>
|
||||
void internal_error_handle(const std::error_code&, const char*, HasHandler, boost::mpl::true_, UseVFork) {}
|
||||
|
||||
int _pipe_sink = -1;
|
||||
|
||||
|
||||
void write_error(const std::error_code & ec, const char * msg)
|
||||
{
|
||||
//I am the child
|
||||
const auto len = static_cast<int>(std::strlen(msg));
|
||||
int data[2] = {ec.value(), len + 1};
|
||||
|
||||
boost::ignore_unused(::write(_pipe_sink, &data[0], sizeof(int) * 2));
|
||||
boost::ignore_unused(::write(_pipe_sink, msg, len));
|
||||
}
|
||||
|
||||
void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::true_ , boost::mpl::false_, boost::mpl::false_)
|
||||
{
|
||||
if (this->pid == 0) //on the fork.
|
||||
write_error(ec, msg);
|
||||
else
|
||||
{
|
||||
this->_ec = ec;
|
||||
this->_msg = msg;
|
||||
}
|
||||
}
|
||||
void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::false_, boost::mpl::false_, boost::mpl::false_)
|
||||
{
|
||||
if (this->pid == 0)
|
||||
write_error(ec, msg);
|
||||
else
|
||||
throw process_error(ec, msg);
|
||||
}
|
||||
|
||||
|
||||
void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::true_ , boost::mpl::false_, boost::mpl::true_)
|
||||
{
|
||||
this->_ec = ec;
|
||||
this->_msg = msg;
|
||||
}
|
||||
void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::false_, boost::mpl::false_, boost::mpl::true_)
|
||||
{
|
||||
if (this->pid == 0)
|
||||
{
|
||||
this->_ec = ec;
|
||||
this->_msg = msg;
|
||||
}
|
||||
else
|
||||
throw process_error(ec, msg);
|
||||
}
|
||||
|
||||
void check_error(boost::mpl::true_) {};
|
||||
void check_error(boost::mpl::false_)
|
||||
{
|
||||
if (_ec)
|
||||
throw process_error(_ec, _msg);
|
||||
}
|
||||
|
||||
typedef typename ::boost::process::v1::detail::has_error_handler<Sequence>::type has_error_handler;
|
||||
typedef typename ::boost::process::v1::detail::has_ignore_error <Sequence>::type has_ignore_error;
|
||||
typedef typename ::boost::process::v1::detail::posix::shall_use_vfork<Sequence>::type shall_use_vfork;
|
||||
|
||||
inline child invoke(boost::mpl::true_ , boost::mpl::true_ );
|
||||
inline child invoke(boost::mpl::false_, boost::mpl::true_ );
|
||||
inline child invoke(boost::mpl::true_ , boost::mpl::false_ );
|
||||
inline child invoke(boost::mpl::false_, boost::mpl::false_ );
|
||||
void _write_error(int sink)
|
||||
{
|
||||
int data[2] = {_ec.value(),static_cast<int>(_msg.size())};
|
||||
while (::write(sink, &data[0], sizeof(int) *2) == -1)
|
||||
{
|
||||
auto err = errno;
|
||||
|
||||
if (err == EBADF)
|
||||
return;
|
||||
else if ((err != EINTR) && (err != EAGAIN))
|
||||
break;
|
||||
}
|
||||
while (::write(sink, &_msg.front(), _msg.size()) == -1)
|
||||
{
|
||||
auto err = errno;
|
||||
|
||||
if (err == EBADF)
|
||||
return;
|
||||
else if ((err != EINTR) && (err != EAGAIN))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void _read_error(int source)
|
||||
{
|
||||
int data[2];
|
||||
|
||||
_ec.clear();
|
||||
int count = 0;
|
||||
while ((count = ::read(source, &data[0], sizeof(int) *2 ) ) == -1)
|
||||
{
|
||||
//actually, this should block until it's read.
|
||||
auto err = errno;
|
||||
if ((err != EAGAIN ) && (err != EINTR))
|
||||
set_error(std::error_code(err, std::system_category()), "Error read pipe");
|
||||
}
|
||||
if (count == 0)
|
||||
return ;
|
||||
|
||||
std::error_code ec(data[0], std::system_category());
|
||||
std::string msg(data[1], ' ');
|
||||
|
||||
while (::read(source, &msg.front(), msg.size() ) == -1)
|
||||
{
|
||||
//actually, this should block until it's read.
|
||||
auto err = errno;
|
||||
if ((err == EBADF) || (err == EPERM))//that should occur on success, therefore return.
|
||||
return;
|
||||
//EAGAIN not yet forked, EINTR interrupted, i.e. try again
|
||||
else if ((err != EAGAIN ) && (err != EINTR))
|
||||
set_error(std::error_code(err, std::system_category()), "Error read pipe");
|
||||
}
|
||||
set_error(ec, std::move(msg));
|
||||
}
|
||||
|
||||
std::string prepare_cmd_style_fn; //buffer
|
||||
|
||||
inline void prepare_cmd_style() //this does what execvpe does - but we execute it in the father process, to avoid allocations.
|
||||
{
|
||||
//use my own implementation
|
||||
prepare_cmd_style_fn = exe;
|
||||
if ((prepare_cmd_style_fn.find('/') == std::string::npos) && ::access(prepare_cmd_style_fn.c_str(), X_OK))
|
||||
{
|
||||
const auto * e = environ;
|
||||
while ((e != nullptr) && (*e != nullptr) && !boost::starts_with(*e, "PATH="))
|
||||
e++;
|
||||
|
||||
if ((e != nullptr) && (*e != nullptr))
|
||||
{
|
||||
std::vector<std::string> path;
|
||||
//the beginning of the string contains "PATH="
|
||||
boost::split(path, (*e) + 5, boost::is_any_of(":"));
|
||||
|
||||
for (const std::string & pp : path)
|
||||
{
|
||||
auto p = pp + "/" + exe;
|
||||
if (!::access(p.c_str(), X_OK))
|
||||
{
|
||||
prepare_cmd_style_fn = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exe = prepare_cmd_style_fn.c_str();
|
||||
}
|
||||
|
||||
std::error_code _ec;
|
||||
std::string _msg;
|
||||
public:
|
||||
executor(Sequence & seq) : seq(seq)
|
||||
{
|
||||
}
|
||||
|
||||
child operator()()
|
||||
{
|
||||
return invoke(has_ignore_error(), shall_use_vfork());
|
||||
}
|
||||
|
||||
|
||||
Sequence & seq;
|
||||
const char * exe = nullptr;
|
||||
char *const* cmd_line = nullptr;
|
||||
bool cmd_style = false;
|
||||
char **env = environ;
|
||||
pid_t pid = -1;
|
||||
std::shared_ptr<std::atomic<int>> exit_status = std::make_shared<std::atomic<int>>(still_active);
|
||||
|
||||
const std::error_code & error() const {return _ec;}
|
||||
|
||||
void set_error(const std::error_code &ec, const char* msg)
|
||||
{
|
||||
internal_error_handle(ec, msg, has_error_handler(), has_ignore_error(), shall_use_vfork());
|
||||
}
|
||||
void set_error(const std::error_code &ec, const std::string &msg) {set_error(ec, msg.c_str());};
|
||||
|
||||
std::vector<int> get_used_handles() const
|
||||
{
|
||||
if (_pipe_sink == -1)
|
||||
return {};
|
||||
else
|
||||
return {_pipe_sink};
|
||||
};
|
||||
};
|
||||
|
||||
template<typename Sequence>
|
||||
child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::false_) //ignore errors
|
||||
{
|
||||
boost::fusion::for_each(seq, call_on_setup(*this));
|
||||
if (_ec)
|
||||
return child();
|
||||
if (cmd_style)
|
||||
prepare_cmd_style();
|
||||
|
||||
this->pid = ::fork();
|
||||
if (pid == -1)
|
||||
{
|
||||
auto ec = boost::process::v1::detail::get_last_error();
|
||||
boost::fusion::for_each(seq, call_on_fork_error(*this, ec));
|
||||
return child();
|
||||
}
|
||||
else if (pid == 0)
|
||||
{
|
||||
boost::fusion::for_each(seq, call_on_exec_setup(*this));
|
||||
::execve(exe, cmd_line, env);
|
||||
auto ec = boost::process::v1::detail::get_last_error();
|
||||
boost::fusion::for_each(seq, call_on_exec_error(*this, ec));
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
child c(child_handle(pid), exit_status);
|
||||
|
||||
boost::fusion::for_each(seq, call_on_success(*this));
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
template<typename Sequence>
|
||||
child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
|
||||
{
|
||||
{
|
||||
struct pipe_guard
|
||||
{
|
||||
int p[2];
|
||||
pipe_guard() : p{-1,-1} {}
|
||||
|
||||
~pipe_guard()
|
||||
{
|
||||
if (p[0] != -1)
|
||||
::close(p[0]);
|
||||
if (p[1] != -1)
|
||||
::close(p[1]);
|
||||
}
|
||||
} p{};
|
||||
|
||||
if (::pipe(p.p) == -1)
|
||||
{
|
||||
set_error(::boost::process::v1::detail::get_last_error(), "pipe(2) failed");
|
||||
return child();
|
||||
}
|
||||
if (::fcntl(p.p[1], F_SETFD, FD_CLOEXEC) == -1)
|
||||
{
|
||||
auto err = ::boost::process::v1::detail::get_last_error();
|
||||
set_error(err, "fcntl(2) failed");//this might throw, so we need to be sure our pipe is safe.
|
||||
return child();
|
||||
}
|
||||
|
||||
_pipe_sink = p.p[1];
|
||||
|
||||
_ec.clear();
|
||||
boost::fusion::for_each(seq, call_on_setup(*this));
|
||||
|
||||
if (_ec)
|
||||
{
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
_pipe_sink = -1;
|
||||
return child();
|
||||
}
|
||||
|
||||
if (cmd_style)
|
||||
prepare_cmd_style();
|
||||
|
||||
this->pid = ::fork();
|
||||
if (pid == -1)
|
||||
{
|
||||
_ec = boost::process::v1::detail::get_last_error();
|
||||
_msg = "fork() failed";
|
||||
boost::fusion::for_each(seq, call_on_fork_error(*this, _ec));
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
_pipe_sink = -1;
|
||||
return child();
|
||||
}
|
||||
else if (pid == 0)
|
||||
{
|
||||
::close(p.p[0]);
|
||||
|
||||
boost::fusion::for_each(seq, call_on_exec_setup(*this));
|
||||
::execve(exe, cmd_line, env);
|
||||
_ec = boost::process::v1::detail::get_last_error();
|
||||
_msg = "execve failed";
|
||||
boost::fusion::for_each(seq, call_on_exec_error(*this, _ec));
|
||||
|
||||
_write_error(_pipe_sink);
|
||||
::close(p.p[1]);
|
||||
|
||||
_exit(EXIT_FAILURE);
|
||||
return child();
|
||||
}
|
||||
|
||||
::close(p.p[1]);
|
||||
p.p[1] = -1;
|
||||
_pipe_sink = -1;
|
||||
_read_error(p.p[0]);
|
||||
|
||||
}
|
||||
if (_ec)
|
||||
{
|
||||
//if an error occurred we need to reap the child process
|
||||
::waitpid(this->pid, nullptr, WNOHANG);
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
return child();
|
||||
}
|
||||
|
||||
child c(child_handle(pid), exit_status);
|
||||
|
||||
boost::fusion::for_each(seq, call_on_success(*this));
|
||||
|
||||
if (_ec)
|
||||
{
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
return child();
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
#if BOOST_POSIX_HAS_VFORK
|
||||
|
||||
|
||||
template<typename Sequence>
|
||||
child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::true_) //ignore errors
|
||||
{
|
||||
boost::fusion::for_each(seq, call_on_setup(*this));
|
||||
if (_ec)
|
||||
return child();
|
||||
this->pid = ::vfork();
|
||||
if (pid == -1)
|
||||
{
|
||||
auto ec = boost::process::v1::detail::get_last_error();
|
||||
boost::fusion::for_each(seq, call_on_fork_error(*this, ec));
|
||||
return child();
|
||||
}
|
||||
else if (pid == 0)
|
||||
{
|
||||
boost::fusion::for_each(seq, call_on_exec_setup(*this));
|
||||
::execve(exe, cmd_line, env);
|
||||
auto ec = boost::process::v1::detail::get_last_error();
|
||||
boost::fusion::for_each(seq, call_on_exec_error(*this, ec));
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
child c(child_handle(pid), exit_status);
|
||||
|
||||
boost::fusion::for_each(seq, call_on_success(*this));
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
template<typename Sequence>
|
||||
child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::true_)
|
||||
{
|
||||
boost::fusion::for_each(seq, call_on_setup(*this));
|
||||
|
||||
if (_ec)
|
||||
{
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
return child();
|
||||
}
|
||||
_ec.clear();
|
||||
if (cmd_style)
|
||||
this->prepare_cmd_style();
|
||||
|
||||
this->pid = ::vfork();
|
||||
if (pid == -1)
|
||||
{
|
||||
_ec = boost::process::v1::detail::get_last_error();
|
||||
_msg = "fork() failed";
|
||||
boost::fusion::for_each(seq, call_on_fork_error(*this, _ec));
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
|
||||
return child();
|
||||
}
|
||||
else if (pid == 0)
|
||||
{
|
||||
boost::fusion::for_each(seq, call_on_exec_setup(*this));
|
||||
|
||||
::execve(exe, cmd_line, env);
|
||||
|
||||
_ec = boost::process::v1::detail::get_last_error();
|
||||
_msg = "execve failed";
|
||||
boost::fusion::for_each(seq, call_on_exec_error(*this, _ec));
|
||||
|
||||
_exit(EXIT_FAILURE);
|
||||
return child();
|
||||
}
|
||||
child c(child_handle(pid), exit_status);
|
||||
|
||||
check_error(has_error_handler());
|
||||
|
||||
|
||||
|
||||
if (_ec)
|
||||
{
|
||||
::waitpid(this->pid, nullptr, WNOHANG);
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
return child();
|
||||
}
|
||||
else
|
||||
boost::fusion::for_each(seq, call_on_success(*this));
|
||||
|
||||
if (_ec)
|
||||
{
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
return child();
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template<typename Char, typename Tup>
|
||||
inline executor<Tup> make_executor(Tup & tup)
|
||||
{
|
||||
return executor<Tup>(tup);
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
102
include/boost/process/v1/detail/posix/fd.hpp
Normal file
102
include/boost/process/v1/detail/posix/fd.hpp
Normal file
@@ -0,0 +1,102 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_FD_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_FD_HPP
|
||||
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <unistd.h>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
|
||||
struct close_fd_ : handler_base_ext, ::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
close_fd_(int fd) : fd_(fd) {}
|
||||
|
||||
template <class PosixExecutor>
|
||||
void on_exec_setup(PosixExecutor& e) const
|
||||
{
|
||||
if (::close(fd_) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
|
||||
}
|
||||
|
||||
int get_used_handles() {return fd_;}
|
||||
|
||||
|
||||
private:
|
||||
int fd_;
|
||||
};
|
||||
|
||||
template <class Range>
|
||||
struct close_fds_ : handler_base_ext, ::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
public:
|
||||
close_fds_(const Range &fds) : fds_(fds) {}
|
||||
|
||||
template <class PosixExecutor>
|
||||
void on_exec_setup(PosixExecutor& e) const
|
||||
{
|
||||
for (auto & fd_ : fds_)
|
||||
if (::close(fd_) == -1)
|
||||
{
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Range& get_used_handles() {return fds_;}
|
||||
|
||||
private:
|
||||
Range fds_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <class FileDescriptor>
|
||||
struct bind_fd_ : handler_base_ext, ::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
public:
|
||||
bind_fd_(int id, const FileDescriptor &fd) : id_(id), fd_(fd) {}
|
||||
|
||||
template <class PosixExecutor>
|
||||
void on_exec_setup(PosixExecutor& e) const
|
||||
{
|
||||
if (::dup2(fd_, id_) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
}
|
||||
|
||||
std::array<int, 2> get_used_handles() {return {id_, fd_};}
|
||||
|
||||
|
||||
private:
|
||||
int id_;
|
||||
FileDescriptor fd_;
|
||||
};
|
||||
|
||||
|
||||
struct fd_
|
||||
{
|
||||
constexpr fd_() {};
|
||||
close_fd_ close(int _fd) const {return close_fd_(_fd);}
|
||||
close_fds_<std::vector<int>> close(const std::initializer_list<int> & vec) const {return std::vector<int>(vec);}
|
||||
template<typename Range>
|
||||
close_fds_<Range> close(const Range & r) const {return r;}
|
||||
|
||||
template <class FileDescriptor>
|
||||
bind_fd_<FileDescriptor> bind(int id, const FileDescriptor & fd) const {return {id, fd};}
|
||||
|
||||
};
|
||||
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
89
include/boost/process/v1/detail/posix/file_descriptor.hpp
Normal file
89
include/boost/process/v1/detail/posix/file_descriptor.hpp
Normal file
@@ -0,0 +1,89 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_FILE_DESCRIPTOR_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_FILE_DESCRIPTOR_HPP_
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <string>
|
||||
#include <boost/process/v1/filesystem.hpp>
|
||||
#include <boost/core/exchange.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
struct file_descriptor
|
||||
{
|
||||
enum mode_t
|
||||
{
|
||||
read = 1,
|
||||
write = 2,
|
||||
read_write = 3
|
||||
};
|
||||
|
||||
|
||||
file_descriptor() = default;
|
||||
explicit file_descriptor(const boost::process::v1::filesystem::path& p, mode_t mode = read_write)
|
||||
: file_descriptor(p.native(), mode)
|
||||
{
|
||||
}
|
||||
|
||||
explicit file_descriptor(const std::string & path , mode_t mode = read_write)
|
||||
: file_descriptor(path.c_str(), mode) {}
|
||||
|
||||
|
||||
explicit file_descriptor(const char* path, mode_t mode = read_write)
|
||||
: _handle(create_file(path, mode))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
file_descriptor(const file_descriptor & ) = delete;
|
||||
file_descriptor(file_descriptor &&other)
|
||||
: _handle(boost::exchange(other._handle, -1))
|
||||
{
|
||||
}
|
||||
|
||||
file_descriptor& operator=(const file_descriptor & ) = delete;
|
||||
file_descriptor& operator=(file_descriptor &&other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
if (_handle != -1)
|
||||
::close(_handle);
|
||||
_handle = boost::exchange(other._handle, -1);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~file_descriptor()
|
||||
{
|
||||
if (_handle != -1)
|
||||
::close(_handle);
|
||||
}
|
||||
|
||||
int handle() const { return _handle;}
|
||||
|
||||
private:
|
||||
static int create_file(const char* name, mode_t mode )
|
||||
{
|
||||
switch(mode)
|
||||
{
|
||||
case read:
|
||||
return ::open(name, O_RDONLY);
|
||||
case write:
|
||||
return ::open(name, O_WRONLY | O_CREAT, 0660);
|
||||
case read_write:
|
||||
return ::open(name, O_RDWR | O_CREAT, 0660);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int _handle = -1;
|
||||
};
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_ */
|
||||
46
include/boost/process/v1/detail/posix/file_in.hpp
Normal file
46
include/boost/process/v1/detail/posix/file_in.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_FILE_IN_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_FILE_IN_HPP
|
||||
|
||||
#include <boost/process/v1/pipe.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/detail/posix/file_descriptor.hpp>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
#include <cstdio>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
struct file_in : handler_base_ext, ::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
file_descriptor file;
|
||||
int handle = file.handle();
|
||||
|
||||
std::array<int, 2> get_used_handles()
|
||||
{
|
||||
return {{STDIN_FILENO, handle}};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
file_in(T&& t) : file(std::forward<T>(t)) {}
|
||||
file_in(FILE * f) : handle(fileno(f)) {}
|
||||
|
||||
template <class WindowsExecutor>
|
||||
void on_exec_setup(WindowsExecutor &e) const
|
||||
{
|
||||
if (::dup2(handle, STDIN_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
}
|
||||
};
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
73
include/boost/process/v1/detail/posix/file_out.hpp
Normal file
73
include/boost/process/v1/detail/posix/file_out.hpp
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_POSIX_FILE_OUT_HPP
|
||||
#define BOOST_PROCESS_POSIX_FILE_OUT_HPP
|
||||
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/detail/posix/file_descriptor.hpp>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
template<int p1, int p2>
|
||||
struct file_out : handler_base_ext, ::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
file_descriptor file;
|
||||
int handle = file.handle();
|
||||
|
||||
template<typename T>
|
||||
file_out(T&& t) : file(std::forward<T>(t), file_descriptor::write), handle(file.handle()) {}
|
||||
file_out(FILE * f) : handle(fileno(f)) {}
|
||||
|
||||
std::array<int, 3> get_used_handles()
|
||||
{
|
||||
const auto pp1 = p1 != -1 ? p1 : p2;
|
||||
const auto pp2 = p2 != -1 ? p2 : p1;
|
||||
|
||||
return {handle, pp1, pp2};
|
||||
}
|
||||
|
||||
template <typename Executor>
|
||||
void on_exec_setup(Executor &e) const;
|
||||
};
|
||||
|
||||
template<>
|
||||
template<typename Executor>
|
||||
void file_out<1,-1>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(handle, STDOUT_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename Executor>
|
||||
void file_out<2,-1>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(handle, STDERR_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename Executor>
|
||||
void file_out<1,2>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(handle, STDOUT_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
if (::dup2(handle, STDERR_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
94
include/boost/process/v1/detail/posix/group_handle.hpp
Normal file
94
include/boost/process/v1/detail/posix/group_handle.hpp
Normal file
@@ -0,0 +1,94 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_GROUP_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_GROUP_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/posix/child_handle.hpp>
|
||||
#include <system_error>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
struct group_handle
|
||||
{
|
||||
pid_t grp = -1;
|
||||
|
||||
typedef pid_t handle_t;
|
||||
handle_t handle() const { return grp; }
|
||||
|
||||
explicit group_handle(handle_t h) :
|
||||
grp(h)
|
||||
{
|
||||
}
|
||||
|
||||
group_handle() = default;
|
||||
|
||||
~group_handle() = default;
|
||||
group_handle(const group_handle & c) = delete;
|
||||
group_handle(group_handle && c) : grp(c.grp)
|
||||
{
|
||||
c.grp = -1;
|
||||
}
|
||||
group_handle &operator=(const group_handle & c) = delete;
|
||||
group_handle &operator=(group_handle && c)
|
||||
{
|
||||
grp = c.grp;
|
||||
c.grp = -1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void add(handle_t proc)
|
||||
{
|
||||
if (::setpgid(proc, grp))
|
||||
throw_last_error();
|
||||
}
|
||||
void add(handle_t proc, std::error_code & ec) noexcept
|
||||
{
|
||||
if (::setpgid(proc, grp))
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
bool has(handle_t proc)
|
||||
{
|
||||
return ::getpgid(proc) == grp;
|
||||
}
|
||||
bool has(handle_t proc, std::error_code &) noexcept
|
||||
{
|
||||
return ::getpgid(proc) == grp;
|
||||
}
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
return grp != -1;
|
||||
}
|
||||
};
|
||||
|
||||
inline void terminate(group_handle &p, std::error_code &ec) noexcept
|
||||
{
|
||||
if (::killpg(p.grp, SIGKILL) == -1)
|
||||
ec = boost::process::v1::detail::get_last_error();
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
p.grp = -1;
|
||||
}
|
||||
|
||||
inline void terminate(group_handle &p)
|
||||
{
|
||||
std::error_code ec;
|
||||
terminate(p, ec);
|
||||
boost::process::v1::detail::throw_error(ec, "killpg(2) failed in terminate");
|
||||
}
|
||||
|
||||
inline bool in_group()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_ */
|
||||
52
include/boost/process/v1/detail/posix/group_ref.hpp
Normal file
52
include/boost/process/v1/detail/posix/group_ref.hpp
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_GROUP_REF_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_GROUP_REF_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/posix/group_handle.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
|
||||
|
||||
namespace detail { namespace posix {
|
||||
|
||||
|
||||
|
||||
struct group_ref : handler_base_ext
|
||||
{
|
||||
group_handle & grp;
|
||||
|
||||
|
||||
explicit group_ref(group_handle & g) :
|
||||
grp(g)
|
||||
{}
|
||||
|
||||
template <class Executor>
|
||||
void on_exec_setup(Executor&) const
|
||||
{
|
||||
if (grp.grp == -1)
|
||||
::setpgid(0, 0);
|
||||
else
|
||||
::setpgid(0, grp.grp);
|
||||
}
|
||||
|
||||
template <class Executor>
|
||||
void on_success(Executor& exec) const
|
||||
{
|
||||
if (grp.grp == -1)
|
||||
grp.grp = exec.pid;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}}}}}
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_POSIX_GROUP_REF_HPP_ */
|
||||
74
include/boost/process/v1/detail/posix/handler.hpp
Normal file
74
include/boost/process/v1/detail/posix/handler.hpp
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_HANDLER_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_HANDLER_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
//does not extend anything.
|
||||
struct handler_base_ext : handler_base
|
||||
{
|
||||
template<typename Executor>
|
||||
void on_fork_error (Executor &, const std::error_code&) const {}
|
||||
|
||||
template<typename Executor>
|
||||
void on_exec_setup (Executor &) const {}
|
||||
|
||||
template<typename Executor>
|
||||
void on_exec_error (Executor &, const std::error_code&) const {}
|
||||
};
|
||||
|
||||
|
||||
template <class Handler>
|
||||
struct on_fork_error_ : handler_base_ext
|
||||
{
|
||||
explicit on_fork_error_(Handler handler) : handler_(handler) {}
|
||||
|
||||
template <class Executor>
|
||||
void on_fork_error(Executor &e, const std::error_code &ec) const
|
||||
{
|
||||
handler_(e, ec);
|
||||
}
|
||||
private:
|
||||
Handler handler_;
|
||||
};
|
||||
|
||||
|
||||
template <class Handler>
|
||||
struct on_exec_setup_ : handler_base_ext
|
||||
{
|
||||
explicit on_exec_setup_(Handler handler) : handler_(handler) {}
|
||||
|
||||
template <class Executor>
|
||||
void on_exec_setup(Executor &e) const
|
||||
{
|
||||
handler_(e);
|
||||
}
|
||||
private:
|
||||
Handler handler_;
|
||||
};
|
||||
|
||||
template <class Handler>
|
||||
struct on_exec_error_ : handler_base_ext
|
||||
{
|
||||
explicit on_exec_error_(Handler handler) : handler_(handler) {}
|
||||
|
||||
template <class Executor>
|
||||
void on_exec_error(Executor &e, const std::error_code &ec) const
|
||||
{
|
||||
handler_(e, ec);
|
||||
}
|
||||
private:
|
||||
Handler handler_;
|
||||
};
|
||||
|
||||
}}}}}
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_POSIX_HANDLER_HPP_ */
|
||||
148
include/boost/process/v1/detail/posix/handles.hpp
Normal file
148
include/boost/process/v1/detail/posix/handles.hpp
Normal file
@@ -0,0 +1,148 @@
|
||||
// Copyright (c) 2019 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_HANDLES_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_HANDLES_HPP_
|
||||
|
||||
#include <vector>
|
||||
#include <system_error>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <cstdlib>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
|
||||
using native_handle_type = int;
|
||||
|
||||
inline std::vector<native_handle_type> get_handles(std::error_code & ec)
|
||||
{
|
||||
std::vector<native_handle_type> res;
|
||||
|
||||
std::unique_ptr<DIR, void(*)(DIR*)> dir{::opendir("/dev/fd"), +[](DIR* p){::closedir(p);}};
|
||||
if (!dir)
|
||||
{
|
||||
ec = ::boost::process::v1::detail::get_last_error();
|
||||
return {};
|
||||
}
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
auto my_fd = dirfd(dir.get());
|
||||
|
||||
struct ::dirent * ent_p;
|
||||
|
||||
while ((ent_p = readdir(dir.get())) != nullptr)
|
||||
{
|
||||
if (ent_p->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
const auto conv = std::atoi(ent_p->d_name);
|
||||
if (conv == 0 && (ent_p->d_name[0] != '0' && ent_p->d_name[1] != '\0'))
|
||||
continue;
|
||||
|
||||
if (conv == my_fd)
|
||||
continue;
|
||||
|
||||
res.push_back(conv);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
inline std::vector<native_handle_type> get_handles()
|
||||
{
|
||||
std::error_code ec;
|
||||
|
||||
auto res = get_handles(ec);
|
||||
if (ec)
|
||||
boost::process::v1::detail::throw_error(ec, "open_dir(\"/dev/fd\") failed");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
inline bool is_stream_handle(native_handle_type handle, std::error_code & ec)
|
||||
{
|
||||
struct ::stat stat_;
|
||||
|
||||
if (::fstat(handle, &stat_) != 0)
|
||||
{
|
||||
ec = ::boost::process::v1::detail::get_last_error();
|
||||
}
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
return S_ISCHR (stat_.st_mode) //This macro returns non-zero if the file is a character special file (a device like a terminal).
|
||||
|| S_ISBLK (stat_.st_mode) // This macro returns non-zero if the file is a block special file (a device like a disk).
|
||||
|| S_ISREG (stat_.st_mode) // This macro returns non-zero if the file is a regular file.
|
||||
|| S_ISFIFO (stat_.st_mode) // This macro returns non-zero if the file is a FIFO special file, or a pipe. See section 15. Pipes and FIFOs.
|
||||
|| S_ISSOCK (stat_.st_mode) ;// This macro returns non-zero if the file is a socket. See section 16. Sockets.;
|
||||
}
|
||||
|
||||
|
||||
inline bool is_stream_handle(native_handle_type handle)
|
||||
{
|
||||
std::error_code ec;
|
||||
auto res = is_stream_handle(handle, ec);
|
||||
if (ec)
|
||||
boost::process::v1::detail::throw_error(ec, "fstat() failed");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
struct limit_handles_ : handler_base_ext
|
||||
{
|
||||
limit_handles_() {}
|
||||
~limit_handles_() {}
|
||||
mutable std::vector<int> used_handles;
|
||||
|
||||
template<typename Executor>
|
||||
void on_setup(Executor & exec) const
|
||||
{
|
||||
used_handles = get_used_handles(exec);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_exec_setup(Executor & exec) const
|
||||
{
|
||||
auto dir = ::opendir("/dev/fd");
|
||||
if (!dir)
|
||||
{
|
||||
exec.set_error(::boost::process::v1::detail::get_last_error(), "opendir(\"/dev/fd\")");
|
||||
return;
|
||||
}
|
||||
|
||||
auto my_fd = dirfd(dir);
|
||||
struct ::dirent * ent_p;
|
||||
|
||||
while ((ent_p = readdir(dir)) != nullptr)
|
||||
{
|
||||
if (ent_p->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
const auto conv = std::atoi(ent_p->d_name);
|
||||
|
||||
if ((conv == my_fd) || (conv == -1))
|
||||
continue;
|
||||
|
||||
if (std::find(used_handles.begin(), used_handles.end(), conv) != used_handles.end())
|
||||
continue;
|
||||
|
||||
if (::close(conv) != 0)
|
||||
{
|
||||
exec.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
::closedir(dir);
|
||||
}
|
||||
};
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif //PROCESS_HANDLES_HPP
|
||||
125
include/boost/process/v1/detail/posix/io_context_ref.hpp
Normal file
125
include/boost/process/v1/detail/posix/io_context_ref.hpp
Normal file
@@ -0,0 +1,125 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_POSIX_IO_CONTEXT_REF_HPP_
|
||||
#define BOOST_PROCESS_POSIX_IO_CONTEXT_REF_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/detail/posix/async_handler.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
|
||||
#include <boost/fusion/algorithm/iteration/for_each.hpp>
|
||||
#include <boost/fusion/algorithm/transformation/filter_if.hpp>
|
||||
#include <boost/fusion/algorithm/transformation/transform.hpp>
|
||||
#include <boost/fusion/view/transform_view.hpp>
|
||||
#include <boost/fusion/container/vector/convert.hpp>
|
||||
|
||||
|
||||
#include <boost/process/v1/detail/posix/sigchld_service.hpp>
|
||||
#include <boost/process/v1/detail/posix/is_running.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <sys/wait.h>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
template<typename Executor>
|
||||
struct on_exit_handler_transformer
|
||||
{
|
||||
Executor & exec;
|
||||
on_exit_handler_transformer(Executor & exec) : exec(exec) {}
|
||||
template<typename Sig>
|
||||
struct result;
|
||||
|
||||
template<typename T>
|
||||
struct result<on_exit_handler_transformer<Executor>(T&)>
|
||||
{
|
||||
typedef typename T::on_exit_handler_t type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
auto operator()(T& t) const -> typename T::on_exit_handler_t
|
||||
{
|
||||
return t.on_exit_handler(exec);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Executor>
|
||||
struct async_handler_collector
|
||||
{
|
||||
Executor & exec;
|
||||
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers;
|
||||
|
||||
|
||||
async_handler_collector(Executor & exec,
|
||||
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers)
|
||||
: exec(exec), handlers(handlers) {}
|
||||
|
||||
template<typename T>
|
||||
void operator()(T & t) const
|
||||
{
|
||||
handlers.push_back(t.on_exit_handler(exec));
|
||||
}
|
||||
};
|
||||
|
||||
//Also set's up waiting for the exit, so it can close async stuff.
|
||||
struct io_context_ref : handler_base_ext
|
||||
{
|
||||
io_context_ref(boost::asio::io_context & ios) : ios(ios)
|
||||
{
|
||||
|
||||
}
|
||||
boost::asio::io_context &get() {return ios;};
|
||||
|
||||
template <class Executor>
|
||||
void on_success(Executor& exec)
|
||||
{
|
||||
ios.notify_fork(boost::asio::io_context::fork_parent);
|
||||
//must be on the heap, so I can move it into the lambda.
|
||||
auto asyncs = boost::fusion::filter_if<
|
||||
is_async_handler<
|
||||
typename std::remove_reference< boost::mpl::_ > ::type
|
||||
>>(exec.seq);
|
||||
|
||||
//ok, check if there are actually any.
|
||||
if (boost::fusion::empty(asyncs))
|
||||
return;
|
||||
|
||||
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
|
||||
funcs.reserve(boost::fusion::size(asyncs));
|
||||
boost::fusion::for_each(asyncs, async_handler_collector<Executor>(exec, funcs));
|
||||
|
||||
auto & es = exec.exit_status;
|
||||
|
||||
auto wh = [funcs, es](int val, const std::error_code & ec)
|
||||
{
|
||||
es->store(val);
|
||||
for (auto & func : funcs)
|
||||
func(::boost::process::v1::detail::posix::eval_exit_status(val), ec);
|
||||
};
|
||||
|
||||
sigchld_service.async_wait(exec.pid, std::move(wh));
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_setup (Executor &) const {/*ios.notify_fork(boost::asio::io_context::fork_prepare);*/}
|
||||
|
||||
template<typename Executor>
|
||||
void on_exec_setup (Executor &) const {/*ios.notify_fork(boost::asio::io_context::fork_child);*/}
|
||||
|
||||
template <class Executor>
|
||||
void on_error(Executor&, const std::error_code &) const {/*ios.notify_fork(boost::asio::io_context::fork_parent);*/}
|
||||
|
||||
private:
|
||||
boost::asio::io_context &ios;
|
||||
boost::process::v1::detail::posix::sigchld_service &sigchld_service = boost::asio::use_service<boost::process::v1::detail::posix::sigchld_service>(ios);
|
||||
};
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_WINDOWS_IO_CONTEXT_REF_HPP_ */
|
||||
80
include/boost/process/v1/detail/posix/is_running.hpp
Normal file
80
include/boost/process/v1/detail/posix/is_running.hpp
Normal file
@@ -0,0 +1,80 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_IS_RUNNING_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_IS_RUNNING_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/posix/child_handle.hpp>
|
||||
#include <system_error>
|
||||
#include <sys/wait.h>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
// Use the "stopped" state (WIFSTOPPED) to indicate "not terminated".
|
||||
// This bit arrangement of status codes is not guaranteed by POSIX, but (according to comments in
|
||||
// the glibc <bits/waitstatus.h> header) is the same across systems in practice.
|
||||
constexpr int still_active = 0x017f;
|
||||
static_assert(WIFSTOPPED(still_active), "Expected still_active to indicate WIFSTOPPED");
|
||||
static_assert(!WIFEXITED(still_active), "Expected still_active to not indicate WIFEXITED");
|
||||
static_assert(!WIFSIGNALED(still_active), "Expected still_active to not indicate WIFSIGNALED");
|
||||
static_assert(!WIFCONTINUED(still_active), "Expected still_active to not indicate WIFCONTINUED");
|
||||
|
||||
inline bool is_running(int code)
|
||||
{
|
||||
return !WIFEXITED(code) && !WIFSIGNALED(code);
|
||||
}
|
||||
|
||||
inline bool is_running(const child_handle &p, int & exit_code, std::error_code &ec) noexcept
|
||||
{
|
||||
int status;
|
||||
auto ret = ::waitpid(p.pid, &status, WNOHANG);
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
if (errno != ECHILD) //because it no child is running, then this one isn't either, obviously.
|
||||
ec = ::boost::process::v1::detail::get_last_error();
|
||||
return false;
|
||||
}
|
||||
else if (ret == 0)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
ec.clear();
|
||||
|
||||
if (!is_running(status))
|
||||
exit_code = status;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool is_running(const child_handle &p, int & exit_code)
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = is_running(p, exit_code, ec);
|
||||
boost::process::v1::detail::throw_error(ec, "waitpid(2) failed in is_running");
|
||||
return b;
|
||||
}
|
||||
|
||||
inline int eval_exit_status(int code)
|
||||
{
|
||||
if (WIFEXITED(code))
|
||||
{
|
||||
return WEXITSTATUS(code);
|
||||
}
|
||||
else if (WIFSIGNALED(code))
|
||||
{
|
||||
return WTERMSIG(code);
|
||||
}
|
||||
else
|
||||
{
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
43
include/boost/process/v1/detail/posix/null_in.hpp
Normal file
43
include/boost/process/v1/detail/posix/null_in.hpp
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_NULL_IN_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_NULL_IN_HPP
|
||||
|
||||
#include <boost/process/v1/pipe.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/detail/posix/file_descriptor.hpp>
|
||||
#include <unistd.h>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
struct null_in : handler_base_ext, ::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
file_descriptor source{"/dev/null", file_descriptor::read};
|
||||
|
||||
std::array<int, 2> get_used_handles()
|
||||
{
|
||||
return {{STDIN_FILENO, source.handle()}};
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
template <class Executor>
|
||||
void on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(source.handle(), STDIN_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
}
|
||||
};
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
68
include/boost/process/v1/detail/posix/null_out.hpp
Normal file
68
include/boost/process/v1/detail/posix/null_out.hpp
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_POSIX_PIPE_OUT_HPP
|
||||
#define BOOST_PROCESS_POSIX_PIPE_OUT_HPP
|
||||
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/detail/posix/file_descriptor.hpp>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
#include <unistd.h>
|
||||
#include <array>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
template<int p1, int p2>
|
||||
struct null_out : handler_base_ext, ::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
file_descriptor sink{"/dev/null", file_descriptor::write};
|
||||
|
||||
template <typename Executor>
|
||||
void on_exec_setup(Executor &e) const;
|
||||
|
||||
std::array<int, 3> get_used_handles()
|
||||
{
|
||||
const auto pp1 = p1 != -1 ? p1 : p2;
|
||||
const auto pp2 = p2 != -1 ? p2 : p1;
|
||||
|
||||
return {sink.handle(), pp1, pp2};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
template<typename Executor>
|
||||
void null_out<1,-1>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(sink.handle(), STDOUT_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename Executor>
|
||||
void null_out<2,-1>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(sink.handle(), STDERR_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename Executor>
|
||||
void null_out<1,2>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(sink.handle(), STDOUT_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
if (::dup2(sink.handle(), STDERR_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
48
include/boost/process/v1/detail/posix/on_exit.hpp
Normal file
48
include/boost/process/v1/detail/posix/on_exit.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_POSIX_ON_EXIT_HPP_
|
||||
#define BOOST_PROCESS_POSIX_ON_EXIT_HPP_
|
||||
|
||||
#include <boost/asio/execution.hpp>
|
||||
#include <boost/process/v1/async.hpp>
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
#include <boost/process/v1/detail/posix/async_handler.hpp>
|
||||
#include <system_error>
|
||||
#include <functional>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
|
||||
template<typename Tuple>
|
||||
inline asio::io_context& get_io_context(const Tuple & tup);
|
||||
|
||||
namespace posix {
|
||||
|
||||
struct on_exit_ : boost::process::v1::detail::posix::async_handler
|
||||
{
|
||||
std::function<void(int, const std::error_code&)> handler;
|
||||
on_exit_(const std::function<void(int, const std::error_code&)> & handler) : handler(handler)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
std::function<void(int, const std::error_code&)> on_exit_handler(Executor& exec)
|
||||
{
|
||||
auto v = boost::asio::prefer(boost::process::v1::detail::get_io_context(exec.seq).get_executor(),
|
||||
boost::asio::execution::outstanding_work.tracked);
|
||||
auto handler_ = this->handler;
|
||||
return
|
||||
[handler_, v](int exit_code, const std::error_code & ec)
|
||||
{
|
||||
handler_(exit_code, ec);
|
||||
};
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}}}}
|
||||
#endif /* BOOST_PROCESS_POSIX_ON_EXIT_HPP_ */
|
||||
98
include/boost/process/v1/detail/posix/pipe_in.hpp
Normal file
98
include/boost/process/v1/detail/posix/pipe_in.hpp
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// 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_POSIX_PIPE_IN_HPP
|
||||
#define BOOST_PROCESS_POSIX_PIPE_IN_HPP
|
||||
|
||||
#include <boost/process/v1/pipe.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <unistd.h>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
struct pipe_in : handler_base_ext, ::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
int source;
|
||||
int sink; //opposite end
|
||||
|
||||
pipe_in(int sink, int source) : source(source), sink(sink) {}
|
||||
|
||||
std::array<int, 3> get_used_handles()
|
||||
{
|
||||
return {{STDIN_FILENO, source, sink}};
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
pipe_in(T & p) : source(p.native_source()), sink(p.native_sink())
|
||||
{
|
||||
p.assign_source(-1);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor &, const std::error_code &) const
|
||||
{
|
||||
::close(source);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_success(Executor &) const
|
||||
{
|
||||
::close(source);
|
||||
}
|
||||
|
||||
template <class Executor>
|
||||
void on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(source, STDIN_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
if (source != STDIN_FILENO)
|
||||
::close(source);
|
||||
|
||||
::close(sink);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class async_pipe;
|
||||
|
||||
struct async_pipe_in : public pipe_in
|
||||
{
|
||||
async_pipe &pipe;
|
||||
|
||||
template<typename AsyncPipe>
|
||||
async_pipe_in(AsyncPipe & p) : pipe_in(p.native_sink(), p.native_source()), pipe(p)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Pipe, typename Executor>
|
||||
static void close(Pipe & pipe, Executor &)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
std::move(pipe).source().close(ec);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor & exec, const std::error_code &)
|
||||
{
|
||||
close(pipe, exec);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_success(Executor &exec)
|
||||
{
|
||||
close(pipe, exec);
|
||||
}
|
||||
};
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
131
include/boost/process/v1/detail/posix/pipe_out.hpp
Normal file
131
include/boost/process/v1/detail/posix/pipe_out.hpp
Normal file
@@ -0,0 +1,131 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_PIPE_OUT_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_PIPE_OUT_HPP
|
||||
|
||||
#include <boost/process/v1/pipe.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <unistd.h>
|
||||
#include <array>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
template<int p1, int p2>
|
||||
struct pipe_out : handler_base_ext, ::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
int sink;
|
||||
int source; //opposite end
|
||||
|
||||
std::array<int, 4> get_used_handles()
|
||||
{
|
||||
const auto pp1 = p1 != -1 ? p1 : p2;
|
||||
const auto pp2 = p2 != -1 ? p2 : p1;
|
||||
|
||||
return {source, sink, pp1, pp2};
|
||||
}
|
||||
|
||||
pipe_out(int sink, int source) : sink(sink), source(source) {}
|
||||
|
||||
template<typename T>
|
||||
pipe_out(T & p) : sink(p.native_sink()), source(p.native_source())
|
||||
{
|
||||
p.assign_sink(-1);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor &, const std::error_code &) const
|
||||
{
|
||||
::close(sink);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_success(Executor &) const
|
||||
{
|
||||
::close(sink);
|
||||
}
|
||||
|
||||
template <typename Executor>
|
||||
void on_exec_setup(Executor &e) const;
|
||||
};
|
||||
|
||||
template<>
|
||||
template<typename Executor>
|
||||
void pipe_out<1,-1>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(sink, STDOUT_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
if (sink != STDOUT_FILENO)
|
||||
::close(sink);
|
||||
::close(source);
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename Executor>
|
||||
void pipe_out<2,-1>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(sink, STDERR_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
if (sink != STDOUT_FILENO)
|
||||
::close(sink);
|
||||
::close(source);
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename Executor>
|
||||
void pipe_out<1,2>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(sink, STDOUT_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
if (::dup2(sink, STDERR_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
if ((sink != STDOUT_FILENO) && (sink != STDERR_FILENO))
|
||||
::close(sink);
|
||||
::close(source);
|
||||
}
|
||||
|
||||
class async_pipe;
|
||||
|
||||
template<int p1, int p2>
|
||||
struct async_pipe_out : public pipe_out<p1, p2>
|
||||
{
|
||||
async_pipe &pipe;
|
||||
template<typename AsyncPipe>
|
||||
async_pipe_out(AsyncPipe & p) : pipe_out<p1, p2>(p.native_sink(), p.native_source()), pipe(p)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Pipe, typename Executor>
|
||||
static void close(Pipe & pipe, Executor &)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
std::move(pipe).sink().close(ec);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor & exec, const std::error_code &)
|
||||
{
|
||||
close(pipe, exec);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_success(Executor &exec)
|
||||
{
|
||||
close(pipe, exec);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
44
include/boost/process/v1/detail/posix/search_path.hpp
Normal file
44
include/boost/process/v1/detail/posix/search_path.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// 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_POSIX_SEARCH_PATH_HPP
|
||||
#define BOOST_PROCESS_POSIX_SEARCH_PATH_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/filesystem.hpp>
|
||||
#include <boost/tokenizer.hpp>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
inline boost::process::v1::filesystem::path search_path(
|
||||
const boost::process::v1::filesystem::path &filename,
|
||||
const std::vector<boost::process::v1::filesystem::path> &path)
|
||||
{
|
||||
for (const boost::process::v1::filesystem::path & pp : path)
|
||||
{
|
||||
auto p = pp / filename;
|
||||
#if defined(BOOST_PROCESS_USE_STD_FS)
|
||||
std::error_code ec;
|
||||
#else
|
||||
boost::system::error_code ec;
|
||||
#endif
|
||||
bool file = boost::process::v1::filesystem::is_regular_file(p, ec);
|
||||
if (!ec && file && ::access(p.c_str(), X_OK) == 0)
|
||||
return p;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
32
include/boost/process/v1/detail/posix/shell_path.hpp
Normal file
32
include/boost/process/v1/detail/posix/shell_path.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// 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_POSIX_SHELL_PATH_HPP
|
||||
#define BOOST_PROCESS_POSIX_SHELL_PATH_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/process/v1/filesystem.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
inline boost::process::v1::filesystem::path shell_path()
|
||||
{
|
||||
return "/bin/sh";
|
||||
}
|
||||
|
||||
inline boost::process::v1::filesystem::path shell_path(std::error_code &ec)
|
||||
{
|
||||
ec.clear();
|
||||
return "/bin/sh";
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
152
include/boost/process/v1/detail/posix/sigchld_service.hpp
Normal file
152
include/boost/process/v1/detail/posix/sigchld_service.hpp
Normal file
@@ -0,0 +1,152 @@
|
||||
// Copyright (c) 2017 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_SIGCHLD_SERVICE_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_SIGCHLD_SERVICE_HPP_
|
||||
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/dispatch.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/consign.hpp>
|
||||
#include <boost/asio/append.hpp>
|
||||
#include <boost/asio/signal_set.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <signal.h>
|
||||
#include <functional>
|
||||
#include <sys/wait.h>
|
||||
#include <list>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
class sigchld_service : public boost::asio::detail::service_base<sigchld_service>
|
||||
{
|
||||
boost::asio::strand<boost::asio::io_context::executor_type> _strand{get_io_context().get_executor()};
|
||||
boost::asio::signal_set _signal_set{get_io_context(), SIGCHLD};
|
||||
|
||||
std::list<std::pair<::pid_t, std::function<void(int, std::error_code)>>> _receivers;
|
||||
inline void _handle_signal(const boost::system::error_code & ec);
|
||||
|
||||
struct initiate_async_wait_op
|
||||
{
|
||||
sigchld_service * self;
|
||||
template<typename Initiation>
|
||||
void operator()(Initiation && init, ::pid_t pid)
|
||||
{
|
||||
// check if the child actually is running first
|
||||
int status;
|
||||
auto pid_res = ::waitpid(pid, &status, WNOHANG);
|
||||
if (pid_res < 0)
|
||||
{
|
||||
auto ec = get_last_error();
|
||||
boost::asio::post(
|
||||
self->_strand,
|
||||
asio::append(std::forward<Initiation>(init), pid_res, ec));
|
||||
}
|
||||
else if ((pid_res == pid) && (WIFEXITED(status) || WIFSIGNALED(status)))
|
||||
boost::asio::post(
|
||||
self->_strand,
|
||||
boost::asio::append(std::forward<Initiation>(init), status, std::error_code{}));
|
||||
else //still running
|
||||
{
|
||||
sigchld_service * self_ = self;
|
||||
if (self->_receivers.empty())
|
||||
self->_signal_set.async_wait(
|
||||
boost::asio::bind_executor(
|
||||
self->_strand,
|
||||
[self_](const boost::system::error_code &ec, int)
|
||||
{
|
||||
self_->_handle_signal(ec);
|
||||
}));
|
||||
self->_receivers.emplace_back(pid, init);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
sigchld_service(boost::asio::io_context & io_context)
|
||||
: boost::asio::detail::service_base<sigchld_service>(io_context)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename SignalHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(SignalHandler,
|
||||
void (int, std::error_code))
|
||||
async_wait(::pid_t pid, SignalHandler && handler)
|
||||
{
|
||||
return boost::asio::async_initiate<
|
||||
SignalHandler,
|
||||
void(int, std::error_code)>(
|
||||
initiate_async_wait_op{this}, handler, pid);
|
||||
}
|
||||
void shutdown() override
|
||||
{
|
||||
_receivers.clear();
|
||||
}
|
||||
|
||||
void cancel()
|
||||
{
|
||||
_signal_set.cancel();
|
||||
}
|
||||
void cancel(boost::system::error_code & ec)
|
||||
{
|
||||
_signal_set.cancel(ec);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void sigchld_service::_handle_signal(const boost::system::error_code & ec)
|
||||
{
|
||||
std::error_code ec_{ec.value(), std::system_category()};
|
||||
|
||||
if (ec_)
|
||||
{
|
||||
for (auto & r : _receivers)
|
||||
r.second(-1, ec_);
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto & r : _receivers) {
|
||||
int status;
|
||||
int pid = ::waitpid(r.first, &status, WNOHANG);
|
||||
if (pid < 0) {
|
||||
// error (eg: the process no longer exists)
|
||||
r.second(-1, get_last_error());
|
||||
r.first = 0; // mark for deletion
|
||||
} else if (pid == r.first) {
|
||||
r.second(status, ec_);
|
||||
r.first = 0; // mark for deletion
|
||||
}
|
||||
// otherwise the process is still around
|
||||
}
|
||||
|
||||
_receivers.erase(std::remove_if(_receivers.begin(), _receivers.end(),
|
||||
[](const std::pair<::pid_t, std::function<void(int, std::error_code)>> & p)
|
||||
{
|
||||
return p.first == 0;
|
||||
}),
|
||||
_receivers.end());
|
||||
|
||||
if (!_receivers.empty())
|
||||
{
|
||||
_signal_set.async_wait(
|
||||
[this](const boost::system::error_code & ec, int)
|
||||
{
|
||||
boost::asio::post(_strand, [this, ec]{this->_handle_signal(ec);});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
79
include/boost/process/v1/detail/posix/signal.hpp
Normal file
79
include/boost/process/v1/detail/posix/signal.hpp
Normal file
@@ -0,0 +1,79 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_POSIX_SIGNAL_HPP
|
||||
#define BOOST_PROCESS_POSIX_SIGNAL_HPP
|
||||
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <signal.h>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
#if defined(__GLIBC__)
|
||||
using sighandler_t = ::sighandler_t;
|
||||
#else
|
||||
using sighandler_t = void(*)(int);
|
||||
#endif
|
||||
|
||||
|
||||
struct sig_init_ : handler_base_ext
|
||||
{
|
||||
|
||||
sig_init_ (sighandler_t handler) : _handler(handler) {}
|
||||
|
||||
template <class PosixExecutor>
|
||||
void on_exec_setup(PosixExecutor&)
|
||||
{
|
||||
_old = ::signal(SIGCHLD, _handler);
|
||||
}
|
||||
|
||||
template <class Executor>
|
||||
void on_error(Executor&, const std::error_code &)
|
||||
{
|
||||
if (!_reset)
|
||||
{
|
||||
::signal(SIGCHLD, _old);
|
||||
_reset = true;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Executor>
|
||||
void on_success(Executor&)
|
||||
{
|
||||
if (!_reset)
|
||||
{
|
||||
::signal(SIGCHLD, _old);
|
||||
_reset = true;
|
||||
}
|
||||
}
|
||||
private:
|
||||
bool _reset = false;
|
||||
::boost::process::v1::detail::posix::sighandler_t _old{0};
|
||||
::boost::process::v1::detail::posix::sighandler_t _handler{0};
|
||||
};
|
||||
|
||||
struct sig_
|
||||
{
|
||||
constexpr sig_() {}
|
||||
|
||||
sig_init_ operator()(::boost::process::v1::detail::posix::sighandler_t h) const {return h;}
|
||||
sig_init_ operator= (::boost::process::v1::detail::posix::sighandler_t h) const {return h;}
|
||||
sig_init_ dfl() const {return SIG_DFL;}
|
||||
sig_init_ ign() const {return SIG_IGN;}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
39
include/boost/process/v1/detail/posix/start_dir.hpp
Normal file
39
include/boost/process/v1/detail/posix/start_dir.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_START_DIR_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_START_DIR_HPP
|
||||
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
template<typename Char>
|
||||
struct start_dir_init : handler_base_ext
|
||||
{
|
||||
typedef Char value_type;
|
||||
typedef std::basic_string<value_type> string_type;
|
||||
start_dir_init(string_type s) : s_(std::move(s)) {}
|
||||
|
||||
template <class PosixExecutor>
|
||||
void on_exec_setup(PosixExecutor&) const
|
||||
{
|
||||
boost::ignore_unused(::chdir(s_.c_str()));
|
||||
}
|
||||
const string_type & str() const {return s_;}
|
||||
private:
|
||||
string_type s_;
|
||||
};
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
42
include/boost/process/v1/detail/posix/terminate.hpp
Normal file
42
include/boost/process/v1/detail/posix/terminate.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_TERMINATE_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_TERMINATE_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/posix/child_handle.hpp>
|
||||
#include <system_error>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
inline void terminate(const child_handle &p, std::error_code &ec) noexcept
|
||||
{
|
||||
if (::kill(p.pid, SIGKILL) == -1)
|
||||
ec = boost::process::v1::detail::get_last_error();
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
int status;
|
||||
::waitpid(p.pid, &status, 0); //should not be WNOHANG, since that would allow zombies.
|
||||
}
|
||||
|
||||
inline void terminate(const child_handle &p)
|
||||
{
|
||||
std::error_code ec;
|
||||
terminate(p, ec);
|
||||
boost::process::v1::detail::throw_error(ec, "kill(2) failed");
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
33
include/boost/process/v1/detail/posix/use_vfork.hpp
Normal file
33
include/boost/process/v1/detail/posix/use_vfork.hpp
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* use_vfork.hpp
|
||||
*
|
||||
* Created on: 17.06.2016
|
||||
* Author: klemens
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_USE_VFORK_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_USE_VFORK_HPP_
|
||||
|
||||
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <boost/fusion/sequence/intrinsic/has_key.hpp>
|
||||
#include <boost/fusion/container/set/convert.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
struct use_vfork_ : handler_base_ext
|
||||
{
|
||||
constexpr use_vfork_(){};
|
||||
};
|
||||
|
||||
template<typename Sequence>
|
||||
struct shall_use_vfork
|
||||
{
|
||||
typedef typename boost::fusion::result_of::as_set<Sequence>::type set_type;
|
||||
typedef typename boost::fusion::result_of::has_key<set_type, const use_vfork_&>::type type;
|
||||
};
|
||||
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_POSIX_USE_VFORK_HPP_ */
|
||||
241
include/boost/process/v1/detail/posix/wait_for_exit.hpp
Normal file
241
include/boost/process/v1/detail/posix/wait_for_exit.hpp
Normal file
@@ -0,0 +1,241 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_WAIT_FOR_EXIT_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_WAIT_FOR_EXIT_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/posix/child_handle.hpp>
|
||||
#include <system_error>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
inline void wait(const child_handle &p, int & exit_code, std::error_code &ec) noexcept
|
||||
{
|
||||
pid_t ret;
|
||||
int status;
|
||||
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(p.pid, &status, 0);
|
||||
}
|
||||
while (((ret == -1) && (errno == EINTR)) ||
|
||||
(ret != -1 && !WIFEXITED(status) && !WIFSIGNALED(status)));
|
||||
|
||||
if (ret == -1)
|
||||
ec = boost::process::v1::detail::get_last_error();
|
||||
else
|
||||
{
|
||||
ec.clear();
|
||||
exit_code = status;
|
||||
}
|
||||
}
|
||||
|
||||
inline void wait(const child_handle &p, int & exit_code) noexcept
|
||||
{
|
||||
std::error_code ec;
|
||||
wait(p, exit_code, ec);
|
||||
boost::process::v1::detail::throw_error(ec, "waitpid(2) failed in wait");
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
inline bool wait_until(
|
||||
const child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::time_point<Clock, Duration>& time_out,
|
||||
std::error_code & ec) noexcept
|
||||
{
|
||||
::sigset_t sigset;
|
||||
|
||||
//I need to set the signal, because it might be ignore / default, in which case sigwait might not work.
|
||||
|
||||
using _signal_t = void(*)(int);
|
||||
static thread_local _signal_t sigchld_handler = SIG_DFL;
|
||||
|
||||
struct signal_interceptor_t
|
||||
{
|
||||
static void handler_func(int val)
|
||||
{
|
||||
if ((sigchld_handler != SIG_DFL) && (sigchld_handler != SIG_IGN))
|
||||
sigchld_handler(val);
|
||||
}
|
||||
signal_interceptor_t() { sigchld_handler = ::signal(SIGCHLD, &handler_func); }
|
||||
~signal_interceptor_t() { ::signal(SIGCHLD, sigchld_handler); sigchld_handler = SIG_DFL;}
|
||||
|
||||
} signal_interceptor{};
|
||||
|
||||
if (sigemptyset(&sigset) != 0)
|
||||
{
|
||||
ec = get_last_error();
|
||||
return false;
|
||||
}
|
||||
if (sigaddset(&sigset, SIGCHLD) != 0)
|
||||
{
|
||||
ec = get_last_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
auto get_timespec =
|
||||
[](const Duration & dur)
|
||||
{
|
||||
::timespec ts;
|
||||
ts.tv_sec = std::chrono::duration_cast<std::chrono::seconds>(dur).count();
|
||||
ts.tv_nsec = std::chrono::duration_cast<std::chrono::nanoseconds>(dur).count() % 1000000000;
|
||||
return ts;
|
||||
};
|
||||
|
||||
int ret;
|
||||
int status{0};
|
||||
|
||||
struct ::sigaction old_sig;
|
||||
if (-1 == ::sigaction(SIGCHLD, nullptr, &old_sig))
|
||||
{
|
||||
ec = get_last_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool timed_out;
|
||||
|
||||
#if defined(BOOST_POSIX_HAS_SIGTIMEDWAIT)
|
||||
do
|
||||
{
|
||||
auto ts = get_timespec(time_out - Clock::now());
|
||||
auto ret_sig = ::sigtimedwait(&sigset, nullptr, &ts);
|
||||
errno = 0;
|
||||
ret = ::waitpid(p.pid, &status, WNOHANG);
|
||||
|
||||
if ((ret_sig == SIGCHLD) && (old_sig.sa_handler != SIG_DFL) && (old_sig.sa_handler != SIG_IGN))
|
||||
old_sig.sa_handler(ret);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
timed_out = Clock::now() >= time_out;
|
||||
if (timed_out)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while ((ret == 0) ||
|
||||
(((ret == -1) && errno == EINTR) ||
|
||||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status))));
|
||||
#else
|
||||
//if we do not have sigtimedwait, we fork off a child process to get the signal in time
|
||||
pid_t timeout_pid = ::fork();
|
||||
if (timeout_pid == -1)
|
||||
{
|
||||
ec = boost::process::v1::detail::get_last_error();
|
||||
return true;
|
||||
}
|
||||
else if (timeout_pid == 0)
|
||||
{
|
||||
auto ts = get_timespec(time_out - Clock::now());
|
||||
::timespec rem;
|
||||
while (ts.tv_sec > 0 || ts.tv_nsec > 0)
|
||||
{
|
||||
if (::nanosleep(&ts, &rem) != 0)
|
||||
{
|
||||
auto err = errno;
|
||||
if ((err == EINVAL) || (err == EFAULT))
|
||||
break;
|
||||
}
|
||||
ts = get_timespec(time_out - Clock::now());
|
||||
}
|
||||
::exit(0);
|
||||
}
|
||||
|
||||
struct child_cleaner_t
|
||||
{
|
||||
pid_t pid;
|
||||
~child_cleaner_t()
|
||||
{
|
||||
int res;
|
||||
::kill(pid, SIGKILL);
|
||||
::waitpid(pid, &res, 0);
|
||||
}
|
||||
};
|
||||
child_cleaner_t child_cleaner{timeout_pid};
|
||||
|
||||
do
|
||||
{
|
||||
int sig_{0};
|
||||
if ((::waitpid(timeout_pid, &status, WNOHANG) != 0)
|
||||
&& (WIFEXITED(status) || WIFSIGNALED(status)))
|
||||
|
||||
return false;
|
||||
|
||||
ret = ::sigwait(&sigset, &sig_);
|
||||
errno = 0;
|
||||
|
||||
if ((sig_ == SIGCHLD) &&
|
||||
(old_sig.sa_handler != SIG_DFL) && (old_sig.sa_handler != SIG_IGN))
|
||||
old_sig.sa_handler(ret);
|
||||
|
||||
ret = ::waitpid(p.pid, &status, WNOHANG);
|
||||
if (ret == 0) // == > is running
|
||||
{
|
||||
timed_out = Clock::now() >= time_out;
|
||||
if (timed_out)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while ((ret == 0) ||
|
||||
(((ret == -1) && errno == EINTR) ||
|
||||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status))));
|
||||
#endif
|
||||
|
||||
if (ret == -1)
|
||||
ec = boost::process::v1::detail::get_last_error();
|
||||
else
|
||||
{
|
||||
ec.clear();
|
||||
exit_code = status;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
inline bool wait_until(
|
||||
const child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::time_point<Clock, Duration>& time_out)
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = wait_until(p, exit_code, time_out, ec);
|
||||
boost::process::v1::detail::throw_error(ec, "waitpid(2) failed in wait_until");
|
||||
return b;
|
||||
}
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
const child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::duration<Rep, Period>& rel_time,
|
||||
std::error_code & ec) noexcept
|
||||
{
|
||||
return wait_until(p, exit_code, std::chrono::steady_clock::now() + rel_time, ec);
|
||||
}
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
const child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = wait_for(p, exit_code, rel_time, ec);
|
||||
boost::process::v1::detail::throw_error(ec, "waitpid(2) failed in wait_for");
|
||||
return b;
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
124
include/boost/process/v1/detail/posix/wait_group.hpp
Normal file
124
include/boost/process/v1/detail/posix/wait_group.hpp
Normal file
@@ -0,0 +1,124 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_WAIT_GROUP_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_WAIT_GROUP_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/posix/group_handle.hpp>
|
||||
#include <chrono>
|
||||
#include <system_error>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
inline void wait(const group_handle &p, std::error_code &ec) noexcept
|
||||
{
|
||||
pid_t ret;
|
||||
siginfo_t status;
|
||||
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(-p.grp, &status.si_status, 0);
|
||||
if (ret == -1)
|
||||
{
|
||||
ec = get_last_error();
|
||||
return;
|
||||
}
|
||||
|
||||
//ECHILD --> no child processes left.
|
||||
ret = ::waitid(P_PGID, p.grp, &status, WEXITED | WNOHANG);
|
||||
}
|
||||
while ((ret != -1) || (errno != ECHILD));
|
||||
|
||||
if (errno != ECHILD)
|
||||
ec = boost::process::v1::detail::get_last_error();
|
||||
else
|
||||
ec.clear();
|
||||
}
|
||||
|
||||
inline void wait(const group_handle &p) noexcept
|
||||
{
|
||||
std::error_code ec;
|
||||
wait(p, ec);
|
||||
boost::process::v1::detail::throw_error(ec, "waitpid(2) failed in wait");
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
inline bool wait_until(
|
||||
const group_handle &p,
|
||||
const std::chrono::time_point<Clock, Duration>& time_out,
|
||||
std::error_code & ec) noexcept
|
||||
{
|
||||
|
||||
::siginfo_t siginfo;
|
||||
|
||||
bool timed_out = false;
|
||||
int ret;
|
||||
|
||||
::timespec sleep_interval;
|
||||
sleep_interval.tv_sec = 0;
|
||||
sleep_interval.tv_nsec = 100000000;
|
||||
|
||||
|
||||
while (!(timed_out = (Clock::now() > time_out)))
|
||||
{
|
||||
ret = ::waitid(P_PGID, p.grp, &siginfo, WEXITED | WSTOPPED | WNOHANG);
|
||||
if (ret == -1)
|
||||
{
|
||||
if ((errno == ECHILD) || (errno == ESRCH))
|
||||
{
|
||||
ec.clear();
|
||||
return true;
|
||||
}
|
||||
ec = boost::process::v1::detail::get_last_error();
|
||||
return false;
|
||||
}
|
||||
//we can wait, because unlike in the wait_for_exit, we have no race condition regarding eh exit code.
|
||||
::nanosleep(&sleep_interval, nullptr);
|
||||
}
|
||||
return !timed_out;
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
inline bool wait_until(
|
||||
const group_handle &p,
|
||||
const std::chrono::time_point<Clock, Duration>& time_out) noexcept
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = wait_until(p, time_out, ec);
|
||||
boost::process::v1::detail::throw_error(ec, "waitpid(2) failed in wait_until");
|
||||
return b;
|
||||
}
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
const group_handle &p,
|
||||
const std::chrono::duration<Rep, Period>& rel_time,
|
||||
std::error_code & ec) noexcept
|
||||
{
|
||||
return wait_until(p, std::chrono::steady_clock::now() + rel_time, ec);
|
||||
}
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
const group_handle &p,
|
||||
const std::chrono::duration<Rep, Period>& rel_time) noexcept
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = wait_for(p, rel_time, ec);
|
||||
boost::process::v1::detail::throw_error(ec, "waitpid(2) failed in wait_for");
|
||||
return b;
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
36
include/boost/process/v1/detail/throw_on_error.hpp
Normal file
36
include/boost/process/v1/detail/throw_on_error.hpp
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_INITIALIZERS_THROW_ON_ERROR_HPP
|
||||
#define BOOST_PROCESS_DETAIL_INITIALIZERS_THROW_ON_ERROR_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
|
||||
struct throw_on_error_ : ::boost::process::v1::detail::handler
|
||||
{
|
||||
template <class Executor>
|
||||
void on_error(Executor& exec, const std::error_code & ec) const
|
||||
{
|
||||
throw process_error(ec, "process creation failed");
|
||||
}
|
||||
|
||||
const throw_on_error_ &operator()() const {return *this;}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
constexpr boost::process::v1::detail::throw_on_error_ throw_on_error;
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
17
include/boost/process/v1/detail/traits.hpp
Normal file
17
include/boost/process/v1/detail/traits.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_TRAITS_HPP_
|
||||
#define BOOST_PROCESS_TRAITS_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/traits/decl.hpp>
|
||||
#include <boost/process/v1/detail/traits/async.hpp>
|
||||
#include <boost/process/v1/detail/traits/cmd_or_exe.hpp>
|
||||
#include <boost/process/v1/detail/traits/env.hpp>
|
||||
#include <boost/process/v1/detail/traits/error.hpp>
|
||||
#include <boost/process/v1/detail/traits/wchar_t.hpp>
|
||||
|
||||
#endif /* BOOST_PROCESS_TRAITS_HPP_ */
|
||||
32
include/boost/process/v1/detail/traits/async.hpp
Normal file
32
include/boost/process/v1/detail/traits/async.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_TRAITS_ASYNC_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_TRAITS_ASYNC_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/traits/decl.hpp>
|
||||
|
||||
namespace boost { namespace asio {
|
||||
|
||||
class io_context;
|
||||
}}
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
|
||||
struct async_tag {};
|
||||
|
||||
template<>
|
||||
struct initializer_builder<async_tag>;
|
||||
|
||||
template<> struct initializer_tag<::boost::asio::io_context> { typedef async_tag type;};
|
||||
|
||||
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */
|
||||
85
include/boost/process/v1/detail/traits/cmd_or_exe.hpp
Normal file
85
include/boost/process/v1/detail/traits/cmd_or_exe.hpp
Normal file
@@ -0,0 +1,85 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_TRAITS_CMD_OR_EXE_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_TRAITS_CMD_OR_EXE_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
#include <initializer_list>
|
||||
#include <boost/process/v1/filesystem.hpp>
|
||||
#include <boost/process/v1/detail/traits/decl.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
|
||||
template<typename Char>
|
||||
struct cmd_or_exe_tag {};
|
||||
|
||||
struct shell_;
|
||||
|
||||
|
||||
template<> struct initializer_tag<const char* > { typedef cmd_or_exe_tag<char> type;};
|
||||
template<> struct initializer_tag<const wchar_t* > { typedef cmd_or_exe_tag<wchar_t> type;};
|
||||
|
||||
template<> struct initializer_tag<char* > { typedef cmd_or_exe_tag<char> type;};
|
||||
template<> struct initializer_tag<wchar_t* > { typedef cmd_or_exe_tag<wchar_t> type;};
|
||||
|
||||
template<std::size_t Size> struct initializer_tag<const char [Size]> { typedef cmd_or_exe_tag<char> type;};
|
||||
template<std::size_t Size> struct initializer_tag<const wchar_t [Size]> { typedef cmd_or_exe_tag<wchar_t> type;};
|
||||
|
||||
template<std::size_t Size> struct initializer_tag<const char (&)[Size]> { typedef cmd_or_exe_tag<char> type;};
|
||||
template<std::size_t Size> struct initializer_tag<const wchar_t (&)[Size]> { typedef cmd_or_exe_tag<wchar_t> type;};
|
||||
|
||||
template<> struct initializer_tag<std::basic_string<char >> { typedef cmd_or_exe_tag<char> type;};
|
||||
template<> struct initializer_tag<std::basic_string<wchar_t >> { typedef cmd_or_exe_tag<wchar_t> type;};
|
||||
|
||||
template<> struct initializer_tag<std::vector<std::basic_string<char >>> { typedef cmd_or_exe_tag<char> type;};
|
||||
template<> struct initializer_tag<std::vector<std::basic_string<wchar_t >>> { typedef cmd_or_exe_tag<wchar_t> type;};
|
||||
|
||||
template<> struct initializer_tag<std::initializer_list<std::basic_string<char >>> { typedef cmd_or_exe_tag<char> type;};
|
||||
template<> struct initializer_tag<std::initializer_list<std::basic_string<wchar_t >>> { typedef cmd_or_exe_tag<wchar_t> type;};
|
||||
|
||||
template<> struct initializer_tag<std::vector<char *>> { typedef cmd_or_exe_tag<char> type;};
|
||||
template<> struct initializer_tag<std::vector<wchar_t *>> { typedef cmd_or_exe_tag<wchar_t> type;};
|
||||
|
||||
template<> struct initializer_tag<std::initializer_list<char *>> { typedef cmd_or_exe_tag<char> type;};
|
||||
template<> struct initializer_tag<std::initializer_list<wchar_t *>> { typedef cmd_or_exe_tag<wchar_t> type;};
|
||||
|
||||
template<> struct initializer_tag<std::initializer_list<const char *>> { typedef cmd_or_exe_tag<char> type;};
|
||||
template<> struct initializer_tag<std::initializer_list<const wchar_t *>> { typedef cmd_or_exe_tag<wchar_t> type;};
|
||||
|
||||
template<> struct initializer_tag<shell_>
|
||||
{
|
||||
typedef cmd_or_exe_tag<typename boost::process::v1::filesystem::path::value_type> type;
|
||||
};
|
||||
|
||||
template<> struct initializer_tag<boost::process::v1::filesystem::path>
|
||||
{
|
||||
typedef cmd_or_exe_tag<typename boost::process::v1::filesystem::path::value_type> type;
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
struct exe_setter_;
|
||||
template <typename Char, bool Append = false>
|
||||
struct arg_setter_;
|
||||
|
||||
template <typename Char, bool Append>
|
||||
struct initializer_tag<arg_setter_<Char, Append>> { typedef cmd_or_exe_tag<Char> type;};
|
||||
|
||||
template<typename Char> struct initializer_tag<exe_setter_<Char>> { typedef cmd_or_exe_tag<Char> type;};
|
||||
|
||||
template<>
|
||||
struct initializer_builder<cmd_or_exe_tag<char>>;
|
||||
|
||||
template<>
|
||||
struct initializer_builder<cmd_or_exe_tag<wchar_t>>;
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_STRING_TRAITS_HPP_ */
|
||||
74
include/boost/process/v1/detail/traits/decl.hpp
Normal file
74
include/boost/process/v1/detail/traits/decl.hpp
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/none.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/v1/detail/windows/handler.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct is_initializer : std::is_base_of<handler_base, T> {};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct is_initializer<T&> : std::is_base_of<handler_base, T> {};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct initializer_tag;// { typedef void type; };
|
||||
|
||||
|
||||
//remove const
|
||||
template<typename T>
|
||||
struct initializer_tag<const T> { typedef typename initializer_tag<T>::type type; };
|
||||
|
||||
//remove &
|
||||
template<typename T>
|
||||
struct initializer_tag<T&> { typedef typename initializer_tag<T>::type type; };
|
||||
|
||||
//remove const &
|
||||
template<typename T>
|
||||
struct initializer_tag<const T&> { typedef typename initializer_tag<T>::type type; };
|
||||
|
||||
template<typename T>
|
||||
struct initializer_builder;
|
||||
|
||||
|
||||
template<typename First, typename ...Args>
|
||||
struct valid_argument_list;
|
||||
|
||||
template<typename First>
|
||||
struct valid_argument_list<First>
|
||||
{
|
||||
constexpr static bool value = is_initializer<First>::value || !std::is_void<typename initializer_tag<First>::type>::value;
|
||||
typedef std::integral_constant<bool, value> type;
|
||||
};
|
||||
|
||||
template<typename First, typename ...Args>
|
||||
struct valid_argument_list
|
||||
{
|
||||
constexpr static bool my_value = is_initializer<First>::value || !std::is_void<typename initializer_tag<First>::type>::value;
|
||||
constexpr static bool value = valid_argument_list<Args...>::value && my_value;
|
||||
typedef std::integral_constant<bool, value> type;
|
||||
};
|
||||
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */
|
||||
48
include/boost/process/v1/detail/traits/env.hpp
Normal file
48
include/boost/process/v1/detail/traits/env.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_TRAITS_ENV_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_TRAITS_ENV_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/traits/decl.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
|
||||
|
||||
template<typename Char>
|
||||
class basic_environment;
|
||||
|
||||
template<typename Char>
|
||||
class basic_native_environment;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename Char>
|
||||
struct env_tag {};
|
||||
|
||||
template<typename Char> struct env_set;
|
||||
template<typename Char> struct env_append;
|
||||
|
||||
template<typename Char> struct env_reset;
|
||||
template<typename Char> struct env_init;
|
||||
|
||||
|
||||
template<typename Char> struct initializer_tag<env_set<Char>> { typedef env_tag<Char> type; };
|
||||
template<typename Char> struct initializer_tag<env_append<Char>> { typedef env_tag<Char> type; };
|
||||
|
||||
template<typename Char> struct initializer_tag<env_reset<Char>> { typedef env_tag<Char> type;};
|
||||
template<typename Char> struct initializer_tag<env_init <Char>> { typedef env_tag<Char> type;};
|
||||
|
||||
template<typename Char> struct initializer_tag<::boost::process::v1::basic_environment<Char>> { typedef env_tag<Char> type; };
|
||||
template<typename Char> struct initializer_tag<::boost::process::v1::basic_native_environment<Char>> { typedef env_tag<Char> type; };
|
||||
|
||||
template<> struct initializer_builder<env_tag<char>>;
|
||||
template<> struct initializer_builder<env_tag<wchar_t>>;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}}}
|
||||
#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENV_HPP_ */
|
||||
25
include/boost/process/v1/detail/traits/error.hpp
Normal file
25
include/boost/process/v1/detail/traits/error.hpp
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_TRAITS_ERROR_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_TRAITS_ERROR_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <system_error>
|
||||
#include <boost/process/v1/detail/traits/decl.hpp>
|
||||
|
||||
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
|
||||
struct error_tag;
|
||||
|
||||
template<>
|
||||
struct initializer_tag<std::error_code>;
|
||||
|
||||
}}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */
|
||||
37
include/boost/process/v1/detail/traits/group.hpp
Normal file
37
include/boost/process/v1/detail/traits/group.hpp
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_TRAITS_GROUP_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_TRAITS_GROUP_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/traits/decl.hpp>
|
||||
|
||||
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
|
||||
|
||||
struct group;
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
struct group_tag {};
|
||||
|
||||
template<>
|
||||
struct make_initializer_t<group_tag>;
|
||||
|
||||
|
||||
template<> struct initializer_tag_t<::boost::process::v1::group> { typedef group_tag type;};
|
||||
|
||||
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */
|
||||
276
include/boost/process/v1/detail/traits/wchar_t.hpp
Normal file
276
include/boost/process/v1/detail/traits/wchar_t.hpp
Normal file
@@ -0,0 +1,276 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_TRAITS_WCHAR_T_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_TRAITS_WCHAR_T_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/process/v1/detail/traits/decl.hpp>
|
||||
#include <boost/process/v1/detail/traits/cmd_or_exe.hpp>
|
||||
#include <boost/process/v1/detail/traits/env.hpp>
|
||||
#include <boost/process/v1/locale.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
|
||||
//template
|
||||
|
||||
template<typename T> struct is_wchar_t : std::false_type {};
|
||||
|
||||
template<> struct is_wchar_t<boost::process::v1::filesystem::path> : std::is_same<typename boost::process::v1::filesystem::path::value_type, wchar_t>
|
||||
{
|
||||
};
|
||||
|
||||
template<> struct is_wchar_t<const wchar_t* > : std::true_type {};
|
||||
|
||||
template<> struct is_wchar_t<wchar_t* > : std::true_type {};
|
||||
|
||||
template<std::size_t Size> struct is_wchar_t<const wchar_t [Size]> : std::true_type {};
|
||||
template<std::size_t Size> struct is_wchar_t<const wchar_t (&)[Size]> : std::true_type {};
|
||||
|
||||
template<> struct is_wchar_t<std::wstring> : std::true_type {};
|
||||
template<> struct is_wchar_t<std::vector<std::wstring>> : std::true_type {};
|
||||
template<> struct is_wchar_t<std::initializer_list<std::wstring>> : std::true_type {};
|
||||
template<> struct is_wchar_t<std::vector<wchar_t *>> : std::true_type {};
|
||||
template<> struct is_wchar_t<std::initializer_list<wchar_t *>> : std::true_type {};
|
||||
|
||||
|
||||
|
||||
template<typename Char, typename T>
|
||||
struct char_converter
|
||||
{
|
||||
static T& conv(T & in)
|
||||
{
|
||||
return in;
|
||||
}
|
||||
static T&& conv(T&& in)
|
||||
{
|
||||
return std::move(in);
|
||||
}
|
||||
static const T& conv(const T & in)
|
||||
{
|
||||
return in;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Char, typename T>
|
||||
using char_converter_t = char_converter<Char,
|
||||
typename std::remove_cv<typename std::remove_reference<T>::type>::type>;
|
||||
|
||||
|
||||
template<>
|
||||
struct char_converter<char, const wchar_t*>
|
||||
{
|
||||
static std::string conv(const wchar_t* in)
|
||||
{
|
||||
std::size_t size = 0;
|
||||
while (in[size] != L'\0') size++;
|
||||
return ::boost::process::v1::detail::convert(in, in + size);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<char, wchar_t*>
|
||||
{
|
||||
static std::string conv(wchar_t* in)
|
||||
{
|
||||
std::size_t size = 0;
|
||||
while (in[size] != L'\0') size++;
|
||||
return ::boost::process::v1::detail::convert(in, in + size);
|
||||
}
|
||||
};
|
||||
|
||||
template<std::size_t Size>
|
||||
struct char_converter<char, wchar_t[Size]>
|
||||
{
|
||||
static std::string conv(const wchar_t(&in)[Size])
|
||||
{
|
||||
return ::boost::process::v1::detail::convert(in, in + Size -1);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, const char*>
|
||||
{
|
||||
static std::wstring conv(const char* in)
|
||||
{
|
||||
std::size_t size = 0;
|
||||
while (in[size] != '\0') size++;
|
||||
return ::boost::process::v1::detail::convert(in, in + size);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, char*>
|
||||
{
|
||||
static std::wstring conv(char* in)
|
||||
{
|
||||
std::size_t size = 0;
|
||||
while (in[size] != '\0') size++;
|
||||
return ::boost::process::v1::detail::convert(in, in + size);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<std::size_t Size>
|
||||
struct char_converter<wchar_t, char[Size]>
|
||||
{
|
||||
static std::wstring conv(const char(&in)[Size])
|
||||
{
|
||||
return ::boost::process::v1::detail::convert(in, in + Size -1);
|
||||
}
|
||||
};
|
||||
|
||||
//all the containers.
|
||||
template<>
|
||||
struct char_converter<wchar_t, std::string>
|
||||
{
|
||||
static std::wstring conv(const std::string & in)
|
||||
{
|
||||
return ::boost::process::v1::detail::convert(in);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<char, std::wstring>
|
||||
{
|
||||
static std::string conv(const std::wstring & in)
|
||||
{
|
||||
return ::boost::process::v1::detail::convert(in);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, std::vector<std::string>>
|
||||
{
|
||||
static std::vector<std::wstring> conv(const std::vector<std::string> & in)
|
||||
{
|
||||
std::vector<std::wstring> ret(in.size());
|
||||
std::transform(in.begin(), in.end(), ret.begin(),
|
||||
[](const std::string & st)
|
||||
{
|
||||
return convert(st);
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, std::initializer_list<std::string>>
|
||||
{
|
||||
static std::vector<std::wstring> conv(const std::initializer_list<std::string> & in)
|
||||
{
|
||||
std::vector<std::wstring> ret(in.size());
|
||||
std::transform(in.begin(), in.end(), ret.begin(),
|
||||
[](const std::string & st)
|
||||
{
|
||||
return convert(st);
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, std::vector<char* >>
|
||||
{
|
||||
static std::vector<std::wstring> conv(const std::vector<char* > & in)
|
||||
{
|
||||
std::vector<std::wstring> ret(in.size());
|
||||
std::transform(in.begin(), in.end(), ret.begin(),
|
||||
[](const char* st)
|
||||
{
|
||||
std::size_t sz = 0;
|
||||
while (st[sz] != '\0') sz++;
|
||||
return convert(st, st + sz);
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, std::initializer_list<char *>>
|
||||
{
|
||||
static std::vector<std::wstring> conv(const std::initializer_list<char * > & in)
|
||||
{
|
||||
std::vector<std::wstring> ret(in.size());
|
||||
std::transform(in.begin(), in.end(), ret.begin(),
|
||||
[](const char* st)
|
||||
{
|
||||
std::size_t sz = 0;
|
||||
while (st[sz] != '\0') sz++;
|
||||
return convert(st, st + sz);
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<char, std::vector<std::wstring>>
|
||||
{
|
||||
static std::vector<std::string> conv(const std::vector<std::wstring> & in)
|
||||
{
|
||||
std::vector<std::string> ret(in.size());
|
||||
std::transform(in.begin(), in.end(), ret.begin(),
|
||||
[](const std::wstring & st)
|
||||
{
|
||||
return convert(st);
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<char, std::initializer_list<std::wstring>>
|
||||
{
|
||||
static std::vector<std::string> conv(const std::initializer_list<std::wstring> & in)
|
||||
{
|
||||
std::vector<std::string> ret(in.size());
|
||||
std::transform(in.begin(), in.end(), ret.begin(),
|
||||
[](const std::wstring & st)
|
||||
{
|
||||
return convert(st);
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<char, std::vector<wchar_t* >>
|
||||
{
|
||||
static std::vector<std::string> conv(const std::vector<wchar_t* > & in)
|
||||
{
|
||||
std::vector<std::string> ret(in.size());
|
||||
std::transform(in.begin(), in.end(), ret.begin(),
|
||||
[](const wchar_t* st)
|
||||
{
|
||||
std::size_t sz = 0;
|
||||
while (st[sz] != L'\0') sz++;
|
||||
return convert(st, st + sz);
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<char, std::initializer_list<wchar_t * >>
|
||||
{
|
||||
static std::vector<std::string> conv(const std::initializer_list<wchar_t *> & in)
|
||||
{
|
||||
std::vector<std::string> ret(in.size());
|
||||
std::transform(in.begin(), in.end(), ret.begin(),
|
||||
[](const wchar_t* st)
|
||||
{
|
||||
std::size_t sz = 0;
|
||||
while (st[sz] != L'\0') sz++;
|
||||
return convert(st, st + sz);
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
#endif /* BOOST_PROCESS_DETAIL_TRAITS_WCHAR_T_HPP_ */
|
||||
81
include/boost/process/v1/detail/used_handles.hpp
Normal file
81
include/boost/process/v1/detail/used_handles.hpp
Normal file
@@ -0,0 +1,81 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_USED_HANDLES_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_USED_HANDLES_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
#include <boost/fusion/include/filter_if.hpp>
|
||||
#include <boost/fusion/include/for_each.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/v1/detail/posix/handles.hpp>
|
||||
#include <boost/process/v1/detail/posix/asio_fwd.hpp>
|
||||
#else
|
||||
#include <boost/process/v1/detail/windows/handles.hpp>
|
||||
#include <boost/process/v1/detail/windows/asio_fwd.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
|
||||
struct uses_handles
|
||||
{
|
||||
//If you get an error here, you must add a `get_handles` function that returns a range or a single handle value
|
||||
void get_used_handles() const;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct does_use_handle: std::is_base_of<uses_handles, T> {};
|
||||
|
||||
template<typename T>
|
||||
struct does_use_handle<T&> : std::is_base_of<uses_handles, T> {};
|
||||
|
||||
template<typename T>
|
||||
struct does_use_handle<const T&> : std::is_base_of<uses_handles, T> {};
|
||||
|
||||
template<typename Char, typename Sequence>
|
||||
class executor;
|
||||
|
||||
template<typename Func>
|
||||
struct foreach_handle_invocator
|
||||
{
|
||||
Func & func;
|
||||
foreach_handle_invocator(Func & func) : func(func) {}
|
||||
|
||||
|
||||
template<typename Range>
|
||||
void invoke(const Range & range) const
|
||||
{
|
||||
for (auto handle_ : range)
|
||||
func(handle_);
|
||||
|
||||
}
|
||||
void invoke(::boost::process::v1::detail::api::native_handle_type handle) const {func(handle);};
|
||||
|
||||
template<typename T>
|
||||
void operator()(T & val) const {invoke(val.get_used_handles());}
|
||||
};
|
||||
|
||||
template<typename Executor, typename Function>
|
||||
void foreach_used_handle(Executor &exec, Function &&func)
|
||||
{
|
||||
boost::fusion::for_each(boost::fusion::filter_if<does_use_handle<boost::mpl::_>>(exec.seq),
|
||||
foreach_handle_invocator<Function>(func));
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
std::vector<::boost::process::v1::detail::api::native_handle_type>
|
||||
get_used_handles(Executor &exec)
|
||||
{
|
||||
std::vector<::boost::process::v1::detail::api::native_handle_type> res = exec.get_used_handles();
|
||||
foreach_used_handle(exec, [&](::boost::process::v1::detail::api::native_handle_type handle){res.push_back(handle);});
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_USED_HANDLES_HPP_ */
|
||||
66
include/boost/process/v1/detail/windows/asio_fwd.hpp
Normal file
66
include/boost/process/v1/detail/windows/asio_fwd.hpp
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_ASIO_FWD_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_ASIO_FWD_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/asio/ts/netfwd.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace boost { namespace asio {
|
||||
|
||||
class mutable_buffer;
|
||||
class mutable_buffers_1;
|
||||
class const_buffer;
|
||||
class const_buffers_1;
|
||||
|
||||
template<typename Allocator>
|
||||
class basic_streambuf;
|
||||
|
||||
typedef basic_streambuf<std::allocator<char>> streambuf;
|
||||
|
||||
template <typename Handler>
|
||||
class basic_yield_context;
|
||||
|
||||
namespace windows {
|
||||
|
||||
template <typename Executor>
|
||||
class basic_stream_handle;
|
||||
typedef basic_stream_handle<any_io_executor> stream_handle;
|
||||
|
||||
template <typename Executor>
|
||||
class basic_object_handle;
|
||||
typedef basic_object_handle<any_io_executor> object_handle;
|
||||
|
||||
} //windows
|
||||
} //asio
|
||||
|
||||
namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
class async_pipe;
|
||||
|
||||
template<typename T>
|
||||
struct async_in_buffer;
|
||||
|
||||
template<int p1, int p2, typename Buffer>
|
||||
struct async_out_buffer;
|
||||
|
||||
template<int p1, int p2, typename Type>
|
||||
struct async_out_future;
|
||||
|
||||
} // windows
|
||||
} // detail
|
||||
|
||||
using ::boost::process::v1::detail::windows::async_pipe;
|
||||
|
||||
} // v1
|
||||
} // process
|
||||
} // boost
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_ASIO_FWD_HPP_ */
|
||||
41
include/boost/process/v1/detail/windows/async_handler.hpp
Normal file
41
include/boost/process/v1/detail/windows/async_handler.hpp
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_
|
||||
#define BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/windows/handler.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
struct require_io_context {};
|
||||
|
||||
struct async_handler : handler_base_ext, require_io_context
|
||||
{
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct is_async_handler : std::is_base_of<async_handler, T> {};
|
||||
template<typename T>
|
||||
struct is_async_handler<T&> : std::is_base_of<async_handler, T> {};
|
||||
template<typename T>
|
||||
struct is_async_handler<const T&> : std::is_base_of<async_handler, T> {};
|
||||
|
||||
template<typename T>
|
||||
struct does_require_io_context : std::is_base_of<require_io_context, T> {};
|
||||
|
||||
template<typename T>
|
||||
struct does_require_io_context<T&> : std::is_base_of<require_io_context, T> {};
|
||||
|
||||
template<typename T>
|
||||
struct does_require_io_context<const T&> : std::is_base_of<require_io_context, T> {};
|
||||
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_ */
|
||||
111
include/boost/process/v1/detail/windows/async_in.hpp
Normal file
111
include/boost/process/v1/detail/windows/async_in.hpp
Normal file
@@ -0,0 +1,111 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// 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_WINDOWS_INITIALIZERS_ASYNC_IN_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_IN_HPP
|
||||
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/winapi/handle_info.hpp>
|
||||
#include <boost/winapi/error_codes.hpp>
|
||||
|
||||
#include <boost/asio/write.hpp>
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
#include <boost/process/v1/detail/windows/async_handler.hpp>
|
||||
#include <boost/process/v1/detail/windows/asio_fwd.hpp>
|
||||
#include <boost/process/v1/async_pipe.hpp>
|
||||
#include <memory>
|
||||
#include <future>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
|
||||
template<typename Buffer>
|
||||
struct async_in_buffer : ::boost::process::v1::detail::windows::handler_base_ext,
|
||||
::boost::process::v1::detail::windows::require_io_context,
|
||||
::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
Buffer & buf;
|
||||
|
||||
std::shared_ptr<std::promise<void>> promise;
|
||||
async_in_buffer operator>(std::future<void> & fut)
|
||||
{
|
||||
promise = std::make_shared<std::promise<void>>();
|
||||
fut = promise->get_future(); return std::move(*this);
|
||||
}
|
||||
|
||||
std::shared_ptr<boost::process::v1::async_pipe> pipe;
|
||||
|
||||
::boost::winapi::HANDLE_ get_used_handles() const
|
||||
{
|
||||
return std::move(*pipe).source().native_handle();
|
||||
}
|
||||
|
||||
async_in_buffer(Buffer & buf) : buf(buf)
|
||||
{
|
||||
}
|
||||
template <typename Executor>
|
||||
inline void on_success(Executor&)
|
||||
{
|
||||
auto pipe_ = this->pipe;
|
||||
|
||||
if (this->promise)
|
||||
{
|
||||
auto promise_ = this->promise;
|
||||
|
||||
boost::asio::async_write(*pipe_, buf,
|
||||
[promise_](const boost::system::error_code & ec, std::size_t)
|
||||
{
|
||||
if (ec && (ec.value() != ::boost::winapi::ERROR_BROKEN_PIPE_))
|
||||
{
|
||||
std::error_code e(ec.value(), std::system_category());
|
||||
promise_->set_exception(std::make_exception_ptr(process_error(e)));
|
||||
}
|
||||
promise_->set_value();
|
||||
});
|
||||
}
|
||||
else
|
||||
boost::asio::async_write(*pipe_, buf,
|
||||
[pipe_](const boost::system::error_code&, std::size_t){});
|
||||
|
||||
std::move(*pipe_).source().close();
|
||||
|
||||
|
||||
this->pipe = nullptr;
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor &, const std::error_code &) const
|
||||
{
|
||||
::boost::winapi::CloseHandle(pipe->native_source());
|
||||
}
|
||||
|
||||
template <typename WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &exec)
|
||||
{
|
||||
if (!pipe)
|
||||
pipe = std::make_shared<boost::process::v1::async_pipe>(get_io_context(exec.seq));
|
||||
|
||||
::boost::winapi::HANDLE_ source_handle = std::move(*pipe).source().native_handle();
|
||||
|
||||
boost::winapi::SetHandleInformation(source_handle,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
exec.startup_info.hStdInput = source_handle;
|
||||
exec.startup_info.dwFlags |= boost::winapi::STARTF_USESTDHANDLES_;
|
||||
exec.inherit_handles = true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
186
include/boost/process/v1/detail/windows/async_out.hpp
Normal file
186
include/boost/process/v1/detail/windows/async_out.hpp
Normal file
@@ -0,0 +1,186 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// 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_WINDOWS_INITIALIZERS_ASYNC_OUT_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_OUT_HPP
|
||||
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/winapi/handle_info.hpp>
|
||||
#include <boost/winapi/error_codes.hpp>
|
||||
#include <boost/asio/read.hpp>
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
#include <boost/process/v1/detail/windows/asio_fwd.hpp>
|
||||
|
||||
#include <istream>
|
||||
#include <memory>
|
||||
#include <exception>
|
||||
#include <future>
|
||||
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
|
||||
template <typename Executor>
|
||||
inline void apply_out_handles(Executor &e, void* handle, std::integral_constant<int, 1>, std::integral_constant<int, -1>)
|
||||
{
|
||||
boost::winapi::SetHandleInformation(handle,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
e.startup_info.hStdOutput = handle;
|
||||
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
|
||||
template <typename Executor>
|
||||
inline void apply_out_handles(Executor &e, void* handle, std::integral_constant<int, 2>, std::integral_constant<int, -1>)
|
||||
{
|
||||
boost::winapi::SetHandleInformation(handle,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
|
||||
e.startup_info.hStdError = handle;
|
||||
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
|
||||
template <typename Executor>
|
||||
inline void apply_out_handles(Executor &e, void* handle, std::integral_constant<int, 1>, std::integral_constant<int, 2>)
|
||||
{
|
||||
boost::winapi::SetHandleInformation(handle,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
e.startup_info.hStdOutput = handle;
|
||||
e.startup_info.hStdError = handle;
|
||||
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
|
||||
template<int p1, int p2, typename Buffer>
|
||||
struct async_out_buffer : ::boost::process::v1::detail::windows::handler_base_ext,
|
||||
::boost::process::v1::detail::windows::require_io_context
|
||||
{
|
||||
Buffer & buf;
|
||||
|
||||
std::shared_ptr<boost::process::v1::async_pipe> pipe;
|
||||
|
||||
|
||||
async_out_buffer(Buffer & buf) : buf(buf)
|
||||
{
|
||||
}
|
||||
template <typename Executor>
|
||||
inline void on_success(Executor&)
|
||||
{
|
||||
auto pipe_ = this->pipe;
|
||||
boost::asio::async_read(*pipe_, buf,
|
||||
[pipe_](const boost::system::error_code&, std::size_t){});
|
||||
std::move(*pipe_).sink().close();
|
||||
this->pipe = nullptr;
|
||||
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor &, const std::error_code &) const
|
||||
{
|
||||
std::move(*pipe).sink().close();
|
||||
}
|
||||
|
||||
template <typename WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &exec)
|
||||
{
|
||||
if (!pipe)
|
||||
pipe = std::make_shared<boost::process::v1::async_pipe>(get_io_context(exec.seq));
|
||||
apply_out_handles(exec, std::move(*pipe).sink().native_handle(),
|
||||
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<int p1, int p2, typename Type>
|
||||
struct async_out_future : ::boost::process::v1::detail::windows::handler_base_ext,
|
||||
::boost::process::v1::detail::windows::require_io_context,
|
||||
::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
std::shared_ptr<boost::process::v1::async_pipe> pipe;
|
||||
std::shared_ptr<std::promise<Type>> promise = std::make_shared<std::promise<Type>>();
|
||||
std::shared_ptr<boost::asio::streambuf> buffer = std::make_shared<boost::asio::streambuf>();
|
||||
|
||||
::boost::winapi::HANDLE_ get_used_handles() const
|
||||
{
|
||||
return std::move(*pipe).sink().native_handle();
|
||||
}
|
||||
|
||||
|
||||
async_out_future(std::future<Type> & fut)
|
||||
{
|
||||
fut = promise->get_future();
|
||||
}
|
||||
template <typename Executor>
|
||||
inline void on_success(Executor&)
|
||||
{
|
||||
auto pipe_ = this->pipe;
|
||||
auto buffer_ = this->buffer;
|
||||
auto promise_ = this->promise;
|
||||
std::move(*pipe_).sink().close();
|
||||
boost::asio::async_read(*pipe_, *buffer_,
|
||||
[pipe_, buffer_, promise_](const boost::system::error_code& ec, std::size_t)
|
||||
{
|
||||
if (ec && (ec.value() != ::boost::winapi::ERROR_BROKEN_PIPE_))
|
||||
{
|
||||
std::error_code e(ec.value(), std::system_category());
|
||||
promise_->set_exception(std::make_exception_ptr(process_error(e)));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::istream is (buffer_.get());
|
||||
Type arg;
|
||||
if (buffer_->size() > 0)
|
||||
{
|
||||
arg.resize(buffer_->size());
|
||||
is.read(&*arg.begin(), buffer_->size());
|
||||
}
|
||||
|
||||
promise_->set_value(std::move(arg));
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
this->pipe = nullptr;
|
||||
this->buffer = nullptr;
|
||||
this->promise = nullptr;
|
||||
|
||||
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor &, const std::error_code &) const
|
||||
{
|
||||
std::move(*pipe).sink().close();
|
||||
}
|
||||
|
||||
template <typename WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &exec)
|
||||
{
|
||||
if (!pipe)
|
||||
pipe = std::make_shared<boost::process::v1::async_pipe>(get_io_context(exec.seq));
|
||||
|
||||
apply_out_handles(exec, std::move(*pipe).sink().native_handle(),
|
||||
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
482
include/boost/process/v1/detail/windows/async_pipe.hpp
Normal file
482
include/boost/process/v1/detail/windows/async_pipe.hpp
Normal file
@@ -0,0 +1,482 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_ASYNC_PIPE_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_ASYNC_PIPE_HPP_
|
||||
|
||||
#include <boost/winapi/basic_types.hpp>
|
||||
#include <boost/winapi/pipes.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/winapi/file_management.hpp>
|
||||
#include <boost/winapi/get_last_error.hpp>
|
||||
#include <boost/winapi/access_rights.hpp>
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/process/v1/detail/windows/basic_pipe.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/windows/stream_handle.hpp>
|
||||
#include <atomic>
|
||||
#include <system_error>
|
||||
#include <string>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
inline std::string make_pipe_name()
|
||||
{
|
||||
std::string name = "\\\\.\\pipe\\boost_process_auto_pipe_";
|
||||
|
||||
auto pid = ::boost::winapi::GetCurrentProcessId();
|
||||
|
||||
static std::atomic_size_t cnt{0};
|
||||
name += std::to_string(pid);
|
||||
name += "_";
|
||||
name += std::to_string(intptr_t(&cnt)); // to unclash Boost instances in plug-in DLLs
|
||||
name += "_";
|
||||
name += std::to_string(cnt++);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
class async_pipe
|
||||
{
|
||||
::boost::asio::windows::stream_handle _source;
|
||||
::boost::asio::windows::stream_handle _sink ;
|
||||
|
||||
inline async_pipe(boost::asio::io_context & ios_source,
|
||||
boost::asio::io_context & ios_sink,
|
||||
const std::string & name, bool private_);
|
||||
|
||||
public:
|
||||
typedef ::boost::winapi::HANDLE_ native_handle_type;
|
||||
typedef ::boost::asio::windows::stream_handle handle_type;
|
||||
typedef typename handle_type::executor_type executor_type;
|
||||
|
||||
async_pipe(boost::asio::io_context & ios) : async_pipe(ios, ios, make_pipe_name(), true) {}
|
||||
async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink)
|
||||
: async_pipe(ios_source, ios_sink, make_pipe_name(), true) {}
|
||||
|
||||
async_pipe(boost::asio::io_context & ios, const std::string & name)
|
||||
: async_pipe(ios, ios, name, false) {}
|
||||
|
||||
async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink, const std::string & name)
|
||||
: async_pipe(ios_source, ios_sink, name, false) {}
|
||||
|
||||
inline async_pipe(const async_pipe& rhs);
|
||||
async_pipe(async_pipe&& rhs) : _source(std::move(rhs._source)), _sink(std::move(rhs._sink))
|
||||
{
|
||||
}
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
explicit async_pipe(::boost::asio::io_context & ios_source,
|
||||
::boost::asio::io_context & ios_sink,
|
||||
const basic_pipe<CharT, Traits> & p)
|
||||
: _source(ios_source, p.native_source()), _sink(ios_sink, p.native_sink())
|
||||
{
|
||||
}
|
||||
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
explicit async_pipe(boost::asio::io_context & ios, const basic_pipe<CharT, Traits> & p)
|
||||
: async_pipe(ios, ios, p)
|
||||
{
|
||||
}
|
||||
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
inline async_pipe& operator=(const basic_pipe<CharT, Traits>& p);
|
||||
inline async_pipe& operator=(const async_pipe& rhs);
|
||||
|
||||
inline async_pipe& operator=(async_pipe&& rhs);
|
||||
|
||||
~async_pipe()
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
close(ec);
|
||||
}
|
||||
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
inline explicit operator basic_pipe<CharT, Traits>() const;
|
||||
|
||||
void cancel()
|
||||
{
|
||||
if (_sink.is_open())
|
||||
_sink.cancel();
|
||||
if (_source.is_open())
|
||||
_source.cancel();
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
if (_sink.is_open())
|
||||
{
|
||||
_sink.close();
|
||||
_sink = handle_type(_sink.get_executor());
|
||||
}
|
||||
if (_source.is_open())
|
||||
{
|
||||
_source.close();
|
||||
_source = handle_type(_source.get_executor());
|
||||
}
|
||||
}
|
||||
void close(boost::system::error_code & ec)
|
||||
{
|
||||
if (_sink.is_open())
|
||||
{
|
||||
_sink.close(ec);
|
||||
_sink = handle_type(_sink.get_executor());
|
||||
}
|
||||
if (_source.is_open())
|
||||
{
|
||||
_source.close(ec);
|
||||
_source = handle_type(_source.get_executor());
|
||||
}
|
||||
}
|
||||
|
||||
bool is_open() const
|
||||
{
|
||||
return _sink.is_open() || _source.is_open();
|
||||
}
|
||||
void async_close()
|
||||
{
|
||||
if (_sink.is_open())
|
||||
boost::asio::post(_sink.get_executor(), [this]{_sink.close();});
|
||||
if (_source.is_open())
|
||||
boost::asio::post(_source.get_executor(), [this]{_source.close();});
|
||||
}
|
||||
|
||||
template<typename MutableBufferSequence>
|
||||
std::size_t read_some(const MutableBufferSequence & buffers)
|
||||
{
|
||||
return _source.read_some(buffers);
|
||||
}
|
||||
template<typename MutableBufferSequence>
|
||||
std::size_t write_some(const MutableBufferSequence & buffers)
|
||||
{
|
||||
return _sink.write_some(buffers);
|
||||
}
|
||||
|
||||
template<typename MutableBufferSequence>
|
||||
std::size_t read_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
|
||||
{
|
||||
return _source.read_some(buffers, ec);
|
||||
}
|
||||
template<typename MutableBufferSequence>
|
||||
std::size_t write_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
|
||||
{
|
||||
return _sink.write_some(buffers, ec);
|
||||
}
|
||||
|
||||
native_handle_type native_source() const {return const_cast<boost::asio::windows::stream_handle&>(_source).native_handle();}
|
||||
native_handle_type native_sink () const {return const_cast<boost::asio::windows::stream_handle&>(_sink ).native_handle();}
|
||||
|
||||
template<typename MutableBufferSequence,
|
||||
typename ReadHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
ReadHandler, void(boost::system::error_code, std::size_t))
|
||||
async_read_some(
|
||||
const MutableBufferSequence & buffers,
|
||||
ReadHandler &&handler)
|
||||
{
|
||||
return _source.async_read_some(buffers, std::forward<ReadHandler>(handler));
|
||||
}
|
||||
|
||||
template<typename ConstBufferSequence,
|
||||
typename WriteHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
WriteHandler, void(boost::system::error_code, std::size_t))
|
||||
async_write_some(
|
||||
const ConstBufferSequence & buffers,
|
||||
WriteHandler && handler)
|
||||
{
|
||||
return _sink.async_write_some(buffers, std::forward<WriteHandler>(handler));
|
||||
}
|
||||
|
||||
const handle_type & sink () const & {return _sink;}
|
||||
const handle_type & source() const & {return _source;}
|
||||
|
||||
handle_type && source() && { return std::move(_source); }
|
||||
handle_type && sink() && { return std::move(_sink); }
|
||||
|
||||
handle_type source(::boost::asio::io_context& ios) &&
|
||||
{
|
||||
::boost::asio::windows::stream_handle stolen(ios.get_executor(), _source.native_handle());
|
||||
boost::system::error_code ec;
|
||||
_source.assign(::boost::winapi::INVALID_HANDLE_VALUE_, ec);
|
||||
return stolen;
|
||||
}
|
||||
handle_type sink (::boost::asio::io_context& ios) &&
|
||||
{
|
||||
::boost::asio::windows::stream_handle stolen(ios.get_executor(), _sink.native_handle());
|
||||
boost::system::error_code ec;
|
||||
_sink.assign(::boost::winapi::INVALID_HANDLE_VALUE_, ec);
|
||||
return stolen;
|
||||
}
|
||||
|
||||
handle_type source(::boost::asio::io_context& ios) const &
|
||||
{
|
||||
auto proc = ::boost::winapi::GetCurrentProcess();
|
||||
|
||||
::boost::winapi::HANDLE_ source;
|
||||
auto source_in = const_cast<handle_type&>(_source).native_handle();
|
||||
if (source_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
source = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::winapi::DuplicateHandle(
|
||||
proc, source_in, proc, &source, 0,
|
||||
static_cast<::boost::winapi::BOOL_>(true),
|
||||
::boost::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
return ::boost::asio::windows::stream_handle(ios.get_executor(), source);
|
||||
}
|
||||
handle_type sink (::boost::asio::io_context& ios) const &
|
||||
{
|
||||
auto proc = ::boost::winapi::GetCurrentProcess();
|
||||
|
||||
::boost::winapi::HANDLE_ sink;
|
||||
auto sink_in = const_cast<handle_type&>(_sink).native_handle();
|
||||
if (sink_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::winapi::DuplicateHandle(
|
||||
proc, sink_in, proc, &sink, 0,
|
||||
static_cast<::boost::winapi::BOOL_>(true),
|
||||
::boost::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
return ::boost::asio::windows::stream_handle(ios.get_executor(), sink);
|
||||
}
|
||||
};
|
||||
|
||||
async_pipe::async_pipe(const async_pipe& p) :
|
||||
_source(const_cast<handle_type&>(p._source).get_executor()),
|
||||
_sink (const_cast<handle_type&>(p._sink).get_executor())
|
||||
{
|
||||
|
||||
auto proc = ::boost::winapi::GetCurrentProcess();
|
||||
|
||||
::boost::winapi::HANDLE_ source;
|
||||
::boost::winapi::HANDLE_ sink;
|
||||
|
||||
//cannot get the handle from a const object.
|
||||
auto source_in = const_cast<handle_type&>(p._source).native_handle();
|
||||
auto sink_in = const_cast<handle_type&>(p._sink).native_handle();
|
||||
|
||||
if (source_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
source = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::winapi::DuplicateHandle(
|
||||
proc, source_in, proc, &source, 0,
|
||||
static_cast<::boost::winapi::BOOL_>(true),
|
||||
::boost::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
if (sink_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::winapi::DuplicateHandle(
|
||||
proc, sink_in, proc, &sink, 0,
|
||||
static_cast<::boost::winapi::BOOL_>(true),
|
||||
::boost::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
if (source != ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
_source.assign(source);
|
||||
if (sink != ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
_sink. assign(sink);
|
||||
}
|
||||
|
||||
async_pipe::async_pipe(boost::asio::io_context & ios_source,
|
||||
boost::asio::io_context & ios_sink,
|
||||
const std::string & name, bool private_) : _source(ios_source), _sink(ios_sink)
|
||||
{
|
||||
static constexpr int FILE_FLAG_OVERLAPPED_ = 0x40000000; //temporary
|
||||
|
||||
::boost::winapi::HANDLE_ source = ::boost::winapi::create_named_pipe(
|
||||
#if defined(BOOST_NO_ANSI_APIS)
|
||||
::boost::process::v1::detail::convert(name).c_str(),
|
||||
#else
|
||||
name.c_str(),
|
||||
#endif
|
||||
::boost::winapi::PIPE_ACCESS_INBOUND_
|
||||
| FILE_FLAG_OVERLAPPED_, //write flag
|
||||
0, private_ ? 1 : ::boost::winapi::PIPE_UNLIMITED_INSTANCES_, 8192, 8192, 0, nullptr);
|
||||
|
||||
if (source == boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::process::v1::detail::throw_last_error("create_named_pipe(" + name + ") failed");
|
||||
|
||||
_source.assign(source);
|
||||
|
||||
::boost::winapi::HANDLE_ sink = boost::winapi::create_file(
|
||||
#if defined(BOOST_NO_ANSI_APIS)
|
||||
::boost::process::v1::detail::convert(name).c_str(),
|
||||
#else
|
||||
name.c_str(),
|
||||
#endif
|
||||
::boost::winapi::GENERIC_WRITE_, 0, nullptr,
|
||||
::boost::winapi::OPEN_EXISTING_,
|
||||
FILE_FLAG_OVERLAPPED_, //to allow read
|
||||
nullptr);
|
||||
|
||||
if (sink == ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::process::v1::detail::throw_last_error("create_file() failed");
|
||||
|
||||
_sink.assign(sink);
|
||||
}
|
||||
|
||||
template<class CharT, class Traits>
|
||||
async_pipe& async_pipe::operator=(const basic_pipe<CharT, Traits> & p)
|
||||
{
|
||||
auto proc = ::boost::winapi::GetCurrentProcess();
|
||||
|
||||
::boost::winapi::HANDLE_ source;
|
||||
::boost::winapi::HANDLE_ sink;
|
||||
|
||||
//cannot get the handle from a const object.
|
||||
auto source_in = p.native_source();
|
||||
auto sink_in = p.native_sink();
|
||||
|
||||
if (source_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
source = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::winapi::DuplicateHandle(
|
||||
proc, source_in.native_handle(), proc, &source, 0,
|
||||
static_cast<::boost::winapi::BOOL_>(true),
|
||||
::boost::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
if (sink_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::winapi::DuplicateHandle(
|
||||
proc, sink_in.native_handle(), proc, &sink, 0,
|
||||
static_cast<::boost::winapi::BOOL_>(true),
|
||||
::boost::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
//so we also assign the io_context
|
||||
if (source != ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
_source.assign(source);
|
||||
|
||||
if (sink != ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
_sink.assign(sink);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
async_pipe& async_pipe::operator=(const async_pipe & p)
|
||||
{
|
||||
auto proc = ::boost::winapi::GetCurrentProcess();
|
||||
|
||||
::boost::winapi::HANDLE_ source;
|
||||
::boost::winapi::HANDLE_ sink;
|
||||
|
||||
//cannot get the handle from a const object.
|
||||
auto &source_in = const_cast<::boost::asio::windows::stream_handle &>(p._source);
|
||||
auto &sink_in = const_cast<::boost::asio::windows::stream_handle &>(p._sink);
|
||||
|
||||
source_in.get_executor();
|
||||
|
||||
if (source_in.native_handle() == ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
source = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::winapi::DuplicateHandle(
|
||||
proc, source_in.native_handle(), proc, &source, 0,
|
||||
static_cast<::boost::winapi::BOOL_>(true),
|
||||
::boost::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
if (sink_in.native_handle() == ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::winapi::DuplicateHandle(
|
||||
proc, sink_in.native_handle(), proc, &sink, 0,
|
||||
static_cast<::boost::winapi::BOOL_>(true),
|
||||
::boost::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
//so we also assign the io_context
|
||||
if (source != ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
_source = ::boost::asio::windows::stream_handle(source_in.get_executor(), source);
|
||||
else
|
||||
_source = ::boost::asio::windows::stream_handle(source_in.get_executor());
|
||||
|
||||
if (sink != ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
_sink = ::boost::asio::windows::stream_handle(source_in.get_executor(), sink);
|
||||
else
|
||||
_sink = ::boost::asio::windows::stream_handle(source_in.get_executor());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
async_pipe& async_pipe::operator=(async_pipe && rhs)
|
||||
{
|
||||
_source = std::move(rhs._source);
|
||||
_sink = std::move(rhs._sink);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class CharT, class Traits>
|
||||
async_pipe::operator basic_pipe<CharT, Traits>() const
|
||||
{
|
||||
auto proc = ::boost::winapi::GetCurrentProcess();
|
||||
|
||||
::boost::winapi::HANDLE_ source;
|
||||
::boost::winapi::HANDLE_ sink;
|
||||
|
||||
//cannot get the handle from a const object.
|
||||
auto source_in = const_cast<::boost::asio::windows::stream_handle &>(_source).native_handle();
|
||||
auto sink_in = const_cast<::boost::asio::windows::stream_handle &>(_sink).native_handle();
|
||||
|
||||
if (source_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
source = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::winapi::DuplicateHandle(
|
||||
proc, source_in, proc, &source, 0,
|
||||
static_cast<::boost::winapi::BOOL_>(true),
|
||||
::boost::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
if (sink_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::winapi::DuplicateHandle(
|
||||
proc, sink_in, proc, &sink, 0,
|
||||
static_cast<::boost::winapi::BOOL_>(true),
|
||||
::boost::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
return basic_pipe<CharT, Traits>{source, sink};
|
||||
}
|
||||
|
||||
inline bool operator==(const async_pipe & lhs, const async_pipe & rhs)
|
||||
{
|
||||
return compare_handles(lhs.native_source(), rhs.native_source()) &&
|
||||
compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
inline bool operator!=(const async_pipe & lhs, const async_pipe & rhs)
|
||||
{
|
||||
return !compare_handles(lhs.native_source(), rhs.native_source()) ||
|
||||
!compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
template<class Char, class Traits>
|
||||
inline bool operator==(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs)
|
||||
{
|
||||
return compare_handles(lhs.native_source(), rhs.native_source()) &&
|
||||
compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
template<class Char, class Traits>
|
||||
inline bool operator!=(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs)
|
||||
{
|
||||
return !compare_handles(lhs.native_source(), rhs.native_source()) ||
|
||||
!compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
template<class Char, class Traits>
|
||||
inline bool operator==(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs)
|
||||
{
|
||||
return compare_handles(lhs.native_source(), rhs.native_source()) &&
|
||||
compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
template<class Char, class Traits>
|
||||
inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs)
|
||||
{
|
||||
return !compare_handles(lhs.native_source(), rhs.native_source()) ||
|
||||
!compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif /* INCLUDE_BOOST_PIPE_DETAIL_WINDOWS_ASYNC_PIPE_HPP_ */
|
||||
207
include/boost/process/v1/detail/windows/basic_cmd.hpp
Normal file
207
include/boost/process/v1/detail/windows/basic_cmd.hpp
Normal file
@@ -0,0 +1,207 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_BASIC_CMD_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_BASIC_CMD_HPP_
|
||||
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/process/v1/shell.hpp>
|
||||
#include <boost/process/v1/detail/windows/handler.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iterator>
|
||||
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace process
|
||||
{
|
||||
BOOST_PROCESS_V1_INLINE namespace v1
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace windows
|
||||
{
|
||||
|
||||
inline std::string build_args(const std::string & exe, std::vector<std::string> && data)
|
||||
{
|
||||
std::string st = exe;
|
||||
|
||||
//put in quotes if it has spaces or double quotes
|
||||
if(!exe.empty())
|
||||
{
|
||||
auto it = st.find_first_of(" \"");
|
||||
|
||||
if(it != st.npos)//contains spaces.
|
||||
{
|
||||
// double existing quotes
|
||||
boost::replace_all(st, "\"", "\"\"");
|
||||
|
||||
// surround with quotes
|
||||
st.insert(st.begin(), '"');
|
||||
st += '"';
|
||||
}
|
||||
}
|
||||
|
||||
for (auto & arg : data)
|
||||
{
|
||||
if(!arg.empty())
|
||||
{
|
||||
auto it = arg.find_first_of(" \"");//contains space or double quotes?
|
||||
if(it != arg.npos)//yes
|
||||
{
|
||||
// double existing quotes
|
||||
boost::replace_all(arg, "\"", "\"\"");
|
||||
|
||||
// surround with quotes
|
||||
arg.insert(arg.begin(), '"');
|
||||
arg += '"';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
arg = "\"\"";
|
||||
}
|
||||
|
||||
if (!st.empty())//first one does not need a preceding space
|
||||
st += ' ';
|
||||
|
||||
st += arg;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
inline std::wstring build_args(const std::wstring & exe, std::vector<std::wstring> && data)
|
||||
{
|
||||
std::wstring st = exe;
|
||||
|
||||
//put in quotes if it has spaces or double quotes
|
||||
if(!exe.empty())
|
||||
{
|
||||
auto it = st.find_first_of(L" \"");
|
||||
|
||||
if(it != st.npos)//contains spaces or double quotes.
|
||||
{
|
||||
// double existing quotes
|
||||
boost::replace_all(st, L"\"", L"\"\"");
|
||||
|
||||
// surround with quotes
|
||||
st.insert(st.begin(), L'"');
|
||||
st += L'"';
|
||||
}
|
||||
}
|
||||
|
||||
for(auto & arg : data)
|
||||
{
|
||||
if(!arg.empty())
|
||||
{
|
||||
auto it = arg.find_first_of(L" \"");//contains space or double quotes?
|
||||
if(it != arg.npos)//yes
|
||||
{
|
||||
// double existing quotes
|
||||
boost::replace_all(arg, L"\"", L"\"\"");
|
||||
|
||||
// surround with quotes
|
||||
arg.insert(arg.begin(), L'"');
|
||||
arg += '"';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
arg = L"\"\"";
|
||||
}
|
||||
|
||||
if (!st.empty())//first one does not need a preceding space
|
||||
st += L' ';
|
||||
|
||||
st += arg;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
template<typename Char>
|
||||
struct exe_cmd_init : handler_base_ext
|
||||
{
|
||||
using value_type = Char;
|
||||
using string_type = std::basic_string<value_type>;
|
||||
|
||||
static const char* c_arg(char) { return "/c";}
|
||||
static const wchar_t* c_arg(wchar_t) { return L"/c";}
|
||||
|
||||
exe_cmd_init(const string_type & exe, bool cmd_only = false)
|
||||
: exe(exe), args({}), cmd_only(cmd_only) {};
|
||||
exe_cmd_init(string_type && exe, bool cmd_only = false)
|
||||
: exe(std::move(exe)), args({}), cmd_only(cmd_only) {};
|
||||
|
||||
exe_cmd_init(string_type && exe, std::vector<string_type> && args)
|
||||
: exe(std::move(exe)), args(build_args(this->exe, std::move(args))), cmd_only(false) {};
|
||||
template <class Executor>
|
||||
void on_setup(Executor& exec) const
|
||||
{
|
||||
|
||||
if (cmd_only && args.empty())
|
||||
exec.cmd_line = exe.c_str();
|
||||
else
|
||||
{
|
||||
exec.exe = exe.c_str();
|
||||
exec.cmd_line = args.c_str();
|
||||
}
|
||||
}
|
||||
static exe_cmd_init<Char> exe_args(string_type && exe, std::vector<string_type> && args)
|
||||
{
|
||||
return exe_cmd_init<Char>(std::move(exe), std::move(args));
|
||||
}
|
||||
static exe_cmd_init<Char> cmd(string_type&& cmd)
|
||||
{
|
||||
return exe_cmd_init<Char>(std::move(cmd), true);
|
||||
}
|
||||
static exe_cmd_init<Char> exe_args_shell(string_type && exe, std::vector<string_type> && args)
|
||||
{
|
||||
std::vector<string_type> args_ = {c_arg(Char())};
|
||||
if (!exe.empty())
|
||||
args_.emplace_back(std::move(exe));
|
||||
args_.insert(args_.end(), std::make_move_iterator(args.begin()), std::make_move_iterator(args.end()));
|
||||
string_type sh = get_shell(Char());
|
||||
|
||||
return exe_cmd_init<Char>(std::move(sh), std::move(args_));
|
||||
}
|
||||
|
||||
#ifdef BOOST_PROCESS_USE_STD_FS
|
||||
static std:: string get_shell(char) {return shell(). string(); }
|
||||
static std::wstring get_shell(wchar_t) {return shell().wstring(); }
|
||||
#else
|
||||
static std:: string get_shell(char) {return shell(). string(codecvt()); }
|
||||
static std::wstring get_shell(wchar_t) {return shell().wstring(codecvt());}
|
||||
#endif
|
||||
|
||||
static exe_cmd_init<Char> cmd_shell(string_type&& cmd)
|
||||
{
|
||||
std::vector<string_type> args = {c_arg(Char()), std::move(cmd)};
|
||||
string_type sh = get_shell(Char());
|
||||
|
||||
return exe_cmd_init<Char>(
|
||||
std::move(sh),
|
||||
std::move(args));
|
||||
}
|
||||
private:
|
||||
string_type exe;
|
||||
string_type args;
|
||||
bool cmd_only;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ARGS_HPP_ */
|
||||
230
include/boost/process/v1/detail/windows/basic_pipe.hpp
Normal file
230
include/boost/process/v1/detail/windows/basic_pipe.hpp
Normal file
@@ -0,0 +1,230 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_PIPE_HPP
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_PIPE_HPP
|
||||
|
||||
#include <boost/winapi/basic_types.hpp>
|
||||
#include <boost/winapi/error_codes.hpp>
|
||||
#include <boost/winapi/pipes.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/winapi/file_management.hpp>
|
||||
#include <boost/winapi/get_last_error.hpp>
|
||||
#include <boost/winapi/access_rights.hpp>
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/process/v1/detail/windows/compare_handles.hpp>
|
||||
#include <system_error>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
class basic_pipe
|
||||
{
|
||||
::boost::winapi::HANDLE_ _source = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
::boost::winapi::HANDLE_ _sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
public:
|
||||
typedef CharT char_type ;
|
||||
typedef Traits traits_type;
|
||||
typedef typename Traits::int_type int_type ;
|
||||
typedef typename Traits::pos_type pos_type ;
|
||||
typedef typename Traits::off_type off_type ;
|
||||
typedef ::boost::winapi::HANDLE_ native_handle_type;
|
||||
|
||||
explicit basic_pipe(::boost::winapi::HANDLE_ source, ::boost::winapi::HANDLE_ sink)
|
||||
: _source(source), _sink(sink) {}
|
||||
inline explicit basic_pipe(const std::string & name);
|
||||
inline basic_pipe(const basic_pipe& p);
|
||||
basic_pipe(basic_pipe&& lhs) : _source(lhs._source), _sink(lhs._sink)
|
||||
{
|
||||
lhs._source = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
lhs._sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
}
|
||||
inline basic_pipe& operator=(const basic_pipe& p);
|
||||
inline basic_pipe& operator=(basic_pipe&& lhs);
|
||||
~basic_pipe()
|
||||
{
|
||||
if (_sink != ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::winapi::CloseHandle(_sink);
|
||||
if (_source != ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::winapi::CloseHandle(_source);
|
||||
}
|
||||
native_handle_type native_source() const {return _source;}
|
||||
native_handle_type native_sink () const {return _sink;}
|
||||
|
||||
void assign_source(native_handle_type h) { _source = h;}
|
||||
void assign_sink (native_handle_type h) { _sink = h;}
|
||||
|
||||
basic_pipe()
|
||||
{
|
||||
if (!::boost::winapi::CreatePipe(&_source, &_sink, nullptr, 0))
|
||||
throw_last_error("CreatePipe() failed");
|
||||
|
||||
}
|
||||
|
||||
int_type write(const char_type * data, int_type count)
|
||||
{
|
||||
::boost::winapi::DWORD_ write_len;
|
||||
if (!::boost::winapi::WriteFile(
|
||||
_sink, data, count * sizeof(char_type), &write_len, nullptr
|
||||
))
|
||||
{
|
||||
auto ec = ::boost::process::v1::detail::get_last_error();
|
||||
if ((ec.value() == ::boost::winapi::ERROR_BROKEN_PIPE_) ||
|
||||
(ec.value() == ::boost::winapi::ERROR_NO_DATA_))
|
||||
return 0;
|
||||
else
|
||||
throw process_error(ec, "WriteFile failed");
|
||||
}
|
||||
return static_cast<int_type>(write_len);
|
||||
}
|
||||
int_type read(char_type * data, int_type count)
|
||||
{
|
||||
::boost::winapi::DWORD_ read_len;
|
||||
if (!::boost::winapi::ReadFile(
|
||||
_source, data, count * sizeof(char_type), &read_len, nullptr
|
||||
))
|
||||
{
|
||||
auto ec = ::boost::process::v1::detail::get_last_error();
|
||||
if ((ec.value() == ::boost::winapi::ERROR_BROKEN_PIPE_) ||
|
||||
(ec.value() == ::boost::winapi::ERROR_NO_DATA_))
|
||||
return 0;
|
||||
else
|
||||
throw process_error(ec, "ReadFile failed");
|
||||
}
|
||||
return static_cast<int_type>(read_len);
|
||||
}
|
||||
|
||||
bool is_open() const
|
||||
{
|
||||
return (_source != ::boost::winapi::INVALID_HANDLE_VALUE_) ||
|
||||
(_sink != ::boost::winapi::INVALID_HANDLE_VALUE_);
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
::boost::winapi::CloseHandle(_source);
|
||||
::boost::winapi::CloseHandle(_sink);
|
||||
_source = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
_sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
}
|
||||
};
|
||||
|
||||
template<class Char, class Traits>
|
||||
basic_pipe<Char, Traits>::basic_pipe(const basic_pipe & p)
|
||||
{
|
||||
auto proc = ::boost::winapi::GetCurrentProcess();
|
||||
|
||||
if (p._source == ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
_source = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::winapi::DuplicateHandle(
|
||||
proc, p._source, proc, &_source, 0,
|
||||
static_cast<::boost::winapi::BOOL_>(true),
|
||||
::boost::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
if (p._sink == ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
_sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::winapi::DuplicateHandle(
|
||||
proc, p._sink, proc, &_sink, 0,
|
||||
static_cast<::boost::winapi::BOOL_>(true),
|
||||
::boost::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
}
|
||||
|
||||
template<class Char, class Traits>
|
||||
basic_pipe<Char, Traits>::basic_pipe(const std::string & name)
|
||||
{
|
||||
static constexpr int OPEN_EXISTING_ = 3; //temporary.
|
||||
static constexpr int FILE_FLAG_OVERLAPPED_ = 0x40000000; //temporary
|
||||
//static constexpr int FILE_ATTRIBUTE_NORMAL_ = 0x00000080; //temporary
|
||||
|
||||
#if BOOST_NO_ANSI_APIS
|
||||
std::wstring name_ = boost::process::v1::detail::convert(name);
|
||||
#else
|
||||
auto &name_ = name;
|
||||
#endif
|
||||
::boost::winapi::HANDLE_ source = ::boost::winapi::create_named_pipe(
|
||||
name_.c_str(),
|
||||
::boost::winapi::PIPE_ACCESS_INBOUND_
|
||||
| FILE_FLAG_OVERLAPPED_, //write flag
|
||||
0, ::boost::winapi::PIPE_UNLIMITED_INSTANCES_, 8192, 8192, 0, nullptr);
|
||||
|
||||
if (source == boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::process::v1::detail::throw_last_error("create_named_pipe() failed");
|
||||
|
||||
::boost::winapi::HANDLE_ sink = boost::winapi::create_file(
|
||||
name_.c_str(),
|
||||
::boost::winapi::GENERIC_WRITE_, 0, nullptr,
|
||||
OPEN_EXISTING_,
|
||||
FILE_FLAG_OVERLAPPED_, //to allow read
|
||||
nullptr);
|
||||
|
||||
if (sink == ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::process::v1::detail::throw_last_error("create_file() failed");
|
||||
|
||||
_source = source;
|
||||
_sink = sink;
|
||||
}
|
||||
|
||||
template<class Char, class Traits>
|
||||
basic_pipe<Char, Traits>& basic_pipe<Char, Traits>::operator=(const basic_pipe & p)
|
||||
{
|
||||
auto proc = ::boost::winapi::GetCurrentProcess();
|
||||
|
||||
if (p._source == ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
_source = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::winapi::DuplicateHandle(
|
||||
proc, p._source, proc, &_source, 0,
|
||||
static_cast<::boost::winapi::BOOL_>(true),
|
||||
::boost::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
if (p._sink == ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
_sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::winapi::DuplicateHandle(
|
||||
proc, p._sink, proc, &_sink, 0,
|
||||
static_cast<::boost::winapi::BOOL_>(true),
|
||||
::boost::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class Char, class Traits>
|
||||
basic_pipe<Char, Traits>& basic_pipe<Char, Traits>::operator=(basic_pipe && lhs)
|
||||
{
|
||||
if (_source != ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::winapi::CloseHandle(_source);
|
||||
|
||||
if (_sink != ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::winapi::CloseHandle(_sink);
|
||||
|
||||
_source = lhs._source;
|
||||
_sink = lhs._sink;
|
||||
lhs._source = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
lhs._sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class Char, class Traits>
|
||||
inline bool operator==(const basic_pipe<Char, Traits> & lhs, const basic_pipe<Char, Traits> & rhs)
|
||||
{
|
||||
return compare_handles(lhs.native_source(), rhs.native_source()) &&
|
||||
compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
template<class Char, class Traits>
|
||||
inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const basic_pipe<Char, Traits> & rhs)
|
||||
{
|
||||
return !compare_handles(lhs.native_source(), rhs.native_source()) ||
|
||||
!compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
99
include/boost/process/v1/detail/windows/child_handle.hpp
Normal file
99
include/boost/process/v1/detail/windows/child_handle.hpp
Normal file
@@ -0,0 +1,99 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// 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_WINDOWS_CHILD_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_CHILD_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/move/move.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/winapi/jobs.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
typedef ::boost::winapi::DWORD_ pid_t;
|
||||
|
||||
struct child_handle
|
||||
{
|
||||
::boost::winapi::PROCESS_INFORMATION_ proc_info{nullptr, nullptr, 0,0};
|
||||
|
||||
explicit child_handle(const ::boost::winapi::PROCESS_INFORMATION_ &pi) :
|
||||
proc_info(pi)
|
||||
{}
|
||||
|
||||
explicit child_handle(pid_t pid) :
|
||||
proc_info{nullptr, nullptr, 0,0}
|
||||
{
|
||||
auto h = ::boost::winapi::OpenProcess(
|
||||
::boost::winapi::PROCESS_ALL_ACCESS_,
|
||||
static_cast<::boost::winapi::BOOL_>(0),
|
||||
pid);
|
||||
|
||||
if (h == nullptr)
|
||||
throw_last_error("OpenProcess() failed");
|
||||
proc_info.hProcess = h;
|
||||
proc_info.dwProcessId = pid;
|
||||
}
|
||||
|
||||
child_handle() = default;
|
||||
~child_handle()
|
||||
{
|
||||
::boost::winapi::CloseHandle(proc_info.hProcess);
|
||||
::boost::winapi::CloseHandle(proc_info.hThread);
|
||||
}
|
||||
child_handle(const child_handle & c) = delete;
|
||||
child_handle(child_handle && c) : proc_info(c.proc_info)
|
||||
{
|
||||
c.proc_info.hProcess = ::boost::winapi::invalid_handle_value;
|
||||
c.proc_info.hThread = ::boost::winapi::invalid_handle_value;
|
||||
}
|
||||
child_handle &operator=(const child_handle & c) = delete;
|
||||
child_handle &operator=(child_handle && c)
|
||||
{
|
||||
::boost::winapi::CloseHandle(proc_info.hProcess);
|
||||
::boost::winapi::CloseHandle(proc_info.hThread);
|
||||
proc_info = c.proc_info;
|
||||
c.proc_info.hProcess = ::boost::winapi::invalid_handle_value;
|
||||
c.proc_info.hThread = ::boost::winapi::invalid_handle_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
pid_t id() const
|
||||
{
|
||||
return static_cast<pid_t>(proc_info.dwProcessId);
|
||||
}
|
||||
|
||||
typedef ::boost::winapi::HANDLE_ process_handle_t;
|
||||
process_handle_t process_handle() const { return proc_info.hProcess; }
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
return (proc_info.hProcess != nullptr) &&
|
||||
(proc_info.hProcess != ::boost::winapi::INVALID_HANDLE_VALUE_);
|
||||
}
|
||||
bool in_group() const
|
||||
{
|
||||
::boost::winapi::BOOL_ value;
|
||||
if (!::boost::winapi::IsProcessInJob(proc_info.hProcess, nullptr, &value))
|
||||
throw_last_error("IsProcessInJob Failed");
|
||||
return value!=0;
|
||||
}
|
||||
bool in_group(std::error_code &ec) const noexcept
|
||||
{
|
||||
::boost::winapi::BOOL_ value;
|
||||
if (!::boost::winapi::IsProcessInJob(proc_info.hProcess, nullptr, &value))
|
||||
ec = get_last_error();
|
||||
return value!=0;
|
||||
}
|
||||
};
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
32
include/boost/process/v1/detail/windows/close_in.hpp
Normal file
32
include/boost/process/v1/detail/windows/close_in.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// 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_WINDOWS_INITIALIZERS_CLOSE_IN_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_CLOSE_IN_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
struct close_in : public ::boost::process::v1::detail::handler_base
|
||||
{
|
||||
template <class WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
e.startup_info.hStdInput = boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
e.startup_info.dwFlags |= boost::winapi::STARTF_USESTDHANDLES_;
|
||||
}
|
||||
};
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
54
include/boost/process/v1/detail/windows/close_out.hpp
Normal file
54
include/boost/process/v1/detail/windows/close_out.hpp
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// 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_WINDOWS_INITIALIZERS_CLOSE_OUT_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_CLOSE_OUT_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
template<int p1, int p2>
|
||||
struct close_out : public ::boost::process::v1::detail::handler_base
|
||||
{
|
||||
template <class WindowsExecutor>
|
||||
inline void on_setup(WindowsExecutor &e) const;
|
||||
};
|
||||
|
||||
template<>
|
||||
template<typename WindowsExecutor>
|
||||
void close_out<1,-1>::on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
e.startup_info.hStdOutput = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename WindowsExecutor>
|
||||
void close_out<2,-1>::on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
e.startup_info.hStdError = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename WindowsExecutor>
|
||||
void close_out<1,2>::on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
e.startup_info.hStdOutput = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
e.startup_info.hStdError = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
51
include/boost/process/v1/detail/windows/cmd.hpp
Normal file
51
include/boost/process/v1/detail/windows/cmd.hpp
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_CMD_HPP_
|
||||
#define BOOST_PROCESS_WINDOWS_CMD_HPP_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace process
|
||||
{
|
||||
BOOST_PROCESS_V1_INLINE namespace v1
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace windows
|
||||
{
|
||||
|
||||
template<typename CharType>
|
||||
struct cmd_setter_ : ::boost::process::v1::detail::handler_base
|
||||
{
|
||||
typedef CharType value_type;
|
||||
typedef std::basic_string<value_type> string_type;
|
||||
|
||||
cmd_setter_(string_type && cmd_line) : _cmd_line(std::move(cmd_line)) {}
|
||||
cmd_setter_(const string_type & cmd_line) : _cmd_line(cmd_line) {}
|
||||
template <class Executor>
|
||||
void on_setup(Executor& exec)
|
||||
{
|
||||
exec.cmd_line = _cmd_line.c_str();
|
||||
}
|
||||
const string_type & str() const {return _cmd_line;}
|
||||
|
||||
private:
|
||||
string_type _cmd_line;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ARGS_HPP_ */
|
||||
41
include/boost/process/v1/detail/windows/compare_handles.hpp
Normal file
41
include/boost/process/v1/detail/windows/compare_handles.hpp
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_COMPARE_HANDLES_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_COMPARE_HANDLES_HPP_
|
||||
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/winapi/file_management.hpp>
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
inline bool compare_handles(boost::winapi::HANDLE_ lhs, boost::winapi::HANDLE_ rhs)
|
||||
{
|
||||
if ( (lhs == ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
|| (rhs == ::boost::winapi::INVALID_HANDLE_VALUE_))
|
||||
return false;
|
||||
|
||||
if (lhs == rhs)
|
||||
return true;
|
||||
|
||||
::boost::winapi::BY_HANDLE_FILE_INFORMATION_ lhs_info{0,{0,0},{0,0},{0,0},0,0,0,0,0,0};
|
||||
::boost::winapi::BY_HANDLE_FILE_INFORMATION_ rhs_info{0,{0,0},{0,0},{0,0},0,0,0,0,0,0};
|
||||
|
||||
if (!::boost::winapi::GetFileInformationByHandle(lhs, &lhs_info))
|
||||
::boost::process::v1::detail::throw_last_error("GetFileInformationByHandle");
|
||||
|
||||
if (!::boost::winapi::GetFileInformationByHandle(rhs, &rhs_info))
|
||||
::boost::process::v1::detail::throw_last_error("GetFileInformationByHandle");
|
||||
|
||||
return (lhs_info.nFileIndexHigh == rhs_info.nFileIndexHigh)
|
||||
&& (lhs_info.nFileIndexLow == rhs_info.nFileIndexLow);
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_COMPARE_HANDLES_HPP_ */
|
||||
54
include/boost/process/v1/detail/windows/env_init.hpp
Normal file
54
include/boost/process/v1/detail/windows/env_init.hpp
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_ENV_INIT_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_ENV_INIT_HPP_
|
||||
|
||||
#include <boost/winapi/error_codes.hpp>
|
||||
#include <boost/winapi/process.hpp>
|
||||
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
#include <boost/process/v1/environment.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
template<typename Char>
|
||||
struct env_init : public ::boost::process::v1::detail::handler_base
|
||||
{
|
||||
boost::process::v1::basic_environment<Char> env;
|
||||
|
||||
env_init(boost::process::v1::basic_environment<Char> && env) : env(std::move(env)) {};
|
||||
env_init(const boost::process::v1::basic_environment<Char> & env) : env(env) {};
|
||||
|
||||
constexpr static ::boost::winapi::DWORD_ creation_flag(char) {return 0u;}
|
||||
constexpr static ::boost::winapi::DWORD_ creation_flag(wchar_t)
|
||||
{
|
||||
return ::boost::winapi::CREATE_UNICODE_ENVIRONMENT_;
|
||||
}
|
||||
|
||||
template <class WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &exec) const
|
||||
{
|
||||
auto e = env.native_handle();
|
||||
if (*e == null_char<char>())
|
||||
{
|
||||
exec.set_error(std::error_code(::boost::winapi::ERROR_BAD_ENVIRONMENT_, std::system_category()),
|
||||
"Empty Environment");
|
||||
}
|
||||
|
||||
exec.env = e;
|
||||
exec.creation_flags |= creation_flag(Char());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}}}}}
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_INIT_HPP_ */
|
||||
356
include/boost/process/v1/detail/windows/environment.hpp
Normal file
356
include/boost/process/v1/detail/windows/environment.hpp
Normal file
@@ -0,0 +1,356 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <boost/winapi/error_codes.hpp>
|
||||
#include <boost/winapi/environment.hpp>
|
||||
#include <boost/winapi/get_current_process.hpp>
|
||||
#include <boost/winapi/get_current_process_id.hpp>
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <algorithm>
|
||||
#include <boost/process/v1/locale.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
template<typename Char>
|
||||
class native_environment_impl
|
||||
{
|
||||
static void _deleter(Char* p) {boost::winapi::free_environment_strings(p);};
|
||||
std::unique_ptr<Char[], void(*)(Char*)> _buf{boost::winapi::get_environment_strings<Char>(), &native_environment_impl::_deleter};
|
||||
static inline std::vector<Char*> _load_var(Char* p);
|
||||
std::vector<Char*> _env_arr{_load_var(_buf.get())};
|
||||
public:
|
||||
using char_type = Char;
|
||||
using pointer_type = const char_type*;
|
||||
using string_type = std::basic_string<char_type>;
|
||||
using native_handle_type = pointer_type;
|
||||
void reload()
|
||||
{
|
||||
_buf.reset(boost::winapi::get_environment_strings<Char>());
|
||||
_env_arr = _load_var(_buf.get());
|
||||
_env_impl = &*_env_arr.begin();
|
||||
}
|
||||
|
||||
string_type get(const pointer_type id);
|
||||
void set(const pointer_type id, const pointer_type value);
|
||||
void reset(const pointer_type id);
|
||||
|
||||
string_type get(const string_type & id) {return get(id.c_str());}
|
||||
void set(const string_type & id, const string_type & value) {set(id.c_str(), value.c_str()); }
|
||||
void reset(const string_type & id) {reset(id.c_str());}
|
||||
|
||||
native_environment_impl() = default;
|
||||
native_environment_impl(const native_environment_impl& ) = delete;
|
||||
native_environment_impl(native_environment_impl && ) = default;
|
||||
native_environment_impl & operator=(const native_environment_impl& ) = delete;
|
||||
native_environment_impl & operator=(native_environment_impl && ) = default;
|
||||
Char ** _env_impl = &*_env_arr.begin();
|
||||
|
||||
native_handle_type native_handle() const {return _buf.get();}
|
||||
};
|
||||
|
||||
template<typename Char>
|
||||
inline auto native_environment_impl<Char>::get(const pointer_type id) -> string_type
|
||||
{
|
||||
Char buf[4096];
|
||||
auto size = boost::winapi::get_environment_variable(id, buf, sizeof(buf));
|
||||
if (size == 0) //failed
|
||||
{
|
||||
auto err = ::boost::winapi::GetLastError();
|
||||
if (err == ::boost::winapi::ERROR_ENVVAR_NOT_FOUND_)//well, then we consider that an empty value
|
||||
return string_type();
|
||||
else
|
||||
throw process_error(std::error_code(err, std::system_category()),
|
||||
"GetEnvironmentVariable() failed");
|
||||
}
|
||||
|
||||
if (size == sizeof(buf)) //the return size gives the size without the null, so I know this went wrong
|
||||
{
|
||||
/* limit defined here https://msdn.microsoft.com/en-us/library/windows/desktop/ms683188(v=vs.85).aspx
|
||||
* but I used 32768, so it is a multiple of 4096.
|
||||
*/
|
||||
constexpr static std::size_t max_size = 32768;
|
||||
//Handle variables longer then buf.
|
||||
std::size_t buf_size = sizeof(buf);
|
||||
while (buf_size <= max_size)
|
||||
{
|
||||
std::vector<Char> buf(buf_size);
|
||||
auto size = boost::winapi::get_environment_variable(id, buf.data(), buf.size());
|
||||
|
||||
if (size == buf_size) //buffer to small
|
||||
buf_size *= 2;
|
||||
else if (size == 0)
|
||||
::boost::process::v1::detail::throw_last_error("GetEnvironmentVariable() failed");
|
||||
else
|
||||
return std::basic_string<Char>(
|
||||
buf.data(), buf.data()+ size);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return std::basic_string<Char>(buf, buf+size);
|
||||
}
|
||||
|
||||
template<typename Char>
|
||||
inline void native_environment_impl<Char>::set(const pointer_type id, const pointer_type value)
|
||||
{
|
||||
boost::winapi::set_environment_variable(id, value);
|
||||
}
|
||||
|
||||
template<typename Char>
|
||||
inline void native_environment_impl<Char>::reset(const pointer_type id)
|
||||
{
|
||||
boost::winapi::set_environment_variable(id, nullptr);
|
||||
}
|
||||
|
||||
template<typename Char>
|
||||
std::vector<Char*> native_environment_impl<Char>::_load_var(Char* p)
|
||||
{
|
||||
std::vector<Char*> ret;
|
||||
if (*p != null_char<Char>())
|
||||
{
|
||||
ret.push_back(p);
|
||||
while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>()))
|
||||
{
|
||||
if (*p==null_char<Char>())
|
||||
{
|
||||
p++;
|
||||
ret.push_back(p);
|
||||
}
|
||||
else
|
||||
p++;
|
||||
}
|
||||
}
|
||||
p++;
|
||||
ret.push_back(nullptr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
template<typename Char>
|
||||
struct basic_environment_impl
|
||||
{
|
||||
std::vector<Char> _data = {null_char<Char>()};
|
||||
static std::vector<Char*> _load_var(Char* p);
|
||||
std::vector<Char*> _env_arr{_load_var(_data.data())};
|
||||
public:
|
||||
using char_type = Char;
|
||||
using pointer_type = const char_type*;
|
||||
using string_type = std::basic_string<char_type>;
|
||||
using native_handle_type = pointer_type;
|
||||
|
||||
std::size_t size() const { return _data.size();}
|
||||
|
||||
void reload()
|
||||
{
|
||||
_env_arr = _load_var(_data.data());
|
||||
_env_impl = _env_arr.data();
|
||||
}
|
||||
|
||||
string_type get(const pointer_type id) {return get(string_type(id));}
|
||||
void set(const pointer_type id, const pointer_type value) {set(string_type(id), value);}
|
||||
void reset(const pointer_type id) {reset(string_type(id));}
|
||||
|
||||
string_type get(const string_type & id);
|
||||
void set(const string_type & id, const string_type & value);
|
||||
void reset(const string_type & id);
|
||||
|
||||
inline basic_environment_impl(const native_environment_impl<Char> & nei);
|
||||
basic_environment_impl() = default;
|
||||
basic_environment_impl(const basic_environment_impl& rhs)
|
||||
: _data(rhs._data)
|
||||
{
|
||||
}
|
||||
basic_environment_impl(basic_environment_impl && rhs)
|
||||
: _data(std::move(rhs._data)),
|
||||
_env_arr(std::move(rhs._env_arr)),
|
||||
_env_impl(_env_arr.data())
|
||||
{
|
||||
}
|
||||
basic_environment_impl &operator=(basic_environment_impl && rhs)
|
||||
{
|
||||
_data = std::move(rhs._data);
|
||||
//reload();
|
||||
_env_arr = std::move(rhs._env_arr);
|
||||
_env_impl = _env_arr.data();
|
||||
|
||||
return *this;
|
||||
}
|
||||
basic_environment_impl & operator=(const basic_environment_impl& rhs)
|
||||
{
|
||||
_data = rhs._data;
|
||||
reload();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename CharR>
|
||||
explicit inline basic_environment_impl(
|
||||
const basic_environment_impl<CharR>& rhs,
|
||||
const ::boost::process::v1::codecvt_type & cv = ::boost::process::v1::codecvt())
|
||||
: _data(::boost::process::v1::detail::convert(rhs._data, cv))
|
||||
{
|
||||
}
|
||||
|
||||
template<typename CharR>
|
||||
basic_environment_impl & operator=(const basic_environment_impl<CharR>& rhs)
|
||||
{
|
||||
_data = ::boost::process::v1::detail::convert(rhs._data);
|
||||
_env_arr = _load_var(&*_data.begin());
|
||||
_env_impl = &*_env_arr.begin();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Char ** _env_impl = &*_env_arr.begin();
|
||||
|
||||
native_handle_type native_handle() const {return &*_data.begin();}
|
||||
};
|
||||
|
||||
|
||||
template<typename Char>
|
||||
basic_environment_impl<Char>::basic_environment_impl(const native_environment_impl<Char> & nei)
|
||||
{
|
||||
auto beg = nei.native_handle();
|
||||
auto p = beg;
|
||||
while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>()))
|
||||
p++;
|
||||
p++; //pointing to the second nullchar
|
||||
p++; //to get the pointer behind the second nullchar, so it's end.
|
||||
|
||||
this->_data.assign(beg, p);
|
||||
this->reload();
|
||||
}
|
||||
|
||||
|
||||
template<typename Char>
|
||||
inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_type
|
||||
{
|
||||
if (id.size() >= _data.size()) //ok, so it is impossible id is in there.
|
||||
return string_type(_data.data());
|
||||
|
||||
if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>()))
|
||||
return string_type(_data.data()); //null-char is handled by the string.
|
||||
|
||||
std::vector<Char> seq = {'\0'}; //using a vector, because strings might cause problems with nullchars
|
||||
seq.insert(seq.end(), id.begin(), id.end());
|
||||
seq.push_back('=');
|
||||
|
||||
auto itr = std::search(_data.begin(), _data.end(), seq.begin(), seq.end());
|
||||
|
||||
if (itr == _data.end()) //not found
|
||||
return "";
|
||||
|
||||
itr += seq.size(); //advance to the value behind the '='; the std::string will take care of finding the null-char.
|
||||
|
||||
return string_type(&*itr);
|
||||
}
|
||||
|
||||
template<typename Char>
|
||||
inline void basic_environment_impl<Char>::set(const string_type &id, const string_type &value)
|
||||
{
|
||||
reset(id);
|
||||
|
||||
std::vector<Char> insertion;
|
||||
|
||||
insertion.insert(insertion.end(), id.begin(), id.end());
|
||||
insertion.push_back('=');
|
||||
insertion.insert(insertion.end(), value.begin(), value.end());
|
||||
insertion.push_back('\0');
|
||||
|
||||
_data.insert(_data.end() -1, insertion.begin(), insertion.end());
|
||||
|
||||
reload();
|
||||
}
|
||||
|
||||
template<typename Char>
|
||||
inline void basic_environment_impl<Char>::reset(const string_type &id)
|
||||
{
|
||||
//ok, we need to check the size of data first
|
||||
if (id.size() >= _data.size()) //ok, so it is impossible id is in there.
|
||||
return;
|
||||
|
||||
//check if it's the first one, spares us the search.
|
||||
if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>()))
|
||||
{
|
||||
auto beg = _data.begin();
|
||||
auto end = beg;
|
||||
|
||||
while (*end != '\0')
|
||||
end++;
|
||||
|
||||
end++; //to point behind the last null-char
|
||||
|
||||
_data.erase(beg, end); //and remove the thingy
|
||||
|
||||
}
|
||||
|
||||
std::vector<Char> seq = {'\0'}; //using a vector, because strings might cause problems with nullchars
|
||||
seq.insert(seq.end(), id.begin(), id.end());
|
||||
seq.push_back('=');
|
||||
|
||||
auto itr = std::search(_data.begin(), _data.end(), seq.begin(), seq.end());
|
||||
|
||||
if (itr == _data.end())
|
||||
return;//nothing to return if it's empty anyway...
|
||||
|
||||
auto end = itr;
|
||||
|
||||
while (*++end != '\0');
|
||||
|
||||
|
||||
_data.erase(itr, end);//and remove it
|
||||
reload();
|
||||
|
||||
|
||||
}
|
||||
|
||||
template<typename Char>
|
||||
std::vector<Char*> basic_environment_impl<Char>::_load_var(Char* p)
|
||||
{
|
||||
std::vector<Char*> ret;
|
||||
if (*p != null_char<Char>())
|
||||
{
|
||||
ret.push_back(p);
|
||||
while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>()))
|
||||
{
|
||||
if (*p==null_char<Char>())
|
||||
{
|
||||
p++;
|
||||
ret.push_back(p);
|
||||
}
|
||||
else
|
||||
p++;
|
||||
}
|
||||
}
|
||||
p++;
|
||||
ret.push_back(nullptr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
template<typename T> constexpr T env_seperator();
|
||||
template<> constexpr char env_seperator() {return ';'; }
|
||||
template<> constexpr wchar_t env_seperator() {return L';'; }
|
||||
|
||||
inline int get_id() {return boost::winapi::GetCurrentProcessId();}
|
||||
inline void* native_handle() {return boost::winapi::GetCurrentProcess(); }
|
||||
|
||||
typedef void* native_handle_t;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_ */
|
||||
259
include/boost/process/v1/detail/windows/executor.hpp
Normal file
259
include/boost/process/v1/detail/windows/executor.hpp
Normal file
@@ -0,0 +1,259 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_EXECUTOR_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_EXECUTOR_HPP
|
||||
|
||||
#include <boost/process/v1/detail/child_decl.hpp>
|
||||
#include <boost/process/v1/detail/windows/is_running.hpp>
|
||||
#include <boost/process/v1/detail/traits.hpp>
|
||||
#include <boost/process/v1/error.hpp>
|
||||
#include <boost/fusion/algorithm/iteration/for_each.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/none.hpp>
|
||||
#include <system_error>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
|
||||
|
||||
namespace detail { namespace windows {
|
||||
|
||||
template<typename CharType> struct startup_info;
|
||||
#if !defined( BOOST_NO_ANSI_APIS )
|
||||
|
||||
template<> struct startup_info<char>
|
||||
{
|
||||
typedef ::boost::winapi::STARTUPINFOA_ type;
|
||||
};
|
||||
#endif
|
||||
|
||||
template<> struct startup_info<wchar_t>
|
||||
{
|
||||
typedef ::boost::winapi::STARTUPINFOW_ type;
|
||||
};
|
||||
|
||||
#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
|
||||
|
||||
template<typename CharType> struct startup_info_ex;
|
||||
|
||||
#if !defined( BOOST_NO_ANSI_APIS )
|
||||
template<> struct startup_info_ex<char>
|
||||
{
|
||||
typedef ::boost::winapi::STARTUPINFOEXA_ type;
|
||||
};
|
||||
#endif
|
||||
|
||||
template<> struct startup_info_ex<wchar_t>
|
||||
{
|
||||
typedef ::boost::winapi::STARTUPINFOEXW_ type;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#if ( BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 )
|
||||
|
||||
template<typename CharT>
|
||||
struct startup_info_impl
|
||||
{
|
||||
::boost::winapi::DWORD_ creation_flags = 0;
|
||||
|
||||
typedef typename startup_info_ex<CharT>::type startup_info_ex_t;
|
||||
typedef typename startup_info<CharT>::type startup_info_t;
|
||||
|
||||
startup_info_ex_t startup_info_ex
|
||||
{startup_info_t {sizeof(startup_info_t), nullptr, nullptr, nullptr,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nullptr,
|
||||
::boost::winapi::invalid_handle_value,
|
||||
::boost::winapi::invalid_handle_value,
|
||||
::boost::winapi::invalid_handle_value},
|
||||
nullptr
|
||||
};
|
||||
startup_info_t & startup_info = startup_info_ex.StartupInfo;
|
||||
|
||||
void set_startup_info_ex()
|
||||
{
|
||||
startup_info.cb = sizeof(startup_info_ex_t);
|
||||
creation_flags |= ::boost::winapi::EXTENDED_STARTUPINFO_PRESENT_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#else
|
||||
|
||||
template<typename CharT>
|
||||
struct startup_info_impl
|
||||
{
|
||||
typedef typename startup_info<CharT>::type startup_info_t;
|
||||
|
||||
::boost::winapi::DWORD_ creation_flags = 0;
|
||||
startup_info_t startup_info
|
||||
{sizeof(startup_info_t), nullptr, nullptr, nullptr,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nullptr,
|
||||
::boost::winapi::invalid_handle_value,
|
||||
::boost::winapi::invalid_handle_value,
|
||||
::boost::winapi::invalid_handle_value};
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
template<typename Char, typename Sequence>
|
||||
class executor : public startup_info_impl<Char>
|
||||
{
|
||||
|
||||
void internal_error_handle(const std::error_code &, const char*, boost::mpl::false_, boost::mpl::true_) {}
|
||||
void internal_error_handle(const std::error_code &, const char*, boost::mpl::true_, boost::mpl::true_) {}
|
||||
|
||||
void internal_error_handle(const std::error_code &ec, const char*, boost::mpl::true_, boost::mpl::false_ )
|
||||
{
|
||||
this->_ec = ec;
|
||||
}
|
||||
void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::false_, boost::mpl::false_ )
|
||||
{
|
||||
throw process_error(ec, msg);
|
||||
}
|
||||
|
||||
struct on_setup_t
|
||||
{
|
||||
executor & exec;
|
||||
on_setup_t(executor & exec) : exec(exec) {};
|
||||
template<typename T>
|
||||
void operator()(T & t) const
|
||||
{
|
||||
if (!exec.error())
|
||||
t.on_setup(exec);
|
||||
}
|
||||
};
|
||||
|
||||
struct on_error_t
|
||||
{
|
||||
executor & exec;
|
||||
const std::error_code & error;
|
||||
on_error_t(executor & exec, const std::error_code & error) : exec(exec), error(error) {};
|
||||
template<typename T>
|
||||
void operator()(T & t) const
|
||||
{
|
||||
t.on_error(exec, error);
|
||||
}
|
||||
};
|
||||
|
||||
struct on_success_t
|
||||
{
|
||||
executor & exec;
|
||||
on_success_t(executor & exec) : exec(exec) {};
|
||||
template<typename T>
|
||||
void operator()(T & t) const
|
||||
{
|
||||
if (!exec.error())
|
||||
t.on_success(exec);
|
||||
}
|
||||
};
|
||||
|
||||
typedef typename ::boost::process::v1::detail::has_error_handler<Sequence>::type has_error_handler;
|
||||
typedef typename ::boost::process::v1::detail::has_ignore_error <Sequence>::type has_ignore_error;
|
||||
|
||||
std::error_code _ec{0, std::system_category()};
|
||||
|
||||
public:
|
||||
|
||||
std::shared_ptr<std::atomic<int>> exit_status = std::make_shared<std::atomic<int>>(still_active);
|
||||
|
||||
executor(Sequence & seq) : seq(seq)
|
||||
{
|
||||
}
|
||||
|
||||
child operator()()
|
||||
{
|
||||
on_setup_t on_setup_fn(*this);
|
||||
boost::fusion::for_each(seq, on_setup_fn);
|
||||
|
||||
if (_ec)
|
||||
{
|
||||
on_error_t on_error_fn(*this, _ec);
|
||||
boost::fusion::for_each(seq, on_error_fn);
|
||||
return child();
|
||||
}
|
||||
|
||||
//NOTE: The non-cast cmd-line string can only be modified by the wchar_t variant which is currently disabled.
|
||||
int err_code = ::boost::winapi::create_process(
|
||||
exe, // LPCSTR_ lpApplicationName,
|
||||
const_cast<Char*>(cmd_line), // LPSTR_ lpCommandLine,
|
||||
proc_attrs, // LPSECURITY_ATTRIBUTES_ lpProcessAttributes,
|
||||
thread_attrs, // LPSECURITY_ATTRIBUTES_ lpThreadAttributes,
|
||||
inherit_handles, // INT_ bInheritHandles,
|
||||
this->creation_flags, // DWORD_ dwCreationFlags,
|
||||
reinterpret_cast<void*>(const_cast<Char*>(env)), // LPVOID_ lpEnvironment,
|
||||
work_dir, // LPCSTR_ lpCurrentDirectory,
|
||||
&this->startup_info, // LPSTARTUPINFOA_ lpStartupInfo,
|
||||
&proc_info); // LPPROCESS_INFORMATION_ lpProcessInformation)
|
||||
|
||||
child c{child_handle(proc_info), exit_status};
|
||||
|
||||
if (err_code != 0)
|
||||
{
|
||||
_ec.clear();
|
||||
on_success_t on_success_fn(*this);
|
||||
boost::fusion::for_each(seq, on_success_fn);
|
||||
}
|
||||
else
|
||||
set_error(::boost::process::v1::detail::get_last_error(),
|
||||
" CreateProcess failed");
|
||||
|
||||
if ( _ec)
|
||||
{
|
||||
on_error_t on_err(*this, _ec);
|
||||
boost::fusion::for_each(seq, on_err);
|
||||
return child();
|
||||
}
|
||||
else
|
||||
return c;
|
||||
|
||||
}
|
||||
|
||||
void set_error(const std::error_code & ec, const char* msg = "Unknown Error.")
|
||||
{
|
||||
internal_error_handle(ec, msg, has_error_handler(), has_ignore_error());
|
||||
}
|
||||
void set_error(const std::error_code & ec, const std::string msg = "Unknown Error.")
|
||||
{
|
||||
internal_error_handle(ec, msg.c_str(), has_error_handler(), has_ignore_error());
|
||||
}
|
||||
|
||||
const std::error_code& error() const {return _ec;}
|
||||
|
||||
::boost::winapi::LPSECURITY_ATTRIBUTES_ proc_attrs = nullptr;
|
||||
::boost::winapi::LPSECURITY_ATTRIBUTES_ thread_attrs = nullptr;
|
||||
::boost::winapi::BOOL_ inherit_handles = false;
|
||||
const Char * work_dir = nullptr;
|
||||
const Char * cmd_line = nullptr;
|
||||
const Char * exe = nullptr;
|
||||
const Char * env = nullptr;
|
||||
|
||||
|
||||
Sequence & seq;
|
||||
::boost::winapi::PROCESS_INFORMATION_ proc_info{nullptr, nullptr, 0,0};
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename Char, typename Tup>
|
||||
executor<Char, Tup> make_executor(Tup & tup)
|
||||
{
|
||||
return executor<Char, Tup>(tup);
|
||||
}
|
||||
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
122
include/boost/process/v1/detail/windows/file_descriptor.hpp
Normal file
122
include/boost/process/v1/detail/windows/file_descriptor.hpp
Normal file
@@ -0,0 +1,122 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_
|
||||
|
||||
#include <boost/winapi/basic_types.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/winapi/file_management.hpp>
|
||||
#include <string>
|
||||
#include <boost/process/v1/filesystem.hpp>
|
||||
#include <boost/core/exchange.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
struct file_descriptor
|
||||
{
|
||||
enum mode_t
|
||||
{
|
||||
read = 1,
|
||||
write = 2,
|
||||
read_write = 3
|
||||
};
|
||||
static ::boost::winapi::DWORD_ desired_access(mode_t mode)
|
||||
{
|
||||
switch(mode)
|
||||
{
|
||||
case read:
|
||||
return ::boost::winapi::GENERIC_READ_;
|
||||
case write:
|
||||
return ::boost::winapi::GENERIC_WRITE_;
|
||||
case read_write:
|
||||
return ::boost::winapi::GENERIC_READ_
|
||||
| ::boost::winapi::GENERIC_WRITE_;
|
||||
default:
|
||||
return 0u;
|
||||
}
|
||||
}
|
||||
|
||||
file_descriptor() = default;
|
||||
file_descriptor(const boost::process::v1::filesystem::path& p, mode_t mode = read_write)
|
||||
: file_descriptor(p.native(), mode)
|
||||
{
|
||||
}
|
||||
|
||||
file_descriptor(const std::string & path , mode_t mode = read_write)
|
||||
#if defined(BOOST_NO_ANSI_APIS)
|
||||
: file_descriptor(::boost::process::v1::detail::convert(path), mode)
|
||||
#else
|
||||
: file_descriptor(path.c_str(), mode)
|
||||
#endif
|
||||
{}
|
||||
file_descriptor(const std::wstring & path, mode_t mode = read_write)
|
||||
: file_descriptor(path.c_str(), mode) {}
|
||||
|
||||
file_descriptor(const char* path, mode_t mode = read_write)
|
||||
#if defined(BOOST_NO_ANSI_APIS)
|
||||
: file_descriptor(std::string(path), mode)
|
||||
#else
|
||||
: _handle(
|
||||
::boost::winapi::create_file(
|
||||
path,
|
||||
desired_access(mode),
|
||||
::boost::winapi::FILE_SHARE_READ_ |
|
||||
::boost::winapi::FILE_SHARE_WRITE_,
|
||||
nullptr,
|
||||
::boost::winapi::OPEN_ALWAYS_,
|
||||
|
||||
::boost::winapi::FILE_ATTRIBUTE_NORMAL_,
|
||||
nullptr
|
||||
))
|
||||
#endif
|
||||
{
|
||||
}
|
||||
file_descriptor(const wchar_t * path, mode_t mode = read_write)
|
||||
: _handle(
|
||||
::boost::winapi::create_file(
|
||||
path,
|
||||
desired_access(mode),
|
||||
::boost::winapi::FILE_SHARE_READ_ |
|
||||
::boost::winapi::FILE_SHARE_WRITE_,
|
||||
nullptr,
|
||||
::boost::winapi::OPEN_ALWAYS_,
|
||||
|
||||
::boost::winapi::FILE_ATTRIBUTE_NORMAL_,
|
||||
nullptr
|
||||
))
|
||||
{
|
||||
|
||||
}
|
||||
file_descriptor(const file_descriptor & ) = delete;
|
||||
file_descriptor(file_descriptor &&other)
|
||||
: _handle( boost::exchange(other._handle, ::boost::winapi::INVALID_HANDLE_VALUE_) )
|
||||
{
|
||||
}
|
||||
|
||||
file_descriptor& operator=(const file_descriptor & ) = delete;
|
||||
file_descriptor& operator=(file_descriptor &&other)
|
||||
{
|
||||
if (_handle != ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::winapi::CloseHandle(_handle);
|
||||
_handle = boost::exchange(other._handle, ::boost::winapi::INVALID_HANDLE_VALUE_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~file_descriptor()
|
||||
{
|
||||
if (_handle != ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::winapi::CloseHandle(_handle);
|
||||
}
|
||||
|
||||
::boost::winapi::HANDLE_ handle() const { return _handle;}
|
||||
|
||||
private:
|
||||
::boost::winapi::HANDLE_ _handle = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
};
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_ */
|
||||
48
include/boost/process/v1/detail/windows/file_in.hpp
Normal file
48
include/boost/process/v1/detail/windows/file_in.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_FILE_IN_HPP
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_FILE_IN_HPP
|
||||
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
#include <boost/process/v1/detail/windows/file_descriptor.hpp>
|
||||
#include <io.h>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
struct file_in : public ::boost::process::v1::detail::handler_base,
|
||||
::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
file_descriptor file;
|
||||
::boost::winapi::HANDLE_ handle = file.handle();
|
||||
|
||||
::boost::winapi::HANDLE_ get_used_handles() const { return handle; }
|
||||
|
||||
template<typename T>
|
||||
file_in(T&& t) : file(std::forward<T>(t), file_descriptor::read) {}
|
||||
file_in(FILE * f) : handle(reinterpret_cast<::boost::winapi::HANDLE_>(_get_osfhandle(_fileno(f)))) {}
|
||||
|
||||
template <class WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
boost::winapi::SetHandleInformation(handle,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_);
|
||||
e.startup_info.hStdInput = handle;
|
||||
e.startup_info.dwFlags |= boost::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
};
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
82
include/boost/process/v1/detail/windows/file_out.hpp
Normal file
82
include/boost/process/v1/detail/windows/file_out.hpp
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_FILE_OUT_HPP
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_FILE_OUT_HPP
|
||||
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/winapi/handle_info.hpp>
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
#include <boost/process/v1/detail/windows/file_descriptor.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
template<int p1, int p2>
|
||||
struct file_out : public ::boost::process::v1::detail::handler_base,
|
||||
::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
file_descriptor file;
|
||||
::boost::winapi::HANDLE_ handle = file.handle();
|
||||
|
||||
::boost::winapi::HANDLE_ get_used_handles() const { return handle; }
|
||||
|
||||
|
||||
template<typename T>
|
||||
file_out(T&& t) : file(std::forward<T>(t), file_descriptor::write) {}
|
||||
file_out(FILE * f) : handle(reinterpret_cast<void*>(_get_osfhandle(_fileno(f)))) {}
|
||||
|
||||
template <typename WindowsExecutor>
|
||||
inline void on_setup(WindowsExecutor &e) const;
|
||||
};
|
||||
|
||||
template<>
|
||||
template<typename WindowsExecutor>
|
||||
void file_out<1,-1>::on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
boost::winapi::SetHandleInformation(handle,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
e.startup_info.hStdOutput = handle;
|
||||
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename WindowsExecutor>
|
||||
void file_out<2,-1>::on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
boost::winapi::SetHandleInformation(handle,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
e.startup_info.hStdError = handle;
|
||||
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename WindowsExecutor>
|
||||
void file_out<1,2>::on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
boost::winapi::SetHandleInformation(handle,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
e.startup_info.hStdOutput = handle;
|
||||
e.startup_info.hStdError = handle;
|
||||
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
212
include/boost/process/v1/detail/windows/group_handle.hpp
Normal file
212
include/boost/process/v1/detail/windows/group_handle.hpp
Normal file
@@ -0,0 +1,212 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/windows/handler.hpp>
|
||||
#include <boost/winapi/jobs.hpp>
|
||||
#include <boost/process/v1/detail/windows/child_handle.hpp>
|
||||
#include <boost/process/v1/detail/windows/job_workaround.hpp>
|
||||
#include <system_error>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
inline bool break_away_enabled(::boost::winapi::HANDLE_ h)
|
||||
{
|
||||
workaround::JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ info;
|
||||
|
||||
if (!workaround::query_information_job_object(
|
||||
h,
|
||||
workaround::JobObjectExtendedLimitInformation_,
|
||||
static_cast<void*>(&info),
|
||||
sizeof(info),
|
||||
nullptr))
|
||||
throw_last_error("QueryInformationJobObject() failed");
|
||||
|
||||
return (info.BasicLimitInformation.LimitFlags & workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_) != 0;
|
||||
}
|
||||
|
||||
inline void enable_break_away(::boost::winapi::HANDLE_ h)
|
||||
{
|
||||
workaround::JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ info;
|
||||
|
||||
if (!workaround::query_information_job_object(
|
||||
h,
|
||||
workaround::JobObjectExtendedLimitInformation_,
|
||||
static_cast<void*>(&info),
|
||||
sizeof(info),
|
||||
nullptr))
|
||||
throw_last_error("QueryInformationJobObject() failed");
|
||||
|
||||
if ((info.BasicLimitInformation.LimitFlags & workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_) != 0)
|
||||
return;
|
||||
|
||||
info.BasicLimitInformation.LimitFlags |= workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_;
|
||||
|
||||
if (!workaround::set_information_job_object(
|
||||
h,
|
||||
workaround::JobObjectExtendedLimitInformation_,
|
||||
static_cast<void*>(&info),
|
||||
sizeof(info)))
|
||||
throw_last_error("SetInformationJobObject() failed");
|
||||
}
|
||||
|
||||
inline void enable_break_away(::boost::winapi::HANDLE_ h, std::error_code & ec)
|
||||
{
|
||||
workaround::JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ info;
|
||||
|
||||
|
||||
if (!workaround::query_information_job_object(
|
||||
h,
|
||||
workaround::JobObjectExtendedLimitInformation_,
|
||||
static_cast<void*>(&info),
|
||||
sizeof(info),
|
||||
nullptr))
|
||||
{
|
||||
ec = get_last_error();
|
||||
return;
|
||||
}
|
||||
|
||||
if ((info.BasicLimitInformation.LimitFlags & workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_) != 0)
|
||||
return;
|
||||
|
||||
info.BasicLimitInformation.LimitFlags |= workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_;
|
||||
|
||||
if (!workaround::set_information_job_object(
|
||||
h,
|
||||
workaround::JobObjectExtendedLimitInformation_,
|
||||
static_cast<void*>(&info),
|
||||
sizeof(info)))
|
||||
{
|
||||
ec = get_last_error();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
inline void associate_completion_port(::boost::winapi::HANDLE_ job,
|
||||
::boost::winapi::HANDLE_ io_port)
|
||||
{
|
||||
workaround::JOBOBJECT_ASSOCIATE_COMPLETION_PORT_ port;
|
||||
port.CompletionKey = job;
|
||||
port.CompletionPort = io_port;
|
||||
|
||||
if (!workaround::set_information_job_object(
|
||||
job,
|
||||
workaround::JobObjectAssociateCompletionPortInformation_,
|
||||
static_cast<void*>(&port),
|
||||
sizeof(port)))
|
||||
throw_last_error("SetInformationJobObject() failed");
|
||||
}
|
||||
|
||||
struct group_handle
|
||||
{
|
||||
::boost::winapi::HANDLE_ _job_object;
|
||||
::boost::winapi::HANDLE_ _io_port;
|
||||
|
||||
typedef ::boost::winapi::HANDLE_ handle_t;
|
||||
handle_t handle() const { return _job_object; }
|
||||
|
||||
explicit group_handle(handle_t h) :
|
||||
_job_object(h),
|
||||
_io_port(::CreateIoCompletionPort(::boost::winapi::INVALID_HANDLE_VALUE_, nullptr, 0, 1))
|
||||
{
|
||||
enable_break_away(_job_object);
|
||||
associate_completion_port(_job_object, _io_port);
|
||||
}
|
||||
|
||||
|
||||
group_handle() : group_handle(::boost::winapi::CreateJobObjectW(nullptr, nullptr))
|
||||
{
|
||||
|
||||
}
|
||||
~group_handle()
|
||||
{
|
||||
::boost::winapi::CloseHandle(_job_object);
|
||||
::boost::winapi::CloseHandle(_io_port);
|
||||
}
|
||||
group_handle(const group_handle & c) = delete;
|
||||
group_handle(group_handle && c) : _job_object(c._job_object),
|
||||
_io_port(c._io_port)
|
||||
{
|
||||
c._job_object = ::boost::winapi::invalid_handle_value;
|
||||
c._io_port = ::boost::winapi::invalid_handle_value;
|
||||
}
|
||||
group_handle &operator=(const group_handle & c) = delete;
|
||||
group_handle &operator=(group_handle && c)
|
||||
{
|
||||
::boost::winapi::CloseHandle(_io_port);
|
||||
_io_port = c._io_port;
|
||||
c._io_port = ::boost::winapi::invalid_handle_value;
|
||||
|
||||
::boost::winapi::CloseHandle(_job_object);
|
||||
_job_object = c._job_object;
|
||||
c._job_object = ::boost::winapi::invalid_handle_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void add(handle_t proc)
|
||||
{
|
||||
if (!::boost::winapi::AssignProcessToJobObject(_job_object, proc))
|
||||
throw_last_error();
|
||||
}
|
||||
void add(handle_t proc, std::error_code & ec) noexcept
|
||||
{
|
||||
if (!::boost::winapi::AssignProcessToJobObject(_job_object, proc))
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
bool has(handle_t proc)
|
||||
{
|
||||
::boost::winapi::BOOL_ is;
|
||||
if (!::boost::winapi::IsProcessInJob(proc, _job_object, &is))
|
||||
throw_last_error();
|
||||
|
||||
return is!=0;
|
||||
}
|
||||
bool has(handle_t proc, std::error_code & ec) noexcept
|
||||
{
|
||||
::boost::winapi::BOOL_ is;
|
||||
if (!::boost::winapi::IsProcessInJob(proc, _job_object, &is))
|
||||
ec = get_last_error();
|
||||
return is!=0;
|
||||
}
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
return _job_object != nullptr;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inline void terminate(const group_handle &p)
|
||||
{
|
||||
if (!::boost::winapi::TerminateJobObject(p.handle(), EXIT_FAILURE))
|
||||
boost::process::v1::detail::throw_last_error("TerminateJobObject() failed");
|
||||
}
|
||||
|
||||
inline void terminate(const group_handle &p, std::error_code &ec) noexcept
|
||||
{
|
||||
if (!::boost::winapi::TerminateJobObject(p.handle(), EXIT_FAILURE))
|
||||
ec = boost::process::v1::detail::get_last_error();
|
||||
else
|
||||
ec.clear();
|
||||
}
|
||||
|
||||
inline bool in_group()
|
||||
{
|
||||
::boost::winapi::BOOL_ res;
|
||||
if (!::boost::winapi::IsProcessInJob(boost::winapi::GetCurrentProcess(), nullptr, &res))
|
||||
throw_last_error("IsProcessInJob failed");
|
||||
|
||||
return res!=0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}}}}}
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_ */
|
||||
54
include/boost/process/v1/detail/windows/group_ref.hpp
Normal file
54
include/boost/process/v1/detail/windows/group_ref.hpp
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_GROUP_REF_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_GROUP_REF_HPP_
|
||||
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/windows/group_handle.hpp>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
#include <boost/process/v1/detail/windows/handler.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
|
||||
|
||||
namespace detail { namespace windows {
|
||||
|
||||
|
||||
|
||||
struct group_ref : handler_base_ext, ::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
::boost::winapi::HANDLE_ handle;
|
||||
|
||||
::boost::winapi::HANDLE_ get_used_handles() const { return handle; }
|
||||
|
||||
explicit group_ref(group_handle &g) :
|
||||
handle(g.handle())
|
||||
{}
|
||||
|
||||
template <class Executor>
|
||||
void on_setup(Executor& exec) const
|
||||
{
|
||||
//I can only enable this if the current process supports breakaways.
|
||||
if (in_group() && break_away_enabled(nullptr))
|
||||
exec.creation_flags |= boost::winapi::CREATE_BREAKAWAY_FROM_JOB_;
|
||||
}
|
||||
|
||||
|
||||
template <class Executor>
|
||||
void on_success(Executor& exec) const
|
||||
{
|
||||
if (!::boost::winapi::AssignProcessToJobObject(handle, exec.proc_info.hProcess))
|
||||
exec.set_error(::boost::process::v1::detail::get_last_error(),
|
||||
"AssignProcessToJobObject() failed.");
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}}}}}
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_ */
|
||||
264
include/boost/process/v1/detail/windows/handle_workaround.hpp
Normal file
264
include/boost/process/v1/detail/windows/handle_workaround.hpp
Normal file
@@ -0,0 +1,264 @@
|
||||
// Copyright (c) 2018 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_HANDLE_WORKAROUND_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_HANDLE_WORKAROUND_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
|
||||
#include <boost/winapi/basic_types.hpp>
|
||||
#include <boost/winapi/dll.hpp>
|
||||
#include <boost/winapi/access_rights.hpp>
|
||||
//#define BOOST_USE_WINDOWS_H 1
|
||||
|
||||
#if defined( BOOST_USE_WINDOWS_H )
|
||||
#include <winternl.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows { namespace workaround
|
||||
{
|
||||
|
||||
|
||||
typedef struct _SYSTEM_HANDLE_ENTRY_
|
||||
{
|
||||
::boost::winapi::ULONG_ OwnerPid;
|
||||
::boost::winapi::BYTE_ ObjectType;
|
||||
::boost::winapi::BYTE_ HandleFlags;
|
||||
::boost::winapi::USHORT_ HandleValue;
|
||||
::boost::winapi::PVOID_ ObjectPointer;
|
||||
::boost::winapi::ULONG_ AccessMask;
|
||||
} SYSTEM_HANDLE_ENTRY_, *PSYSTEM_HANDLE_ENTRY_;
|
||||
|
||||
typedef struct _SYSTEM_HANDLE_INFORMATION_
|
||||
{
|
||||
::boost::winapi::ULONG_ Count;
|
||||
SYSTEM_HANDLE_ENTRY_ Handle[1];
|
||||
} SYSTEM_HANDLE_INFORMATION_, *PSYSTEM_HANDLE_INFORMATION_;
|
||||
|
||||
#if defined( BOOST_USE_WINDOWS_H )
|
||||
|
||||
using UNICODE_STRING_ = ::UNICODE_STRING;
|
||||
using GENERIC_MAPPING_ = ::GENERIC_MAPPING;
|
||||
using OBJECT_INFORMATION_CLASS_ = ::OBJECT_INFORMATION_CLASS;
|
||||
|
||||
constexpr static OBJECT_INFORMATION_CLASS_ ObjectTypeInformation = ::OBJECT_INFORMATION_CLASS::ObjectTypeInformation;
|
||||
|
||||
typedef struct _OBJECT_TYPE_INFORMATION_ {
|
||||
UNICODE_STRING TypeName;
|
||||
ULONG TotalNumberOfObjects;
|
||||
ULONG TotalNumberOfHandles;
|
||||
ULONG TotalPagedPoolUsage;
|
||||
ULONG TotalNonPagedPoolUsage;
|
||||
ULONG TotalNamePoolUsage;
|
||||
ULONG TotalHandleTableUsage;
|
||||
ULONG HighWaterNumberOfObjects;
|
||||
ULONG HighWaterNumberOfHandles;
|
||||
ULONG HighWaterPagedPoolUsage;
|
||||
ULONG HighWaterNonPagedPoolUsage;
|
||||
ULONG HighWaterNamePoolUsage;
|
||||
ULONG HighWaterHandleTableUsage;
|
||||
ULONG InvalidAttributes;
|
||||
GENERIC_MAPPING GenericMapping;
|
||||
ULONG ValidAccessMask;
|
||||
BOOLEAN SecurityRequired;
|
||||
BOOLEAN MaintainHandleCount;
|
||||
UCHAR TypeIndex;
|
||||
CHAR ReservedByte;
|
||||
ULONG PoolType;
|
||||
ULONG DefaultPagedPoolCharge;
|
||||
ULONG DefaultNonPagedPoolCharge;
|
||||
} OBJECT_TYPE_INFORMATION_, *POBJECT_TYPE_INFORMATION_;
|
||||
|
||||
#else
|
||||
|
||||
typedef enum _OBJECT_INFORMATION_CLASS_
|
||||
{
|
||||
ObjectBasicInformation,
|
||||
ObjectNameInformation,
|
||||
ObjectTypeInformation,
|
||||
ObjectAllInformation,
|
||||
ObjectDataInformation
|
||||
} OBJECT_INFORMATION_CLASS_, *POBJECT_INFORMATION_CLASS_;
|
||||
|
||||
typedef struct _UNICODE_STRING_ {
|
||||
::boost::winapi::USHORT_ Length;
|
||||
::boost::winapi::USHORT_ MaximumLength;
|
||||
::boost::winapi::LPWSTR_ Buffer;
|
||||
} UNICODE_STRING_, *PUNICODE_STRING_;
|
||||
|
||||
typedef struct _GENERIC_MAPPING_ {
|
||||
::boost::winapi::ACCESS_MASK_ GenericRead;
|
||||
::boost::winapi::ACCESS_MASK_ GenericWrite;
|
||||
::boost::winapi::ACCESS_MASK_ GenericExecute;
|
||||
::boost::winapi::ACCESS_MASK_ GenericAll;
|
||||
} GENERIC_MAPPING_;
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct _OBJECT_BASIC_INFORMATION {
|
||||
::boost::winapi::ULONG_ Attributes;
|
||||
::boost::winapi::ACCESS_MASK_ GrantedAccess;
|
||||
::boost::winapi::ULONG_ HandleCount;
|
||||
::boost::winapi::ULONG_ PointerCount;
|
||||
::boost::winapi::ULONG_ PagedPoolUsage;
|
||||
::boost::winapi::ULONG_ NonPagedPoolUsage;
|
||||
::boost::winapi::ULONG_ Reserved[3];
|
||||
::boost::winapi::ULONG_ NameInformationLength;
|
||||
::boost::winapi::ULONG_ TypeInformationLength;
|
||||
::boost::winapi::ULONG_ SecurityDescriptorLength;
|
||||
::boost::winapi::LARGE_INTEGER_ CreateTime;
|
||||
} OBJECT_BASIC_INFORMATION_, *POBJECT_BASIC_INFORMATION_;
|
||||
|
||||
typedef struct _OBJECT_NAME_INFORMATION {
|
||||
UNICODE_STRING_ Name;
|
||||
} OBJECT_NAME_INFORMATION_, *POBJECT_NAME_INFORMATION_;
|
||||
|
||||
|
||||
#if defined( BOOST_USE_WINDOWS_H )
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
using SYSTEM_INFORMATION_CLASS_ = ::SYSTEM_INFORMATION_CLASS;
|
||||
constexpr static SYSTEM_INFORMATION_CLASS_ SystemHandleInformation_ = static_cast<SYSTEM_INFORMATION_CLASS_>(16);
|
||||
|
||||
inline ::boost::winapi::NTSTATUS_ nt_system_query_information(
|
||||
SYSTEM_INFORMATION_CLASS SystemInformationClass,
|
||||
void * SystemInformation,
|
||||
::boost::winapi::ULONG_ SystemInformationLength,
|
||||
::boost::winapi::PULONG_ ReturnLength)
|
||||
{
|
||||
return ::NtQuerySystemInformation(SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength);
|
||||
}
|
||||
|
||||
inline ::boost::winapi::NTSTATUS_ nt_query_object(
|
||||
::boost::winapi::HANDLE_ Handle,
|
||||
OBJECT_INFORMATION_CLASS_ ObjectInformationClass,
|
||||
::boost::winapi::PVOID_ ObjectInformation,
|
||||
::boost::winapi::ULONG_ ObjectInformationLength,
|
||||
::boost::winapi::PULONG_ ReturnLength
|
||||
)
|
||||
{
|
||||
return ::NtQueryObject(Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength, ReturnLength);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
//this import workaround is to keep it a header-only library. and enums cannot be imported from the winapi.
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
typedef enum _SYSTEM_INFORMATION_CLASS_
|
||||
{
|
||||
SystemBasicInformation_ = 0,
|
||||
SystemProcessorInformation_ = 1,
|
||||
SystemPerformanceInformation_ = 2,
|
||||
SystemTimeOfDayInformation_ = 3,
|
||||
SystemProcessInformation_ = 5,
|
||||
SystemProcessorPerformanceInformation_ = 8,
|
||||
SystemHandleInformation_ = 16,
|
||||
SystemPagefileInformation_ = 18,
|
||||
SystemInterruptInformation_ = 23,
|
||||
SystemExceptionInformation_ = 33,
|
||||
SystemRegistryQuotaInformation_ = 37,
|
||||
SystemLookasideInformation_ = 45
|
||||
} SYSTEM_INFORMATION_CLASS_;
|
||||
|
||||
|
||||
typedef struct _OBJECT_TYPE_INFORMATION_ {
|
||||
UNICODE_STRING_ TypeName;
|
||||
::boost::winapi::ULONG_ TotalNumberOfObjects;
|
||||
::boost::winapi::ULONG_ TotalNumberOfHandles;
|
||||
::boost::winapi::ULONG_ TotalPagedPoolUsage;
|
||||
::boost::winapi::ULONG_ TotalNonPagedPoolUsage;
|
||||
::boost::winapi::ULONG_ TotalNamePoolUsage;
|
||||
::boost::winapi::ULONG_ TotalHandleTableUsage;
|
||||
::boost::winapi::ULONG_ HighWaterNumberOfObjects;
|
||||
::boost::winapi::ULONG_ HighWaterNumberOfHandles;
|
||||
::boost::winapi::ULONG_ HighWaterPagedPoolUsage;
|
||||
::boost::winapi::ULONG_ HighWaterNonPagedPoolUsage;
|
||||
::boost::winapi::ULONG_ HighWaterNamePoolUsage;
|
||||
::boost::winapi::ULONG_ HighWaterHandleTableUsage;
|
||||
::boost::winapi::ULONG_ InvalidAttributes;
|
||||
GENERIC_MAPPING_ GenericMapping;
|
||||
::boost::winapi::ULONG_ ValidAccessMask;
|
||||
::boost::winapi::BOOLEAN_ SecurityRequired;
|
||||
::boost::winapi::BOOLEAN_ MaintainHandleCount;
|
||||
::boost::winapi::UCHAR_ TypeIndex;
|
||||
::boost::winapi::CHAR_ ReservedByte;
|
||||
::boost::winapi::ULONG_ PoolType;
|
||||
::boost::winapi::ULONG_ DefaultPagedPoolCharge;
|
||||
::boost::winapi::ULONG_ DefaultNonPagedPoolCharge;
|
||||
} OBJECT_TYPE_INFORMATION_, *POBJECT_TYPE_INFORMATION_;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
NTSTATUS NtQuerySystemInformation(
|
||||
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
|
||||
OUT PVOID SystemInformation,
|
||||
IN ULONG SystemInformationLength,
|
||||
OUT PULONG ReturnLength
|
||||
);
|
||||
*/
|
||||
typedef ::boost::winapi::NTSTATUS_ (*nt_system_query_information_p )(
|
||||
SYSTEM_INFORMATION_CLASS_,
|
||||
void *,
|
||||
::boost::winapi::ULONG_,
|
||||
::boost::winapi::PULONG_);
|
||||
/*
|
||||
NTSYSCALLAPI NTSTATUS NtQueryObject(
|
||||
HANDLE Handle,
|
||||
OBJECT_INFORMATION_CLASS ObjectInformationClass,
|
||||
PVOID ObjectInformation,
|
||||
ULONG ObjectInformationLength,
|
||||
PULONG ReturnLength
|
||||
);
|
||||
*/
|
||||
|
||||
typedef ::boost::winapi::NTSTATUS_ (*nt_query_object_p )(
|
||||
::boost::winapi::HANDLE_,
|
||||
OBJECT_INFORMATION_CLASS_,
|
||||
void *,
|
||||
::boost::winapi::ULONG_,
|
||||
::boost::winapi::PULONG_);
|
||||
|
||||
}
|
||||
|
||||
inline ::boost::winapi::NTSTATUS_ nt_system_query_information(
|
||||
SYSTEM_INFORMATION_CLASS_ SystemInformationClass,
|
||||
void *SystemInformation,
|
||||
::boost::winapi::ULONG_ SystemInformationLength,
|
||||
::boost::winapi::PULONG_ ReturnLength)
|
||||
{
|
||||
static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle(L"Ntdll.dll");
|
||||
static nt_system_query_information_p f = reinterpret_cast<nt_system_query_information_p>(::boost::winapi::get_proc_address(h, "NtQuerySystemInformation"));
|
||||
|
||||
return (*f)(SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength);
|
||||
}
|
||||
|
||||
|
||||
inline ::boost::winapi::BOOL_ nt_query_object(
|
||||
::boost::winapi::HANDLE_ Handle,
|
||||
OBJECT_INFORMATION_CLASS_ ObjectInformationClass,
|
||||
void *ObjectInformation,
|
||||
::boost::winapi::ULONG_ ObjectInformationLength,
|
||||
::boost::winapi::PULONG_ ReturnLength)
|
||||
{
|
||||
static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle(L"Ntdll.dll");
|
||||
static nt_query_object_p f = reinterpret_cast<nt_query_object_p>(::boost::winapi::get_proc_address(h, "NtQueryObject"));
|
||||
|
||||
return (*f)(Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength, ReturnLength);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}}}}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_JOB_WORKAROUND_HPP_ */
|
||||
21
include/boost/process/v1/detail/windows/handler.hpp
Normal file
21
include/boost/process/v1/detail/windows/handler.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_HANDLER_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_HANDLER_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
//does not extend anything.
|
||||
struct handler_base_ext : handler_base {};
|
||||
|
||||
}}}}}
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_HANDLER_HPP_ */
|
||||
175
include/boost/process/v1/detail/windows/handles.hpp
Normal file
175
include/boost/process/v1/detail/windows/handles.hpp
Normal file
@@ -0,0 +1,175 @@
|
||||
// Copyright (c) 2019 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_HANDLES_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_HANDLES_HPP_
|
||||
|
||||
#include <vector>
|
||||
#include <system_error>
|
||||
#include <boost/process/v1/detail/windows/handle_workaround.hpp>
|
||||
#include <boost/process/v1/detail/windows/handler.hpp>
|
||||
#include <boost/winapi/get_current_process_id.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/winapi/handle_info.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
|
||||
|
||||
template<typename Executor, typename Function>
|
||||
void foreach_used_handle(Executor &exec, Function &&func);
|
||||
|
||||
|
||||
namespace windows {
|
||||
|
||||
|
||||
using native_handle_type = ::boost::winapi::HANDLE_ ;
|
||||
|
||||
inline std::vector<native_handle_type> get_handles(std::error_code & ec)
|
||||
{
|
||||
auto pid = ::boost::winapi::GetCurrentProcessId();
|
||||
|
||||
std::vector<char> buffer(2048);
|
||||
constexpr static auto STATUS_INFO_LENGTH_MISMATCH_ = static_cast<::boost::winapi::NTSTATUS_>(0xC0000004l);
|
||||
auto info_pointer = reinterpret_cast<workaround::SYSTEM_HANDLE_INFORMATION_*>(buffer.data());
|
||||
|
||||
::boost::winapi::NTSTATUS_ nt_status = STATUS_INFO_LENGTH_MISMATCH_;
|
||||
|
||||
for (;
|
||||
nt_status == STATUS_INFO_LENGTH_MISMATCH_;
|
||||
nt_status = workaround::nt_system_query_information(
|
||||
workaround::SystemHandleInformation_,
|
||||
info_pointer, static_cast<::boost::winapi::ULONG_>(buffer.size()),
|
||||
nullptr))
|
||||
{
|
||||
buffer.resize(buffer.size() * 2);
|
||||
info_pointer = reinterpret_cast<workaround::SYSTEM_HANDLE_INFORMATION_*>(buffer.data());
|
||||
}
|
||||
|
||||
|
||||
if (nt_status < 0 || nt_status > 0x7FFFFFFF)
|
||||
{
|
||||
ec = ::boost::process::v1::detail::get_last_error();
|
||||
return {};
|
||||
}
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
std::vector<native_handle_type> res;
|
||||
for (auto itr = info_pointer->Handle; itr != (info_pointer->Handle + info_pointer->Count); itr++)
|
||||
{
|
||||
if (itr->OwnerPid == pid)
|
||||
res.push_back(reinterpret_cast<native_handle_type>(static_cast<std::uintptr_t>(itr->HandleValue)));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
inline std::vector<native_handle_type> get_handles()
|
||||
{
|
||||
std::error_code ec;
|
||||
|
||||
auto res = get_handles(ec);
|
||||
if (ec)
|
||||
boost::process::v1::detail::throw_error(ec, "NtQuerySystemInformation failed");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
inline bool is_stream_handle(native_handle_type handle, std::error_code & ec)
|
||||
{
|
||||
::boost::winapi::ULONG_ actual_size;
|
||||
auto nt_status = workaround::nt_query_object(
|
||||
handle,
|
||||
workaround::ObjectTypeInformation,
|
||||
NULL,
|
||||
0, &actual_size);
|
||||
|
||||
std::vector<char> vec;
|
||||
vec.resize(actual_size);
|
||||
|
||||
workaround::OBJECT_TYPE_INFORMATION_ * type_info_p = reinterpret_cast<workaround::OBJECT_TYPE_INFORMATION_*>(vec.data());
|
||||
nt_status = workaround::nt_query_object(
|
||||
handle,
|
||||
workaround::ObjectTypeInformation,
|
||||
type_info_p,
|
||||
actual_size, &actual_size);
|
||||
|
||||
if (nt_status < 0 || nt_status > 0x7FFFFFFF)
|
||||
{
|
||||
ec = ::boost::process::v1::detail::get_last_error();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
auto &nm = type_info_p->TypeName.Buffer;
|
||||
return type_info_p->TypeName.Length >= 5 &&
|
||||
nm[0] == L'F' &&
|
||||
nm[1] == L'i' &&
|
||||
nm[2] == L'l' &&
|
||||
nm[3] == L'e' &&
|
||||
nm[4] == L'\0';
|
||||
}
|
||||
|
||||
|
||||
inline bool is_stream_handle(native_handle_type handle)
|
||||
{
|
||||
std::error_code ec;
|
||||
auto res = is_stream_handle(handle, ec);
|
||||
if (ec)
|
||||
boost::process::v1::detail::throw_error(ec, "NtQueryObject failed");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
struct limit_handles_ : handler_base_ext
|
||||
{
|
||||
mutable std::vector<::boost::winapi::HANDLE_> handles_with_inherit_flag;
|
||||
|
||||
template<typename Executor>
|
||||
void on_setup(Executor & exec) const
|
||||
{
|
||||
auto all_handles = get_handles();
|
||||
foreach_used_handle(exec,
|
||||
[&](::boost::winapi::HANDLE_ handle)
|
||||
{
|
||||
auto itr = std::find(all_handles.begin(), all_handles .end(), handle);
|
||||
::boost::winapi::DWORD_ flags = 0u;
|
||||
if (itr != all_handles.end())
|
||||
*itr = ::boost::winapi::INVALID_HANDLE_VALUE_; // the handle is used mark it as invalid, so it doesn't get reset
|
||||
});
|
||||
|
||||
auto part_itr = std::partition(all_handles.begin(), all_handles.end(),
|
||||
[](::boost::winapi::HANDLE_ handle) {return handle != ::boost::winapi::INVALID_HANDLE_VALUE_;});
|
||||
|
||||
all_handles.erase(part_itr, all_handles.end()); //remove invalid handles
|
||||
handles_with_inherit_flag = std::move(all_handles);
|
||||
|
||||
for (auto handle : handles_with_inherit_flag)
|
||||
::boost::winapi::SetHandleInformation(handle, ::boost::winapi::HANDLE_FLAG_INHERIT_, 0);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor & exec, const std::error_code & ec) const
|
||||
{
|
||||
for (auto handle : handles_with_inherit_flag)
|
||||
::boost::winapi::SetHandleInformation(handle, ::boost::winapi::HANDLE_FLAG_INHERIT_, ::boost::winapi::HANDLE_FLAG_INHERIT_);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_success(Executor & exec) const
|
||||
{
|
||||
for (auto handle : handles_with_inherit_flag)
|
||||
::boost::winapi::SetHandleInformation(handle, ::boost::winapi::HANDLE_FLAG_INHERIT_, ::boost::winapi::HANDLE_FLAG_INHERIT_);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif //PROCESS_HANDLES_HPP
|
||||
172
include/boost/process/v1/detail/windows/io_context_ref.hpp
Normal file
172
include/boost/process/v1/detail/windows/io_context_ref.hpp
Normal file
@@ -0,0 +1,172 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_IO_CONTEXT_REF_HPP_
|
||||
#define BOOST_PROCESS_WINDOWS_IO_CONTEXT_REF_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
#include <boost/process/v1/detail/windows/async_handler.hpp>
|
||||
#include <boost/process/v1/detail/windows/is_running.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/windows/object_handle.hpp>
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
|
||||
#include <boost/fusion/algorithm/iteration/for_each.hpp>
|
||||
#include <boost/fusion/algorithm/transformation/filter_if.hpp>
|
||||
#include <boost/fusion/algorithm/transformation/transform.hpp>
|
||||
#include <boost/fusion/view/transform_view.hpp>
|
||||
#include <boost/fusion/container/vector/convert.hpp>
|
||||
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/type_index.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
template<typename Executor>
|
||||
struct on_exit_handler_transformer
|
||||
{
|
||||
Executor & exec;
|
||||
on_exit_handler_transformer(Executor & exec) : exec(exec) {}
|
||||
template<typename Sig>
|
||||
struct result;
|
||||
|
||||
template<typename T>
|
||||
struct result<on_exit_handler_transformer<Executor>(T&)>
|
||||
{
|
||||
typedef typename T::on_exit_handler_t type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
auto operator()(T& t) const -> typename T::on_exit_handler_t
|
||||
{
|
||||
return t.on_exit_handler(exec);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Executor>
|
||||
struct async_handler_collector
|
||||
{
|
||||
Executor & exec;
|
||||
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers;
|
||||
|
||||
|
||||
async_handler_collector(Executor & exec,
|
||||
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers)
|
||||
: exec(exec), handlers(handlers) {}
|
||||
|
||||
template<typename T>
|
||||
void operator()(T & t) const
|
||||
{
|
||||
handlers.push_back(t.on_exit_handler(exec));
|
||||
}
|
||||
};
|
||||
|
||||
//Also set's up waiting for the exit, so it can close async stuff.
|
||||
struct io_context_ref : boost::process::v1::detail::handler_base
|
||||
{
|
||||
|
||||
io_context_ref(boost::asio::io_context & ios)
|
||||
: ios(ios)
|
||||
{
|
||||
}
|
||||
boost::asio::io_context &get() {return ios;};
|
||||
|
||||
template <class Executor>
|
||||
void on_success(Executor& exec) const
|
||||
{
|
||||
auto asyncs = boost::fusion::filter_if<
|
||||
is_async_handler<
|
||||
typename std::remove_reference< boost::mpl::_ > ::type
|
||||
>>(exec.seq);
|
||||
|
||||
//ok, check if there are actually any.
|
||||
if (boost::fusion::empty(asyncs))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
::boost::winapi::PROCESS_INFORMATION_ & proc = exec.proc_info;
|
||||
auto this_proc = ::boost::winapi::GetCurrentProcess();
|
||||
|
||||
auto proc_in = proc.hProcess;;
|
||||
::boost::winapi::HANDLE_ process_handle;
|
||||
|
||||
if (!::boost::winapi::DuplicateHandle(
|
||||
this_proc, proc_in, this_proc, &process_handle, 0,
|
||||
static_cast<::boost::winapi::BOOL_>(true),
|
||||
::boost::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
|
||||
exec.set_error(::boost::process::v1::detail::get_last_error(),
|
||||
"Duplicate Pipe Failed");
|
||||
|
||||
|
||||
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
|
||||
funcs.reserve(boost::fusion::size(asyncs));
|
||||
boost::fusion::for_each(asyncs, async_handler_collector<Executor>(exec, funcs));
|
||||
|
||||
wait_handler wh(std::move(funcs), ios, process_handle, exec.exit_status);
|
||||
|
||||
::boost::winapi::DWORD_ code;
|
||||
if(::boost::winapi::GetExitCodeProcess(process_handle, &code)
|
||||
&& code != still_active)
|
||||
{
|
||||
::boost::asio::post(wh.handle->get_executor(), std::move(wh));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
auto handle_p = wh.handle.get();
|
||||
handle_p->async_wait(std::move(wh));
|
||||
}
|
||||
|
||||
|
||||
struct wait_handler
|
||||
{
|
||||
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
|
||||
std::unique_ptr<boost::asio::windows::object_handle> handle;
|
||||
std::shared_ptr<std::atomic<int>> exit_status;
|
||||
wait_handler(const wait_handler & ) = delete;
|
||||
wait_handler(wait_handler && ) = default;
|
||||
wait_handler(std::vector<std::function<void(int, const std::error_code & ec)>> && funcs,
|
||||
boost::asio::io_context & ios, void * handle,
|
||||
const std::shared_ptr<std::atomic<int>> &exit_status)
|
||||
: funcs(std::move(funcs)),
|
||||
handle(new boost::asio::windows::object_handle(
|
||||
asio::prefer(ios.get_executor(), asio::execution::outstanding_work.tracked), handle)),
|
||||
exit_status(exit_status)
|
||||
{
|
||||
|
||||
}
|
||||
void operator()(const boost::system::error_code & ec_in = {})
|
||||
{
|
||||
std::error_code ec;
|
||||
if (ec_in)
|
||||
ec = std::error_code(ec_in.value(), std::system_category());
|
||||
|
||||
::boost::winapi::DWORD_ code;
|
||||
::boost::winapi::GetExitCodeProcess(handle->native_handle(), &code);
|
||||
exit_status->store(code);
|
||||
|
||||
for (auto & func : funcs)
|
||||
func(code, ec);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
boost::asio::io_context &ios;
|
||||
};
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_WINDOWS_IO_CONTEXT_REF_HPP_ */
|
||||
57
include/boost/process/v1/detail/windows/is_running.hpp
Normal file
57
include/boost/process/v1/detail/windows/is_running.hpp
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_IS_RUNNING_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_IS_RUNNING_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/windows/child_handle.hpp>
|
||||
#include <system_error>
|
||||
#include <cstdlib>
|
||||
#include <boost/winapi/process.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
constexpr static ::boost::winapi::DWORD_ still_active = 259;
|
||||
|
||||
|
||||
struct child_handle;
|
||||
|
||||
inline bool is_running(const child_handle &p, int & exit_code, std::error_code &ec) noexcept
|
||||
{
|
||||
::boost::winapi::DWORD_ code;
|
||||
//single value, not needed in the winapi.
|
||||
if (!::boost::winapi::GetExitCodeProcess(p.process_handle(), &code))
|
||||
ec = ::boost::process::v1::detail::get_last_error();
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
if (code == still_active)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
exit_code = code;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool is_running(const child_handle &p, int & exit_code)
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = is_running(p, exit_code, ec);
|
||||
boost::process::v1::detail::throw_error(ec, "GetExitCodeProcess() failed in is_running");
|
||||
return b;
|
||||
}
|
||||
|
||||
inline bool is_running(int code)
|
||||
{
|
||||
return code == still_active;
|
||||
}
|
||||
|
||||
inline int eval_exit_status(int in ) {return in;}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
262
include/boost/process/v1/detail/windows/job_workaround.hpp
Normal file
262
include/boost/process/v1/detail/windows/job_workaround.hpp
Normal file
@@ -0,0 +1,262 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_JOB_WORKAROUND_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_JOB_WORKAROUND_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/winapi/config.hpp>
|
||||
#include <boost/winapi/basic_types.hpp>
|
||||
#include <boost/winapi/dll.hpp>
|
||||
#include <boost/winapi/overlapped.hpp>
|
||||
|
||||
#if defined( BOOST_USE_WINDOWS_H )
|
||||
#include <windows.h>
|
||||
#else
|
||||
extern "C"
|
||||
{
|
||||
BOOST_SYMBOL_IMPORT ::boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC CreateIoCompletionPort(
|
||||
::boost::winapi::HANDLE_ FileHandle,
|
||||
::boost::winapi::HANDLE_ ExistingCompletionPort,
|
||||
::boost::winapi::ULONG_PTR_ CompletionKey,
|
||||
::boost::winapi::DWORD_ NumberOfConcurrentThreads
|
||||
);
|
||||
|
||||
BOOST_SYMBOL_IMPORT ::boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC GetQueuedCompletionStatus(
|
||||
::boost::winapi::HANDLE_ CompletionPort,
|
||||
::boost::winapi::LPDWORD_ lpNumberOfBytes,
|
||||
::boost::winapi::ULONG_PTR_ *lpCompletionKey,
|
||||
_OVERLAPPED **lpOverlapped,
|
||||
::boost::winapi::DWORD_ dwMilliseconds
|
||||
);
|
||||
|
||||
}
|
||||
#endif
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows { namespace workaround {
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
struct JOBOBJECT_ASSOCIATE_COMPLETION_PORT_
|
||||
{
|
||||
::boost::winapi::PVOID_ CompletionKey;
|
||||
::boost::winapi::HANDLE_ CompletionPort;
|
||||
};
|
||||
|
||||
constexpr static int JOB_OBJECT_MSG_END_OF_JOB_TIME_ = 1;
|
||||
constexpr static int JOB_OBJECT_MSG_END_OF_PROCESS_TIME_ = 2;
|
||||
constexpr static int JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT_ = 3;
|
||||
constexpr static int JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO_ = 4;
|
||||
constexpr static int JOB_OBJECT_MSG_NEW_PROCESS_ = 6;
|
||||
constexpr static int JOB_OBJECT_MSG_EXIT_PROCESS_ = 7;
|
||||
constexpr static int JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS_ = 8;
|
||||
constexpr static int JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT_ = 9;
|
||||
constexpr static int JOB_OBJECT_MSG_JOB_MEMORY_LIMIT_ = 10;
|
||||
constexpr static int JOB_OBJECT_MSG_NOTIFICATION_LIMIT_ = 11;
|
||||
constexpr static int JOB_OBJECT_MSG_JOB_CYCLE_TIME_LIMIT_ = 12;
|
||||
constexpr static int JOB_OBJECT_MSG_SILO_TERMINATED_ = 13;
|
||||
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE ::boost::winapi::BOOL_ get_queued_completion_status(
|
||||
::boost::winapi::HANDLE_ CompletionPort,
|
||||
::boost::winapi::LPDWORD_ lpNumberOfBytes,
|
||||
::boost::winapi::ULONG_PTR_ *lpCompletionKey,
|
||||
::boost::winapi::LPOVERLAPPED_ *lpOverlapped,
|
||||
::boost::winapi::DWORD_ dwMilliseconds)
|
||||
{
|
||||
return ::GetQueuedCompletionStatus(
|
||||
CompletionPort,
|
||||
lpNumberOfBytes,
|
||||
lpCompletionKey,
|
||||
reinterpret_cast<::_OVERLAPPED**>(lpOverlapped),
|
||||
dwMilliseconds);
|
||||
}
|
||||
|
||||
#if defined( BOOST_USE_WINDOWS_H )
|
||||
|
||||
constexpr auto static JobObjectExtendedLimitInformation_ = ::JobObjectExtendedLimitInformation;
|
||||
constexpr auto static JobObjectAssociateCompletionPortInformation_ = ::JobObjectAssociateCompletionPortInformation;
|
||||
constexpr auto static JobObjectBasicAccountingInformation_ = ::JobObjectBasicAccountingInformation;
|
||||
|
||||
using JOBOBJECT_BASIC_LIMIT_INFORMATION_ = ::JOBOBJECT_BASIC_LIMIT_INFORMATION;
|
||||
using JOBOBJECTINFOCLASS_ = ::JOBOBJECTINFOCLASS;
|
||||
using IO_COUNTERS_ = ::IO_COUNTERS;
|
||||
using JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ = ::JOBOBJECT_EXTENDED_LIMIT_INFORMATION;
|
||||
using JOBOBJECT_BASIC_ACCOUNTING_INFORMATION_ = ::JOBOBJECT_BASIC_ACCOUNTING_INFORMATION;
|
||||
|
||||
inline ::boost::winapi::BOOL_ query_information_job_object(
|
||||
::boost::winapi::HANDLE_ hJob,
|
||||
JOBOBJECTINFOCLASS_ JobObjectInfoClass,
|
||||
void * lpJobObjectInfo,
|
||||
::boost::winapi::DWORD_ cbJobObjectInfoLength,
|
||||
::boost::winapi::DWORD_ *lpReturnLength)
|
||||
{
|
||||
return ::QueryInformationJobObject(hJob, JobObjectInfoClass, lpJobObjectInfo, cbJobObjectInfoLength, lpReturnLength);
|
||||
}
|
||||
|
||||
inline ::boost::winapi::BOOL_ set_information_job_object(
|
||||
::boost::winapi::HANDLE_ hJob,
|
||||
JOBOBJECTINFOCLASS_ JobObjectInfoClass,
|
||||
void * lpJobObjectInfo,
|
||||
::boost::winapi::DWORD_ cbJobObjectInfoLength)
|
||||
{
|
||||
return ::SetInformationJobObject(hJob, JobObjectInfoClass, lpJobObjectInfo, cbJobObjectInfoLength);
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
//this import workaround is to keep it a header-only library. and enums cannot be imported from the winapi.
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
typedef enum _JOBOBJECTINFOCLASS_
|
||||
{
|
||||
JobObjectBasicAccountingInformation_ = 1,
|
||||
JobObjectBasicLimitInformation_,
|
||||
JobObjectBasicProcessIdList_,
|
||||
JobObjectBasicUIRestrictions_,
|
||||
JobObjectSecurityLimitInformation_,
|
||||
JobObjectEndOfJobTimeInformation_,
|
||||
JobObjectAssociateCompletionPortInformation_,
|
||||
JobObjectBasicAndIoAccountingInformation_,
|
||||
JobObjectExtendedLimitInformation_,
|
||||
JobObjectJobSetInformation_,
|
||||
JobObjectGroupInformation_,
|
||||
JobObjectNotificationLimitInformation_,
|
||||
JobObjectLimitViolationInformation_,
|
||||
JobObjectGroupInformationEx_,
|
||||
JobObjectCpuRateControlInformation_,
|
||||
JobObjectCompletionFilter_,
|
||||
JobObjectCompletionCounter_,
|
||||
JobObjectReserved1Information_ = 18,
|
||||
JobObjectReserved2Information_,
|
||||
JobObjectReserved3Information_,
|
||||
JobObjectReserved4Information_,
|
||||
JobObjectReserved5Information_,
|
||||
JobObjectReserved6Information_,
|
||||
JobObjectReserved7Information_,
|
||||
JobObjectReserved8Information_,
|
||||
MaxJobObjectInfoClass_
|
||||
} JOBOBJECTINFOCLASS_;
|
||||
|
||||
typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION_
|
||||
{
|
||||
::boost::winapi::LARGE_INTEGER_ PerProcessUserTimeLimit;
|
||||
::boost::winapi::LARGE_INTEGER_ PerJobUserTimeLimit;
|
||||
::boost::winapi::DWORD_ LimitFlags;
|
||||
::boost::winapi::SIZE_T_ MinimumWorkingSetSize;
|
||||
::boost::winapi::SIZE_T_ MaximumWorkingSetSize;
|
||||
::boost::winapi::DWORD_ ActiveProcessLimit;
|
||||
::boost::winapi::ULONG_PTR_ Affinity;
|
||||
::boost::winapi::DWORD_ PriorityClass;
|
||||
::boost::winapi::DWORD_ SchedulingClass;
|
||||
} JOBOBJECT_BASIC_LIMIT_INFORMATION_;
|
||||
|
||||
|
||||
typedef struct _JOBOBJECT_BASIC_ACCOUNTING_INFORMATION_ {
|
||||
::boost::winapi::LARGE_INTEGER_ TotalUserTime;
|
||||
::boost::winapi::LARGE_INTEGER_ TotalKernelTime;
|
||||
::boost::winapi::LARGE_INTEGER_ ThisPeriodTotalUserTime;
|
||||
::boost::winapi::LARGE_INTEGER_ ThisPeriodTotalKernelTime;
|
||||
::boost::winapi::DWORD_ TotalPageFaultCount;
|
||||
::boost::winapi::DWORD_ TotalProcesses;
|
||||
::boost::winapi::DWORD_ ActiveProcesses;
|
||||
::boost::winapi::DWORD_ TotalTerminatedProcesses;
|
||||
} JOBOBJECT_BASIC_ACCOUNTING_INFORMATION_;
|
||||
|
||||
typedef struct _IO_COUNTERS_
|
||||
{
|
||||
::boost::winapi::ULONGLONG_ ReadOperationCount;
|
||||
::boost::winapi::ULONGLONG_ WriteOperationCount;
|
||||
::boost::winapi::ULONGLONG_ OtherOperationCount;
|
||||
::boost::winapi::ULONGLONG_ ReadTransferCount;
|
||||
::boost::winapi::ULONGLONG_ WriteTransferCount;
|
||||
::boost::winapi::ULONGLONG_ OtherTransferCount;
|
||||
} IO_COUNTERS_;
|
||||
|
||||
|
||||
typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION_
|
||||
{
|
||||
JOBOBJECT_BASIC_LIMIT_INFORMATION_ BasicLimitInformation;
|
||||
IO_COUNTERS_ IoInfo;
|
||||
::boost::winapi::SIZE_T_ ProcessMemoryLimit;
|
||||
::boost::winapi::SIZE_T_ JobMemoryLimit;
|
||||
::boost::winapi::SIZE_T_ PeakProcessMemoryUsed;
|
||||
::boost::winapi::SIZE_T_ PeakJobMemoryUsed;
|
||||
} JOBOBJECT_EXTENDED_LIMIT_INFORMATION_;
|
||||
|
||||
|
||||
/*BOOL WINAPI QueryInformationJobObject(
|
||||
_In_opt_ HANDLE hJob,
|
||||
_In_ JOBOBJECTINFOCLASS JobObjectInfoClass,
|
||||
_Out_ LPVOID lpJobObjectInfo,
|
||||
_In_ DWORD cbJobObjectInfoLength,
|
||||
_Out_opt_ LPDWORD lpReturnLength
|
||||
);
|
||||
*/
|
||||
typedef ::boost::winapi::BOOL_ (BOOST_WINAPI_WINAPI_CC *query_information_job_object_p)(
|
||||
::boost::winapi::HANDLE_,
|
||||
JOBOBJECTINFOCLASS_,
|
||||
void *,
|
||||
::boost::winapi::DWORD_,
|
||||
::boost::winapi::DWORD_ *);
|
||||
|
||||
|
||||
inline ::boost::winapi::BOOL_ query_information_job_object(
|
||||
::boost::winapi::HANDLE_ hJob,
|
||||
JOBOBJECTINFOCLASS_ JobObjectInfoClass,
|
||||
void *lpJobObjectInfo,
|
||||
::boost::winapi::DWORD_ cbJobObjectInfoLength,
|
||||
::boost::winapi::DWORD_ *lpReturnLength)
|
||||
{
|
||||
static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle(
|
||||
L"Kernel32.dll");
|
||||
static query_information_job_object_p f = reinterpret_cast<query_information_job_object_p>(::boost::winapi::get_proc_address(
|
||||
h, "QueryInformationJobObject"));
|
||||
|
||||
return (*f)(hJob, JobObjectInfoClass, lpJobObjectInfo,
|
||||
cbJobObjectInfoLength, lpReturnLength);
|
||||
}
|
||||
|
||||
/*BOOL WINAPI SetInformationJobObject(
|
||||
_In_ HANDLE hJob,
|
||||
_In_ JOBOBJECTINFOCLASS JobObjectInfoClass,
|
||||
_In_ LPVOID lpJobObjectInfo,
|
||||
_In_ DWORD cbJobObjectInfoLength
|
||||
);*/
|
||||
|
||||
typedef ::boost::winapi::BOOL_ (BOOST_WINAPI_WINAPI_CC *set_information_job_object_p)(
|
||||
::boost::winapi::HANDLE_,
|
||||
JOBOBJECTINFOCLASS_,
|
||||
void *,
|
||||
::boost::winapi::DWORD_);
|
||||
|
||||
}
|
||||
|
||||
inline ::boost::winapi::BOOL_ set_information_job_object(
|
||||
::boost::winapi::HANDLE_ hJob,
|
||||
JOBOBJECTINFOCLASS_ JobObjectInfoClass,
|
||||
void *lpJobObjectInfo,
|
||||
::boost::winapi::DWORD_ cbJobObjectInfoLength)
|
||||
{
|
||||
static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle(
|
||||
L"Kernel32.dll");
|
||||
static set_information_job_object_p f = reinterpret_cast<set_information_job_object_p>(::boost::winapi::get_proc_address(
|
||||
h, "SetInformationJobObject"));
|
||||
|
||||
return (*f)(hJob, JobObjectInfoClass, lpJobObjectInfo,
|
||||
cbJobObjectInfoLength);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
constexpr static ::boost::winapi::DWORD_ JOB_OBJECT_LIMIT_BREAKAWAY_OK_ = 0x00000800;
|
||||
|
||||
}}}}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_JOB_WORKAROUND_HPP_ */
|
||||
114
include/boost/process/v1/detail/windows/locale.hpp
Normal file
114
include/boost/process/v1/detail/windows/locale.hpp
Normal file
@@ -0,0 +1,114 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2008 Beman Dawes
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_LOCALE_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_LOCALE_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <locale>
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
#include <boost/winapi/file_management.hpp>
|
||||
#include <boost/winapi/character_code_conversion.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace process
|
||||
{
|
||||
BOOST_PROCESS_V1_INLINE namespace v1
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace windows
|
||||
{
|
||||
|
||||
//copied from boost.filesystem
|
||||
class windows_file_codecvt
|
||||
: public std::codecvt< wchar_t, char, std::mbstate_t >
|
||||
{
|
||||
public:
|
||||
explicit windows_file_codecvt(std::size_t refs = 0)
|
||||
: std::codecvt<wchar_t, char, std::mbstate_t>(refs) {}
|
||||
protected:
|
||||
|
||||
bool do_always_noconv() const noexcept override { return false; }
|
||||
|
||||
// seems safest to assume variable number of characters since we don't
|
||||
// actually know what codepage is active
|
||||
int do_encoding() const noexcept override { return 0; }
|
||||
|
||||
std::codecvt_base::result do_in(std::mbstate_t& state,
|
||||
const char* from, const char* from_end, const char*& from_next,
|
||||
wchar_t* to, wchar_t* to_end, wchar_t*& to_next) const override
|
||||
{
|
||||
boost::ignore_unused(state);
|
||||
|
||||
auto codepage =
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
::boost::winapi::AreFileApisANSI() ?
|
||||
::boost::winapi::CP_ACP_ :
|
||||
#endif
|
||||
::boost::winapi::CP_OEMCP_;
|
||||
|
||||
int count = 0;
|
||||
if ((count = ::boost::winapi::MultiByteToWideChar(codepage,
|
||||
::boost::winapi::MB_PRECOMPOSED_, from,
|
||||
static_cast<int>(from_end - from), to, static_cast<int>(to_end - to))) == 0)
|
||||
{
|
||||
return error; // conversion failed
|
||||
}
|
||||
|
||||
from_next = from_end;
|
||||
to_next = to + count;
|
||||
*to_next = L'\0';
|
||||
return ok;
|
||||
}
|
||||
|
||||
std::codecvt_base::result do_out(std::mbstate_t & state,
|
||||
const wchar_t* from, const wchar_t* from_end, const wchar_t*& from_next,
|
||||
char* to, char* to_end, char*& to_next) const override
|
||||
{
|
||||
boost::ignore_unused(state);
|
||||
auto codepage =
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
::boost::winapi::AreFileApisANSI() ?
|
||||
::boost::winapi::CP_ACP_ :
|
||||
#endif
|
||||
::boost::winapi::CP_OEMCP_;
|
||||
int count = 0;
|
||||
|
||||
|
||||
if ((count = ::boost::winapi::WideCharToMultiByte(codepage,
|
||||
::boost::winapi::WC_NO_BEST_FIT_CHARS_, from,
|
||||
static_cast<int>(from_end - from), to, static_cast<int>(to_end - to), 0, 0)) == 0)
|
||||
{
|
||||
return error; // conversion failed
|
||||
}
|
||||
|
||||
from_next = from_end;
|
||||
to_next = to + count;
|
||||
*to_next = '\0';
|
||||
return ok;
|
||||
}
|
||||
|
||||
std::codecvt_base::result do_unshift(std::mbstate_t&,
|
||||
char* /*from*/, char* /*to*/, char* & /*next*/) const override { return ok; }
|
||||
|
||||
int do_length(std::mbstate_t&,
|
||||
const char* /*from*/, const char* /*from_end*/, std::size_t /*max*/) const override { return 0; }
|
||||
|
||||
int do_max_length() const noexcept override { return 0; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_LOCALE_HPP_ */
|
||||
45
include/boost/process/v1/detail/windows/null_in.hpp
Normal file
45
include/boost/process/v1/detail/windows/null_in.hpp
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// 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_WINDOWS_INITIALIZERS_NULL_IN_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_NULL_IN_HPP
|
||||
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/winapi/handle_info.hpp>
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
#include <boost/process/v1/detail/windows/file_descriptor.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
struct null_in : public ::boost::process::v1::detail::handler_base, ::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
file_descriptor source{"NUL", file_descriptor::read};
|
||||
|
||||
::boost::winapi::HANDLE_ get_used_handles() const { return source.handle(); }
|
||||
|
||||
|
||||
public:
|
||||
template <class WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
boost::winapi::SetHandleInformation(source.handle(),
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
e.startup_info.hStdInput = source.handle();
|
||||
e.startup_info.dwFlags |= boost::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
};
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
78
include/boost/process/v1/detail/windows/null_out.hpp
Normal file
78
include/boost/process/v1/detail/windows/null_out.hpp
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// 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_WINDOWS_INITIALIZERS_NULL_OUT_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_NULL_OUT_HPP
|
||||
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/winapi/handle_info.hpp>
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
#include <boost/process/v1/detail/windows/file_descriptor.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
template<int p1, int p2>
|
||||
struct null_out : public ::boost::process::v1::detail::handler_base, ::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
file_descriptor sink {"NUL", file_descriptor::write}; //works because it gets destroyed AFTER launch.
|
||||
|
||||
::boost::winapi::HANDLE_ get_used_handles() const { return sink.handle(); }
|
||||
|
||||
template <typename WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &e) const;
|
||||
};
|
||||
|
||||
template<>
|
||||
template<typename WindowsExecutor>
|
||||
void null_out<1,-1>::on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
boost::winapi::SetHandleInformation(sink.handle(),
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
e.startup_info.hStdOutput = sink.handle();
|
||||
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename WindowsExecutor>
|
||||
void null_out<2,-1>::on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
boost::winapi::SetHandleInformation(sink.handle(),
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
e.startup_info.hStdError = sink.handle();
|
||||
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename WindowsExecutor>
|
||||
void null_out<1,2>::on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
boost::winapi::SetHandleInformation(sink.handle(),
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
e.startup_info.hStdOutput = sink.handle();
|
||||
e.startup_info.hStdError = sink.handle();
|
||||
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
48
include/boost/process/v1/detail/windows/on_exit.hpp
Normal file
48
include/boost/process/v1/detail/windows/on_exit.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_
|
||||
#define BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_
|
||||
|
||||
#include <boost/process/v1/async.hpp>
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
#include <boost/process/v1/detail/windows/async_handler.hpp>
|
||||
#include <boost/asio/execution.hpp>
|
||||
#include <system_error>
|
||||
#include <functional>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
|
||||
template<typename Tuple>
|
||||
inline asio::io_context& get_io_context(const Tuple & tup);
|
||||
|
||||
namespace windows {
|
||||
|
||||
struct on_exit_ : boost::process::v1::detail::windows::async_handler
|
||||
{
|
||||
std::function<void(int, const std::error_code&)> handler;
|
||||
on_exit_(const std::function<void(int, const std::error_code&)> & handler) : handler(handler)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
std::function<void(int, const std::error_code&)> on_exit_handler(Executor& exec)
|
||||
{
|
||||
auto v = boost::asio::prefer(boost::process::v1::detail::get_io_context(exec.seq).get_executor(),
|
||||
boost::asio::execution::outstanding_work.tracked);
|
||||
auto handler_ = this->handler;
|
||||
return [v, handler_](int exit_code, const std::error_code & ec)
|
||||
{
|
||||
handler_(static_cast<int>(exit_code), ec);
|
||||
};
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}}}}
|
||||
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_ */
|
||||
94
include/boost/process/v1/detail/windows/pipe_in.hpp
Normal file
94
include/boost/process/v1/detail/windows/pipe_in.hpp
Normal file
@@ -0,0 +1,94 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// 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_WINDOWS_INITIALIZERS_PIPE_IN_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_PIPE_IN_HPP
|
||||
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
struct pipe_in : public ::boost::process::v1::detail::handler_base, ::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
::boost::winapi::HANDLE_ handle;
|
||||
|
||||
::boost::winapi::HANDLE_ get_used_handles() const { return handle; }
|
||||
|
||||
pipe_in(::boost::winapi::HANDLE_ handle) : handle(handle) {}
|
||||
|
||||
template<typename T> //async_pipe
|
||||
pipe_in(T & p) : handle(p.native_source())
|
||||
{
|
||||
p.assign_source(::boost::winapi::INVALID_HANDLE_VALUE_);
|
||||
}
|
||||
|
||||
template <class WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
boost::winapi::SetHandleInformation(handle,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
e.startup_info.hStdInput = handle;
|
||||
e.startup_info.dwFlags |= boost::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
template<typename WindowsExecutor>
|
||||
void on_error(WindowsExecutor &, const std::error_code &) const
|
||||
{
|
||||
::boost::winapi::CloseHandle(handle);
|
||||
}
|
||||
|
||||
template<typename WindowsExecutor>
|
||||
void on_success(WindowsExecutor &) const
|
||||
{
|
||||
::boost::winapi::CloseHandle(handle);
|
||||
}
|
||||
};
|
||||
|
||||
class async_pipe;
|
||||
|
||||
struct async_pipe_in : public pipe_in
|
||||
{
|
||||
async_pipe &pipe;
|
||||
|
||||
template<typename AsyncPipe>
|
||||
async_pipe_in(AsyncPipe & p) : pipe_in(p.native_source()), pipe(p)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Pipe, typename Executor>
|
||||
static void close(Pipe & pipe, Executor &)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
std::move(pipe).source().close(ec);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor & exec, const std::error_code &)
|
||||
{
|
||||
close(pipe, exec);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_success(Executor &exec)
|
||||
{
|
||||
close(pipe, exec);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
125
include/boost/process/v1/detail/windows/pipe_out.hpp
Normal file
125
include/boost/process/v1/detail/windows/pipe_out.hpp
Normal file
@@ -0,0 +1,125 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_PIPE_OUT_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_PIPE_OUT_HPP
|
||||
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
template<int p1, int p2>
|
||||
struct pipe_out : public ::boost::process::v1::detail::handler_base, ::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
::boost::winapi::HANDLE_ handle;
|
||||
|
||||
::boost::winapi::HANDLE_ get_used_handles() const { return handle; }
|
||||
|
||||
pipe_out(::boost::winapi::HANDLE_ handle) : handle(handle) {}
|
||||
template<typename T>
|
||||
pipe_out(T & p) : handle(p.native_sink())
|
||||
{
|
||||
p.assign_sink(::boost::winapi::INVALID_HANDLE_VALUE_);
|
||||
}
|
||||
|
||||
template<typename WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &e) const;
|
||||
|
||||
template<typename WindowsExecutor>
|
||||
void on_error(WindowsExecutor &, const std::error_code &) const
|
||||
{
|
||||
::boost::winapi::CloseHandle(handle);
|
||||
}
|
||||
|
||||
template<typename WindowsExecutor>
|
||||
void on_success(WindowsExecutor &) const
|
||||
{
|
||||
::boost::winapi::CloseHandle(handle);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
template<typename WindowsExecutor>
|
||||
void pipe_out<1,-1>::on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
boost::winapi::SetHandleInformation(handle,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
e.startup_info.hStdOutput = handle;
|
||||
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename WindowsExecutor>
|
||||
void pipe_out<2,-1>::on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
boost::winapi::SetHandleInformation(handle,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
|
||||
e.startup_info.hStdError = handle;
|
||||
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename WindowsExecutor>
|
||||
void pipe_out<1,2>::on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
boost::winapi::SetHandleInformation(handle,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
e.startup_info.hStdOutput = handle;
|
||||
e.startup_info.hStdError = handle;
|
||||
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
|
||||
template<int p1, int p2>
|
||||
struct async_pipe_out : public pipe_out<p1, p2>
|
||||
{
|
||||
async_pipe &pipe;
|
||||
template<typename AsyncPipe>
|
||||
async_pipe_out(AsyncPipe & p) : pipe_out<p1, p2>(p.native_sink()), pipe(p)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Pipe, typename Executor>
|
||||
static void close(Pipe & pipe, Executor &)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
std::move(pipe).sink().close(ec);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor & exec, const std::error_code &)
|
||||
{
|
||||
close(pipe, exec);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_success(Executor &exec)
|
||||
{
|
||||
close(pipe, exec);
|
||||
}
|
||||
};
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
84
include/boost/process/v1/detail/windows/search_path.hpp
Normal file
84
include/boost/process/v1/detail/windows/search_path.hpp
Normal file
@@ -0,0 +1,84 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// 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_WINDOWS_SEARCH_PATH_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_SEARCH_PATH_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/filesystem.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstdlib>
|
||||
#include <boost/winapi/shell.hpp>
|
||||
#include <boost/process/v1/environment.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
inline boost::process::v1::filesystem::path search_path(
|
||||
const boost::process::v1::filesystem::path &filename,
|
||||
const std::vector<boost::process::v1::filesystem::path> &path)
|
||||
{
|
||||
const ::boost::process::v1::wnative_environment ne{};
|
||||
typedef typename ::boost::process::v1::wnative_environment::const_entry_type value_type;
|
||||
const auto id = L"PATHEXT";
|
||||
|
||||
auto itr = std::find_if(ne.cbegin(), ne.cend(),
|
||||
[&](const value_type & e)
|
||||
{return id == ::boost::to_upper_copy(e.get_name(), ::boost::process::v1::detail::process_locale());});
|
||||
|
||||
std::vector<std::wstring> extensions_in;
|
||||
if (itr != ne.cend())
|
||||
extensions_in = itr->to_vector();
|
||||
|
||||
std::vector<std::wstring> extensions((extensions_in.size() * 2) + 1);
|
||||
|
||||
auto it_ex = extensions.begin();
|
||||
it_ex++;
|
||||
it_ex = std::transform(extensions_in.begin(), extensions_in.end(), it_ex,
|
||||
[](const std::wstring & ws){return boost::to_lower_copy(ws, ::boost::process::v1::detail::process_locale());});
|
||||
|
||||
std::transform(extensions_in.begin(), extensions_in.end(), it_ex,
|
||||
[](const std::wstring & ws){return boost::to_upper_copy(ws, ::boost::process::v1::detail::process_locale());});
|
||||
|
||||
|
||||
std::copy(std::make_move_iterator(extensions_in.begin()), std::make_move_iterator(extensions_in.end()), extensions.begin() + 1);
|
||||
|
||||
|
||||
for (auto & ext : extensions)
|
||||
boost::to_lower(ext);
|
||||
|
||||
for (const boost::process::v1::filesystem::path & pp_ : path)
|
||||
{
|
||||
auto p = pp_ / filename;
|
||||
for (boost::process::v1::filesystem::path ext : extensions)
|
||||
{
|
||||
boost::process::v1::filesystem::path pp_ext = p;
|
||||
pp_ext += ext;
|
||||
#if defined(BOOST_PROCESS_USE_STD_FS)
|
||||
std::error_code ec;
|
||||
#else
|
||||
boost::system::error_code ec;
|
||||
#endif
|
||||
bool file = boost::process::v1::filesystem::is_regular_file(pp_ext, ec);
|
||||
if (!ec && file &&
|
||||
::boost::winapi::sh_get_file_info(pp_ext.native().c_str(), 0, 0, 0, ::boost::winapi::SHGFI_EXETYPE_))
|
||||
{
|
||||
return pp_ext;
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
53
include/boost/process/v1/detail/windows/shell_path.hpp
Normal file
53
include/boost/process/v1/detail/windows/shell_path.hpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// 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_WINDOWS_SHELL_PATH_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_SHELL_PATH_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <system_error>
|
||||
#include <boost/process/v1/filesystem.hpp>
|
||||
#include <boost/winapi/basic_types.hpp>
|
||||
#include <boost/winapi/get_system_directory.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
inline boost::process::v1::filesystem::path shell_path()
|
||||
{
|
||||
::boost::winapi::WCHAR_ sysdir[260];
|
||||
unsigned int size = ::boost::winapi::get_system_directory(sysdir, sizeof(sysdir));
|
||||
if (!size)
|
||||
throw_last_error("GetSystemDirectory() failed");
|
||||
|
||||
boost::process::v1::filesystem::path p = sysdir;
|
||||
return p / "cmd.exe";
|
||||
}
|
||||
|
||||
inline boost::process::v1::filesystem::path shell_path(std::error_code &ec) noexcept
|
||||
{
|
||||
|
||||
::boost::winapi::WCHAR_ sysdir[260];
|
||||
unsigned int size = ::boost::winapi::get_system_directory(sysdir, sizeof(sysdir));
|
||||
boost::process::v1::filesystem::path p;
|
||||
if (!size)
|
||||
ec = std::error_code(
|
||||
::boost::winapi::GetLastError(),
|
||||
std::system_category());
|
||||
else
|
||||
{
|
||||
ec.clear();
|
||||
p = sysdir;
|
||||
p /= "cmd.exe";
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
46
include/boost/process/v1/detail/windows/show_window.hpp
Normal file
46
include/boost/process/v1/detail/windows/show_window.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_SHOW_WINDOW_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_SHOW_WINDOW_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/winapi/show_window.hpp>
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
template<::boost::winapi::WORD_ Flags>
|
||||
struct show_window : ::boost::process::v1::detail::handler_base
|
||||
{
|
||||
template <class WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESHOWWINDOW_;
|
||||
e.startup_info.wShowWindow |= Flags;
|
||||
}
|
||||
};
|
||||
|
||||
struct create_no_window_ : public ::boost::process::v1::detail::handler_base
|
||||
{
|
||||
template <class Executor>
|
||||
void on_setup(Executor &exec) const
|
||||
{
|
||||
exec.creation_flags |= ::boost::winapi::CREATE_NO_WINDOW_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
|
||||
36
include/boost/process/v1/detail/windows/start_dir.hpp
Normal file
36
include/boost/process/v1/detail/windows/start_dir.hpp
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_START_DIR_HPP
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_START_DIR_HPP
|
||||
|
||||
#include <string>
|
||||
#include <boost/process/v1/detail/windows/handler.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
template<typename Char>
|
||||
struct start_dir_init : handler_base_ext
|
||||
{
|
||||
start_dir_init(const std::basic_string<Char> &s) : s_(s) {}
|
||||
|
||||
template <class Executor>
|
||||
void on_setup(Executor& exec) const
|
||||
{
|
||||
exec.work_dir = s_.c_str();
|
||||
}
|
||||
|
||||
const std::basic_string<Char> &str() const {return s_;}
|
||||
private:
|
||||
std::basic_string<Char> s_;
|
||||
};
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
44
include/boost/process/v1/detail/windows/terminate.hpp
Normal file
44
include/boost/process/v1/detail/windows/terminate.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// 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_WINDOWS_TERMINATE_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_TERMINATE_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <system_error>
|
||||
#include <cstdlib>
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/winapi/get_last_error.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
struct child_handle;
|
||||
|
||||
inline void terminate(child_handle &p, std::error_code &ec) noexcept
|
||||
{
|
||||
if (!::boost::winapi::TerminateProcess(p.process_handle(), EXIT_FAILURE))
|
||||
ec = boost::process::v1::detail::get_last_error();
|
||||
else
|
||||
{
|
||||
ec.clear();
|
||||
::boost::winapi::CloseHandle(p.proc_info.hProcess);
|
||||
p.proc_info.hProcess = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
}
|
||||
}
|
||||
|
||||
inline void terminate(child_handle &p)
|
||||
{
|
||||
std::error_code ec;
|
||||
terminate(p, ec);
|
||||
boost::process::v1::detail::throw_error(ec, "TerminateProcess() failed in terminate");
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
123
include/boost/process/v1/detail/windows/wait_for_exit.hpp
Normal file
123
include/boost/process/v1/detail/windows/wait_for_exit.hpp
Normal file
@@ -0,0 +1,123 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_WAIT_FOR_EXIT_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_WAIT_FOR_EXIT_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <system_error>
|
||||
#include <boost/winapi/synchronization.hpp>
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/process/v1/detail/windows/child_handle.hpp>
|
||||
#include <chrono>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
inline void wait(child_handle &p, int & exit_code, std::error_code &ec) noexcept
|
||||
{
|
||||
::boost::winapi::DWORD_ _exit_code = 1;
|
||||
|
||||
if (::boost::winapi::WaitForSingleObject(p.process_handle(),
|
||||
::boost::winapi::infinite) == ::boost::winapi::wait_failed)
|
||||
ec = std::error_code(
|
||||
::boost::winapi::GetLastError(),
|
||||
std::system_category());
|
||||
else if (!::boost::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
|
||||
ec = std::error_code(
|
||||
::boost::winapi::GetLastError(),
|
||||
std::system_category());
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
::boost::winapi::CloseHandle(p.proc_info.hProcess);
|
||||
p.proc_info.hProcess = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
exit_code = static_cast<int>(_exit_code);
|
||||
}
|
||||
|
||||
inline void wait(child_handle &p, int & exit_code)
|
||||
{
|
||||
std::error_code ec;
|
||||
wait(p, exit_code, ec);
|
||||
boost::process::v1::detail::throw_error(ec, "wait error");
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
inline bool wait_until(
|
||||
child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::time_point<Clock, Duration>& timeout_time,
|
||||
std::error_code &ec) noexcept
|
||||
{
|
||||
std::chrono::milliseconds ms =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
timeout_time - Clock::now());
|
||||
|
||||
::boost::winapi::DWORD_ wait_code;
|
||||
wait_code = ::boost::winapi::WaitForSingleObject(p.process_handle(),
|
||||
static_cast<::boost::winapi::DWORD_>(ms.count()));
|
||||
|
||||
if (wait_code == ::boost::winapi::wait_failed)
|
||||
ec = std::error_code(
|
||||
::boost::winapi::GetLastError(),
|
||||
std::system_category());
|
||||
else if (wait_code == ::boost::winapi::wait_timeout)
|
||||
return false;
|
||||
|
||||
::boost::winapi::DWORD_ _exit_code;
|
||||
if (!::boost::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
|
||||
ec = std::error_code(
|
||||
::boost::winapi::GetLastError(),
|
||||
std::system_category());
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
exit_code = static_cast<int>(_exit_code);
|
||||
::boost::winapi::CloseHandle(p.proc_info.hProcess);
|
||||
p.proc_info.hProcess = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
return true;
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
inline bool wait_until(
|
||||
child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::time_point<Clock, Duration>& timeout_time)
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = wait_until(p, exit_code, timeout_time, ec);
|
||||
boost::process::v1::detail::throw_error(ec, "wait_until error");
|
||||
return b;
|
||||
}
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::duration<Rep, Period>& rel_time,
|
||||
std::error_code &ec) noexcept
|
||||
{
|
||||
return wait_until(p, exit_code, std::chrono::steady_clock::now() + rel_time, ec);
|
||||
}
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
child_handle &p,
|
||||
int & exit_code,
|
||||
const std::chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = wait_for(p, exit_code, rel_time, ec);
|
||||
boost::process::v1::detail::throw_error(ec, "wait_for error");
|
||||
return b;
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
132
include/boost/process/v1/detail/windows/wait_group.hpp
Normal file
132
include/boost/process/v1/detail/windows/wait_group.hpp
Normal file
@@ -0,0 +1,132 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_WAIT_GROUP_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_WAIT_GROUP_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/windows/group_handle.hpp>
|
||||
#include <boost/winapi/jobs.hpp>
|
||||
#include <boost/winapi/wait.hpp>
|
||||
#include <chrono>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace windows {
|
||||
|
||||
struct group_handle;
|
||||
|
||||
|
||||
inline bool wait_impl(const group_handle & p, std::error_code & ec, std::chrono::system_clock::rep wait_time)
|
||||
{
|
||||
::boost::winapi::DWORD_ completion_code;
|
||||
::boost::winapi::ULONG_PTR_ completion_key;
|
||||
::boost::winapi::LPOVERLAPPED_ overlapped;
|
||||
|
||||
auto start_time = std::chrono::system_clock::now();
|
||||
|
||||
while (workaround::get_queued_completion_status(
|
||||
p._io_port, &completion_code,
|
||||
&completion_key, &overlapped, static_cast<::boost::winapi::DWORD_>(wait_time)))
|
||||
{
|
||||
if (reinterpret_cast<::boost::winapi::HANDLE_>(completion_key) == p._job_object &&
|
||||
completion_code == workaround::JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO_)
|
||||
{
|
||||
|
||||
//double check, could be a different handle from a child
|
||||
workaround::JOBOBJECT_BASIC_ACCOUNTING_INFORMATION_ info;
|
||||
if (!workaround::query_information_job_object(
|
||||
p._job_object,
|
||||
workaround::JobObjectBasicAccountingInformation_,
|
||||
static_cast<void *>(&info),
|
||||
sizeof(info), nullptr))
|
||||
{
|
||||
ec = get_last_error();
|
||||
return false;
|
||||
}
|
||||
else if (info.ActiveProcesses == 0)
|
||||
return false; //correct, nothing left.
|
||||
}
|
||||
//reduce the remaining wait time -> in case interrupted by something else
|
||||
if (wait_time != static_cast<int>(::boost::winapi::infinite))
|
||||
{
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
|
||||
wait_time -= static_cast<std::chrono::system_clock::rep>(diff.count());
|
||||
start_time = now;
|
||||
if (wait_time <= 0)
|
||||
return true; //timeout with other source
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
auto ec_ = get_last_error();
|
||||
if (ec_.value() == ::boost::winapi::wait_timeout)
|
||||
return true; //timeout
|
||||
|
||||
ec = ec_;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void wait(const group_handle &p, std::error_code &ec)
|
||||
{
|
||||
wait_impl(p, ec, ::boost::winapi::infinite);
|
||||
}
|
||||
|
||||
inline void wait(const group_handle &p)
|
||||
{
|
||||
std::error_code ec;
|
||||
wait(p, ec);
|
||||
boost::process::v1::detail::throw_error(ec, "wait error");
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
inline bool wait_until(
|
||||
const group_handle &p,
|
||||
const std::chrono::time_point<Clock, Duration>& timeout_time,
|
||||
std::error_code &ec)
|
||||
{
|
||||
std::chrono::milliseconds ms =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
timeout_time - Clock::now());
|
||||
|
||||
auto timeout = wait_impl(p, ec, ms.count());
|
||||
return !ec && !timeout;
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
inline bool wait_until(
|
||||
const group_handle &p,
|
||||
const std::chrono::time_point<Clock, Duration>& timeout_time)
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = wait_until(p, timeout_time, ec);
|
||||
boost::process::v1::detail::throw_error(ec, "wait_until error");
|
||||
return b;
|
||||
}
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
const group_handle &p,
|
||||
const std::chrono::duration<Rep, Period>& rel_time,
|
||||
std::error_code &ec)
|
||||
{
|
||||
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time);
|
||||
auto timeout = wait_impl(p, ec, ms.count());
|
||||
return !ec && !timeout;
|
||||
}
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
const group_handle &p,
|
||||
const std::chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = wait_for(p, rel_time, ec);
|
||||
boost::process::v1::detail::throw_error(ec, "wait_for error");
|
||||
return b;
|
||||
}
|
||||
|
||||
}}}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_WAIT_GROUP_HPP_ */
|
||||
Reference in New Issue
Block a user