整理
This commit is contained in:
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