diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2017-09-13 11:08:07 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2017-09-13 11:09:00 +0900 |
commit | b5c87084afaef42b2d058f68091be31988a6a874 (patch) | |
tree | adef9a65870a41181687e11d57fdf98e7629de3c /boost/process/detail/windows | |
parent | 34bd32e225e2a8a94104489b31c42e5801cc1f4a (diff) | |
download | boost-b5c87084afaef42b2d058f68091be31988a6a874.tar.gz boost-b5c87084afaef42b2d058f68091be31988a6a874.tar.bz2 boost-b5c87084afaef42b2d058f68091be31988a6a874.zip |
Imported Upstream version 1.64.0upstream/1.64.0
Change-Id: Id9212edd016dd55f21172c427aa7894d1d24148b
Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
Diffstat (limited to 'boost/process/detail/windows')
37 files changed, 4002 insertions, 0 deletions
diff --git a/boost/process/detail/windows/asio_fwd.hpp b/boost/process/detail/windows/asio_fwd.hpp new file mode 100644 index 0000000000..f7667db101 --- /dev/null +++ b/boost/process/detail/windows/asio_fwd.hpp @@ -0,0 +1,71 @@ +// 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 <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; +class io_service; + +template <typename Handler> +class basic_yield_context; + +namespace windows { + +class stream_handle_service; + +template <typename StreamHandleService> +class basic_stream_handle; + +typedef basic_stream_handle<stream_handle_service> stream_handle; + + +class object_handle_service; + +template <typename ObjectHandleService> +class basic_object_handle; + +typedef basic_object_handle<object_handle_service> object_handle; + +} //windows +} //asio + +namespace process { 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::detail::windows::async_pipe; + +} // process +} // boost + + + + +#endif /* BOOST_PROCESS_DETAIL_WINDOWS_ASIO_FWD_HPP_ */ diff --git a/boost/process/detail/windows/async_handler.hpp b/boost/process/detail/windows/async_handler.hpp new file mode 100644 index 0000000000..197c264126 --- /dev/null +++ b/boost/process/detail/windows/async_handler.hpp @@ -0,0 +1,40 @@ +// Copyright (c) 2016 Klemens D. Morgenstern
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+ + +#ifndef BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_
+#define BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_
+ +#include <boost/process/detail/windows/handler.hpp>
+#include <type_traits>
+ +namespace boost { namespace process { namespace detail { namespace windows {
+ +struct require_io_service {};
+ +struct async_handler : handler_base_ext, require_io_service
+{
+};
+ +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_service : std::is_base_of<require_io_service, T> {};
+ +template<typename T>
+struct does_require_io_service<T&> : std::is_base_of<require_io_service, T> {};
+ +template<typename T>
+struct does_require_io_service<const T&> : std::is_base_of<require_io_service, T> {};
+ + +}}}}
+ +#endif /* BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_ */
diff --git a/boost/process/detail/windows/async_in.hpp b/boost/process/detail/windows/async_in.hpp new file mode 100644 index 0000000000..4c498612d3 --- /dev/null +++ b/boost/process/detail/windows/async_in.hpp @@ -0,0 +1,105 @@ +// 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/detail/winapi/process.hpp>
+#include <boost/detail/winapi/handles.hpp>
+#include <boost/detail/winapi/handle_info.hpp>
+#include <boost/detail/winapi/error_codes.hpp>
+ +#include <boost/asio/write.hpp>
+#include <boost/process/detail/handler_base.hpp>
+#include <boost/process/detail/windows/async_handler.hpp>
+#include <boost/process/detail/windows/asio_fwd.hpp>
+#include <boost/process/async_pipe.hpp>
+#include <memory>
+#include <future>
+ + +namespace boost { namespace process { namespace detail { namespace windows {
+ + +template<typename Buffer>
+struct async_in_buffer : ::boost::process::detail::windows::handler_base_ext,
+ ::boost::process::detail::windows::require_io_service
+{
+ 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::async_pipe> pipe;
+ + async_in_buffer(Buffer & buf) : buf(buf)
+ {
+ }
+ template <typename Executor>
+ inline void on_success(Executor&)
+ {
+ auto pipe = this->pipe;
+ + if (this->promise)
+ {
+ auto promise = this->promise;
+ + boost::asio::async_write(*pipe, buf,
+ [promise](const boost::system::error_code & ec, std::size_t)
+ {
+ if (ec && (ec.value() != ::boost::detail::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::detail::winapi::CloseHandle(pipe->native_source());
+ }
+ + template <typename WindowsExecutor>
+ void on_setup(WindowsExecutor &exec)
+ {
+ if (!pipe)
+ pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));
+ + ::boost::detail::winapi::HANDLE_ source_handle = std::move(*pipe).source().native_handle();
+ + boost::detail::winapi::SetHandleInformation(source_handle,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_);
+ + exec.startup_info.hStdInput = source_handle;
+ exec.startup_info.dwFlags |= boost::detail::winapi::STARTF_USESTDHANDLES_;
+ exec.inherit_handles = true;
+ }
+};
+ + +}}}}
+ +#endif
diff --git a/boost/process/detail/windows/async_out.hpp b/boost/process/detail/windows/async_out.hpp new file mode 100644 index 0000000000..435f56ebd6 --- /dev/null +++ b/boost/process/detail/windows/async_out.hpp @@ -0,0 +1,176 @@ +// 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/detail/winapi/process.hpp>
+#include <boost/detail/winapi/handles.hpp>
+#include <boost/detail/winapi/handle_info.hpp>
+#include <boost/asio/read.hpp>
+#include <boost/process/detail/handler_base.hpp>
+#include <boost/process/detail/windows/asio_fwd.hpp>
+#include <boost/detail/winapi/error_codes.hpp>
+ +#include <istream>
+#include <memory>
+#include <exception>
+#include <future>
+ + +namespace boost { namespace process { 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::detail::winapi::SetHandleInformation(handle,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_);
+ + e.startup_info.hStdOutput = handle;
+ e.startup_info.dwFlags |= ::boost::detail::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::detail::winapi::SetHandleInformation(handle,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_);
+ + + e.startup_info.hStdError = handle;
+ e.startup_info.dwFlags |= ::boost::detail::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::detail::winapi::SetHandleInformation(handle,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_);
+ + e.startup_info.hStdOutput = handle;
+ e.startup_info.hStdError = handle;
+ e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
+ e.inherit_handles = true;
+}
+ +template<int p1, int p2, typename Buffer>
+struct async_out_buffer : ::boost::process::detail::windows::handler_base_ext,
+ ::boost::process::detail::windows::require_io_service
+{
+ Buffer & buf;
+ + std::shared_ptr<boost::process::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::async_pipe>(get_io_service(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::detail::windows::handler_base_ext,
+ ::boost::process::detail::windows::require_io_service
+{
+ std::shared_ptr<boost::process::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>();
+ + + 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::detail::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;
+ 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::async_pipe>(get_io_service(exec.seq));
+ + apply_out_handles(exec, std::move(*pipe).sink().native_handle(),
+ std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
+ }
+};
+ + +}}}}
+ +#endif
diff --git a/boost/process/detail/windows/async_pipe.hpp b/boost/process/detail/windows/async_pipe.hpp new file mode 100644 index 0000000000..ca4f3559d0 --- /dev/null +++ b/boost/process/detail/windows/async_pipe.hpp @@ -0,0 +1,415 @@ +// 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/detail/winapi/basic_types.hpp> +#include <boost/detail/winapi/pipes.hpp> +#include <boost/detail/winapi/handles.hpp> +#include <boost/detail/winapi/file_management.hpp> +#include <boost/detail/winapi/get_last_error.hpp> +#include <boost/detail/winapi/access_rights.hpp> +#include <boost/detail/winapi/process.hpp> +#include <boost/process/detail/windows/basic_pipe.hpp> +#include <boost/asio/windows/stream_handle.hpp> +#include <system_error> +#include <string> + +namespace boost { namespace process { namespace detail { namespace windows { + +inline std::string make_pipe_name() +{ + std::string name = "\\\\.\\pipe\\boost_process_auto_pipe_"; + + auto pid = ::boost::detail::winapi::GetCurrentProcessId(); + + static unsigned long long cnt = 0; + name += std::to_string(pid); + name += "_"; + name += std::to_string(cnt++); + + return name; +} + +class async_pipe +{ + ::boost::asio::windows::stream_handle _source; + ::boost::asio::windows::stream_handle _sink ; +public: + typedef ::boost::detail::winapi::HANDLE_ native_handle_type; + typedef ::boost::asio::windows::stream_handle handle_type; + + inline async_pipe(boost::asio::io_service & ios, + const std::string & name = make_pipe_name()) + : async_pipe(ios, ios, name) {} + + inline async_pipe(boost::asio::io_service & ios_source, + boost::asio::io_service & ios_sink, + const std::string & name = make_pipe_name()); + + inline async_pipe(const async_pipe& rhs); + async_pipe(async_pipe&& rhs) : _source(std::move(rhs._source)), _sink(std::move(rhs._sink)) + { + rhs._source.assign (::boost::detail::winapi::INVALID_HANDLE_VALUE_); + rhs._sink .assign (::boost::detail::winapi::INVALID_HANDLE_VALUE_); + } + template<class CharT, class Traits = std::char_traits<CharT>> + explicit async_pipe(::boost::asio::io_service & ios_source, + ::boost::asio::io_service & 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_service & 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() + { + if (_sink .native() != ::boost::detail::winapi::INVALID_HANDLE_VALUE_) + ::boost::detail::winapi::CloseHandle(_sink.native()); + if (_source.native() != ::boost::detail::winapi::INVALID_HANDLE_VALUE_) + ::boost::detail::winapi::CloseHandle(_source.native()); + } + + 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_io_service()); + } + if (_source.is_open()) + { + _source.close(); + _source = handle_type(_source.get_io_service()); + } + } + void close(boost::system::error_code & ec) + { + if (_sink.is_open()) + { + _sink.close(ec); + _sink = handle_type(_sink.get_io_service()); + } + if (_source.is_open()) + { + _source.close(ec); + _source = handle_type(_source.get_io_service()); + } + } + + bool is_open() const + { + return _sink.is_open() || _source.is_open(); + } + void async_close() + { + if (_sink.is_open()) + _sink.get_io_service(). post([this]{_sink.close();}); + if (_source.is_open()) + _source.get_io_service().post([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); + } + + native_handle_type native_source() const {return const_cast<boost::asio::windows::stream_handle&>(_source).native();} + native_handle_type native_sink () const {return const_cast<boost::asio::windows::stream_handle&>(_sink ).native();} + + 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) + { + _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) + { + _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_service& ios) && + { + ::boost::asio::windows::stream_handle stolen(ios, _source.native_handle()); + _source.assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_); + return stolen; + } + handle_type sink (::boost::asio::io_service& ios) && + { + ::boost::asio::windows::stream_handle stolen(ios, _sink.native_handle()); + _sink.assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_); + return stolen; + } + + handle_type source(::boost::asio::io_service& ios) const & + { + auto proc = ::boost::detail::winapi::GetCurrentProcess(); + + ::boost::detail::winapi::HANDLE_ source; + auto source_in = const_cast<handle_type&>(_source).native(); + if (source_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_) + source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + else if (!::boost::detail::winapi::DuplicateHandle( + proc, source_in, proc, &source, 0, + static_cast<::boost::detail::winapi::BOOL_>(true), + ::boost::detail::winapi::DUPLICATE_SAME_ACCESS_)) + throw_last_error("Duplicate Pipe Failed"); + + return ::boost::asio::windows::stream_handle(ios, source); + } + handle_type sink (::boost::asio::io_service& ios) const & + { + auto proc = ::boost::detail::winapi::GetCurrentProcess(); + + ::boost::detail::winapi::HANDLE_ sink; + auto sink_in = const_cast<handle_type&>(_sink).native(); + if (sink_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_) + sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + else if (!::boost::detail::winapi::DuplicateHandle( + proc, sink_in, proc, &sink, 0, + static_cast<::boost::detail::winapi::BOOL_>(true), + ::boost::detail::winapi::DUPLICATE_SAME_ACCESS_)) + throw_last_error("Duplicate Pipe Failed"); + + return ::boost::asio::windows::stream_handle(ios, sink); + } +}; + + + +async_pipe::async_pipe(const async_pipe& p) : + _source(const_cast<handle_type&>(p._source).get_io_service()), + _sink (const_cast<handle_type&>(p._sink).get_io_service()) +{ + auto proc = ::boost::detail::winapi::GetCurrentProcess(); + + ::boost::detail::winapi::HANDLE_ source; + ::boost::detail::winapi::HANDLE_ sink; + + //cannot get the handle from a const object. + auto source_in = const_cast<handle_type&>(p._source).native(); + auto sink_in = const_cast<handle_type&>(p._sink).native(); + + if (source_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_) + source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + else if (!::boost::detail::winapi::DuplicateHandle( + proc, source_in, proc, &source, 0, + static_cast<::boost::detail::winapi::BOOL_>(true), + ::boost::detail::winapi::DUPLICATE_SAME_ACCESS_)) + throw_last_error("Duplicate Pipe Failed"); + + if (sink_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_) + sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + else if (!::boost::detail::winapi::DuplicateHandle( + proc, sink_in, proc, &sink, 0, + static_cast<::boost::detail::winapi::BOOL_>(true), + ::boost::detail::winapi::DUPLICATE_SAME_ACCESS_)) + throw_last_error("Duplicate Pipe Failed"); + + _source.assign(source); + _sink. assign(sink); +} + + +async_pipe::async_pipe(boost::asio::io_service & ios_source, + boost::asio::io_service & ios_sink, + const std::string & name) : _source(ios_source), _sink(ios_sink) +{ + static constexpr int FILE_FLAG_OVERLAPPED_ = 0x40000000; //temporary + + ::boost::detail::winapi::HANDLE_ source = ::boost::detail::winapi::create_named_pipe( + name.c_str(), + ::boost::detail::winapi::PIPE_ACCESS_INBOUND_ + | FILE_FLAG_OVERLAPPED_, //write flag + 0, 1, 8192, 8192, 0, nullptr); + + + if (source == boost::detail::winapi::INVALID_HANDLE_VALUE_) + ::boost::process::detail::throw_last_error("create_named_pipe(" + name + ") failed"); + + _source.assign(source); + + ::boost::detail::winapi::HANDLE_ sink = boost::detail::winapi::create_file( + name.c_str(), + ::boost::detail::winapi::GENERIC_WRITE_, 0, nullptr, + ::boost::detail::winapi::OPEN_EXISTING_, + FILE_FLAG_OVERLAPPED_, //to allow read + nullptr); + + if (sink == ::boost::detail::winapi::INVALID_HANDLE_VALUE_) + ::boost::process::detail::throw_last_error("create_file() failed"); + + _sink.assign(sink); +} + +async_pipe& async_pipe::operator=(const async_pipe & p) +{ + auto proc = ::boost::detail::winapi::GetCurrentProcess(); + + ::boost::detail::winapi::HANDLE_ source; + ::boost::detail::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); + + if (source_in.native() == ::boost::detail::winapi::INVALID_HANDLE_VALUE_) + source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + else if (!::boost::detail::winapi::DuplicateHandle( + proc, source_in.native(), proc, &source, 0, + static_cast<::boost::detail::winapi::BOOL_>(true), + ::boost::detail::winapi::DUPLICATE_SAME_ACCESS_)) + throw_last_error("Duplicate Pipe Failed"); + + if (sink_in.native() == ::boost::detail::winapi::INVALID_HANDLE_VALUE_) + sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + else if (!::boost::detail::winapi::DuplicateHandle( + proc, sink_in.native(), proc, &sink, 0, + static_cast<::boost::detail::winapi::BOOL_>(true), + ::boost::detail::winapi::DUPLICATE_SAME_ACCESS_)) + throw_last_error("Duplicate Pipe Failed"); + + //so we also assign the io_service + _source = ::boost::asio::windows::stream_handle(source_in.get_io_service(), source); + _sink = ::boost::asio::windows::stream_handle(source_in.get_io_service(), sink); + + return *this; +} + +async_pipe& async_pipe::operator=(async_pipe && rhs) +{ + if (_source.native_handle() != ::boost::detail::winapi::INVALID_HANDLE_VALUE_) + ::boost::detail::winapi::CloseHandle(_source.native()); + + if (_sink.native_handle() != ::boost::detail::winapi::INVALID_HANDLE_VALUE_) + ::boost::detail::winapi::CloseHandle(_sink.native()); + + _source.assign(rhs._source.native_handle()); + _sink .assign(rhs._sink .native_handle()); + rhs._source.assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_); + rhs._sink .assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_); + return *this; +} + +template<class CharT, class Traits> +async_pipe::operator basic_pipe<CharT, Traits>() const +{ + auto proc = ::boost::detail::winapi::GetCurrentProcess(); + + ::boost::detail::winapi::HANDLE_ source; + ::boost::detail::winapi::HANDLE_ sink; + + //cannot get the handle from a const object. + auto source_in = const_cast<::boost::asio::windows::stream_handle &>(_source).native(); + auto sink_in = const_cast<::boost::asio::windows::stream_handle &>(_sink).native(); + + if (source_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_) + source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + else if (!::boost::detail::winapi::DuplicateHandle( + proc, source_in, proc, &source, 0, + static_cast<::boost::detail::winapi::BOOL_>(true), + ::boost::detail::winapi::DUPLICATE_SAME_ACCESS_)) + throw_last_error("Duplicate Pipe Failed"); + + if (sink_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_) + sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + else if (!::boost::detail::winapi::DuplicateHandle( + proc, sink_in, proc, &sink, 0, + static_cast<::boost::detail::winapi::BOOL_>(true), + ::boost::detail::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_ */ diff --git a/boost/process/detail/windows/basic_cmd.hpp b/boost/process/detail/windows/basic_cmd.hpp new file mode 100644 index 0000000000..176a052368 --- /dev/null +++ b/boost/process/detail/windows/basic_cmd.hpp @@ -0,0 +1,164 @@ +// 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/shell.hpp>
+#include <boost/process/detail/windows/handler.hpp>
+ +#include <vector>
+#include <string>
+#include <iterator>
+ + +namespace boost
+{
+namespace process
+{
+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
+ {
+ boost::replace_all(st, "\"", "\\\"");
+ + auto it = std::find(st.begin(), st.end(), ' ');
+ + if (it != st.end())//contains spaces.
+ {
+ st.insert(st.begin(), '"');
+ st += '"';
+ }
+ }
+ + for (auto & arg : data)
+ {
+ boost::replace_all(arg, "\"", "\\\"");
+ + auto it = std::find(arg.begin(), arg.end(), ' ');//contains space?
+ if (it != arg.end())//ok, contains spaces.
+ {
+ //the first one is put directly onto the output,
+ //because then I don't have to copy the whole string
+ arg.insert(arg.begin(), '"');
+ arg += '"'; //thats the post one.
+ }
+ + if (!st.empty())//first one does not need a preceeding space
+ st += ' ';
+ + st += arg;
+ }
+ return st;
+}
+ +inline std::wstring build_args(const std::wstring & exe, std::vector<std::wstring> && data)
+{
+ std::wstring st = exe;
+ for (auto & arg : data)
+ {
+ boost::replace_all(arg, L"\"", L"\\\"");
+ + auto it = std::find(arg.begin(), arg.end(), ' ');//contains space?
+ if (it != arg.end())//ok, contains spaces.
+ {
+ //the first one is put directly onto the output,
+ //because then I don't have to copy the whole string
+ arg.insert(arg.begin(), L'"');
+ arg += L'"'; //thats the post one.
+ }
+ + if (!st.empty())//first one does not need a preceeding 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()), 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_));
+ }
+ + static std:: string get_shell(char) {return shell(). string(codecvt()); }
+ static std::wstring get_shell(wchar_t) {return shell().wstring(codecvt());}
+ + 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_ */
diff --git a/boost/process/detail/windows/basic_pipe.hpp b/boost/process/detail/windows/basic_pipe.hpp new file mode 100644 index 0000000000..2471e60f6d --- /dev/null +++ b/boost/process/detail/windows/basic_pipe.hpp @@ -0,0 +1,225 @@ +// 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/detail/winapi/basic_types.hpp> +#include <boost/detail/winapi/error_codes.hpp> +#include <boost/detail/winapi/pipes.hpp> +#include <boost/detail/winapi/handles.hpp> +#include <boost/detail/winapi/file_management.hpp> +#include <boost/detail/winapi/get_last_error.hpp> +#include <boost/detail/winapi/access_rights.hpp> +#include <boost/detail/winapi/process.hpp> +#include <boost/process/detail/windows/compare_handles.hpp> +#include <system_error> +#include <string> + + +namespace boost { namespace process { namespace detail { namespace windows { + +template<class CharT, class Traits = std::char_traits<CharT>> +class basic_pipe +{ + ::boost::detail::winapi::HANDLE_ _source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + ::boost::detail::winapi::HANDLE_ _sink = ::boost::detail::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::detail::winapi::HANDLE_ native_handle_type; + + explicit basic_pipe(::boost::detail::winapi::HANDLE_ source, ::boost::detail::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::detail::winapi::INVALID_HANDLE_VALUE_; + lhs._sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + } + inline basic_pipe& operator=(const basic_pipe& p); + inline basic_pipe& operator=(basic_pipe&& lhs); + ~basic_pipe() + { + if (_sink != ::boost::detail::winapi::INVALID_HANDLE_VALUE_) + ::boost::detail::winapi::CloseHandle(_sink); + if (_source != ::boost::detail::winapi::INVALID_HANDLE_VALUE_) + ::boost::detail::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::detail::winapi::CreatePipe(&_source, &_sink, nullptr, 0)) + throw_last_error("CreatePipe() failed"); + + } + + int_type write(const char_type * data, int_type count) + { + ::boost::detail::winapi::DWORD_ write_len; + if (!::boost::detail::winapi::WriteFile( + _sink, data, count * sizeof(char_type), &write_len, nullptr + )) + { + auto ec = ::boost::process::detail::get_last_error(); + if ((ec.value() == ::boost::detail::winapi::ERROR_BROKEN_PIPE_) || + (ec.value() == ::boost::detail::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::detail::winapi::DWORD_ read_len; + if (!::boost::detail::winapi::ReadFile( + _source, data, count * sizeof(char_type), &read_len, nullptr + )) + { + auto ec = ::boost::process::detail::get_last_error(); + if ((ec.value() == ::boost::detail::winapi::ERROR_BROKEN_PIPE_) || + (ec.value() == ::boost::detail::winapi::ERROR_NO_DATA_)) + return 0; + else + throw process_error(ec, "ReadFile failed"); + } + return static_cast<int_type>(read_len); + } + + bool is_open() + { + return (_source != ::boost::detail::winapi::INVALID_HANDLE_VALUE_) || + (_sink != ::boost::detail::winapi::INVALID_HANDLE_VALUE_); + } + + void close() + { + ::boost::detail::winapi::CloseHandle(_source); + ::boost::detail::winapi::CloseHandle(_sink); + _source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + _sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + } +}; + +template<class Char, class Traits> +basic_pipe<Char, Traits>::basic_pipe(const basic_pipe & p) +{ + auto proc = ::boost::detail::winapi::GetCurrentProcess(); + + if (p._source == ::boost::detail::winapi::INVALID_HANDLE_VALUE_) + _source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + else if (!::boost::detail::winapi::DuplicateHandle( + proc, p._source, proc, &_source, 0, + static_cast<::boost::detail::winapi::BOOL_>(true), + ::boost::detail::winapi::DUPLICATE_SAME_ACCESS_)) + throw_last_error("Duplicate Pipe Failed"); + + if (p._sink == ::boost::detail::winapi::INVALID_HANDLE_VALUE_) + _sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + else if (!::boost::detail::winapi::DuplicateHandle( + proc, p._sink, proc, &_sink, 0, + static_cast<::boost::detail::winapi::BOOL_>(true), + ::boost::detail::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 + + ::boost::detail::winapi::HANDLE_ source = ::boost::detail::winapi::create_named_pipe( + name.c_str(), + ::boost::detail::winapi::PIPE_ACCESS_INBOUND_ + | FILE_FLAG_OVERLAPPED_, //write flag + 0, 1, 8192, 8192, 0, nullptr); + + if (source == boost::detail::winapi::INVALID_HANDLE_VALUE_) + ::boost::process::detail::throw_last_error("create_named_pipe() failed"); + + ::boost::detail::winapi::HANDLE_ sink = boost::detail::winapi::create_file( + name.c_str(), + ::boost::detail::winapi::GENERIC_WRITE_, 0, nullptr, + OPEN_EXISTING_, + FILE_FLAG_OVERLAPPED_, //to allow read + nullptr); + + if (sink == ::boost::detail::winapi::INVALID_HANDLE_VALUE_) + ::boost::process::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::detail::winapi::GetCurrentProcess(); + + if (p._source == ::boost::detail::winapi::INVALID_HANDLE_VALUE_) + _source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + else if (!::boost::detail::winapi::DuplicateHandle( + proc, p._source, proc, &_source, 0, + static_cast<::boost::detail::winapi::BOOL_>(true), + ::boost::detail::winapi::DUPLICATE_SAME_ACCESS_)) + throw_last_error("Duplicate Pipe Failed"); + + if (p._sink == ::boost::detail::winapi::INVALID_HANDLE_VALUE_) + _sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + else if (!::boost::detail::winapi::DuplicateHandle( + proc, p._sink, proc, &_sink, 0, + static_cast<::boost::detail::winapi::BOOL_>(true), + ::boost::detail::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::detail::winapi::INVALID_HANDLE_VALUE_) + ::boost::detail::winapi::CloseHandle(_source); + + if (_sink != ::boost::detail::winapi::INVALID_HANDLE_VALUE_) + ::boost::detail::winapi::CloseHandle(_sink); + + _source = lhs._source; + _sink = lhs._sink; + lhs._source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + lhs._sink = ::boost::detail::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 diff --git a/boost/process/detail/windows/child_handle.hpp b/boost/process/detail/windows/child_handle.hpp new file mode 100644 index 0000000000..4e809be9fc --- /dev/null +++ b/boost/process/detail/windows/child_handle.hpp @@ -0,0 +1,98 @@ +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling +// Copyright (c) 2009 Boris Schaeling +// Copyright (c) 2010 Felipe Tanus, Boris Schaeling +// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_PROCESS_WINDOWS_CHILD_HPP +#define BOOST_PROCESS_WINDOWS_CHILD_HPP + +#include <boost/move/move.hpp> +#include <boost/detail/winapi/handles.hpp> +#include <boost/detail/winapi/process.hpp> +#include <boost/detail/winapi/jobs.hpp> + +namespace boost { namespace process { namespace detail { namespace windows { + +typedef int pid_t; + +struct child_handle +{ + ::boost::detail::winapi::PROCESS_INFORMATION_ proc_info{nullptr, nullptr, 0,0}; + + explicit child_handle(const ::boost::detail::winapi::PROCESS_INFORMATION_ &pi) : + proc_info(pi) + {} + + explicit child_handle(pid_t pid) : + proc_info{nullptr, nullptr, 0,0} + { + auto h = ::boost::detail::winapi::OpenProcess( + ::boost::detail::winapi::PROCESS_ALL_ACCESS_, + static_cast<::boost::detail::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::detail::winapi::CloseHandle(proc_info.hProcess); + ::boost::detail::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::detail::winapi::invalid_handle_value; + c.proc_info.hThread = ::boost::detail::winapi::invalid_handle_value; + } + child_handle &operator=(const child_handle & c) = delete; + child_handle &operator=(child_handle && c) + { + ::boost::detail::winapi::CloseHandle(proc_info.hProcess); + ::boost::detail::winapi::CloseHandle(proc_info.hThread); + proc_info = c.proc_info; + c.proc_info.hProcess = ::boost::detail::winapi::invalid_handle_value; + c.proc_info.hThread = ::boost::detail::winapi::invalid_handle_value; + return *this; + } + + pid_t id() const + { + return static_cast<int>(proc_info.dwProcessId); + } + + typedef ::boost::detail::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::detail::winapi::INVALID_HANDLE_VALUE_); + } + bool in_group() const + { + ::boost::detail::winapi::BOOL_ value; + if (!::boost::detail::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::detail::winapi::BOOL_ value; + if (!::boost::detail::winapi::IsProcessInJob(proc_info.hProcess, nullptr, &value)) + ec = get_last_error(); + return value!=0; + } +}; + +}}}} + +#endif diff --git a/boost/process/detail/windows/close_in.hpp b/boost/process/detail/windows/close_in.hpp new file mode 100644 index 0000000000..5100564b4c --- /dev/null +++ b/boost/process/detail/windows/close_in.hpp @@ -0,0 +1,31 @@ +// 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/detail/winapi/process.hpp> +#include <boost/detail/winapi/handles.hpp> +#include <boost/process/detail/handler_base.hpp> + +namespace boost { namespace process { namespace detail { namespace windows { + +struct close_in : public ::boost::process::detail::handler_base +{ + template <class WindowsExecutor> + void on_setup(WindowsExecutor &e) const + { + e.startup_info.hStdInput = boost::detail::winapi::INVALID_HANDLE_VALUE_; + e.startup_info.dwFlags |= boost::detail::winapi::STARTF_USESTDHANDLES_; + } +}; + +}}}} + +#endif diff --git a/boost/process/detail/windows/close_out.hpp b/boost/process/detail/windows/close_out.hpp new file mode 100644 index 0000000000..dc3de412fc --- /dev/null +++ b/boost/process/detail/windows/close_out.hpp @@ -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_INITIALIZERS_CLOSE_OUT_HPP +#define BOOST_PROCESS_WINDOWS_INITIALIZERS_CLOSE_OUT_HPP + +#include <boost/detail/winapi/process.hpp> +#include <boost/detail/winapi/handles.hpp> +#include <boost/process/detail/handler_base.hpp> + +namespace boost { namespace process { namespace detail { namespace windows { + +template<int p1, int p2> +struct close_out : public ::boost::process::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::detail::winapi::INVALID_HANDLE_VALUE_; + e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_; +} + +template<> +template<typename WindowsExecutor> +void close_out<2,-1>::on_setup(WindowsExecutor &e) const +{ + e.startup_info.hStdError = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_; +} + +template<> +template<typename WindowsExecutor> +void close_out<1,2>::on_setup(WindowsExecutor &e) const +{ + e.startup_info.hStdOutput = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + e.startup_info.hStdError = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_; +} + +}}}} + +#endif diff --git a/boost/process/detail/windows/cmd.hpp b/boost/process/detail/windows/cmd.hpp new file mode 100644 index 0000000000..c76c08a546 --- /dev/null +++ b/boost/process/detail/windows/cmd.hpp @@ -0,0 +1,49 @@ +// 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
+{
+namespace detail
+{
+namespace windows
+{
+ +template<typename CharType>
+struct cmd_setter_ : ::boost::process::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_ */
diff --git a/boost/process/detail/windows/compare_handles.hpp b/boost/process/detail/windows/compare_handles.hpp new file mode 100644 index 0000000000..1eafd43209 --- /dev/null +++ b/boost/process/detail/windows/compare_handles.hpp @@ -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/detail/winapi/handles.hpp> +#include <boost/detail/winapi/file_management.hpp> +#include <boost/process/detail/config.hpp> + +namespace boost { namespace process { namespace detail { namespace windows { + +inline bool compare_handles(boost::detail::winapi::HANDLE_ lhs, boost::detail::winapi::HANDLE_ rhs) +{ + if ( (lhs == ::boost::detail::winapi::INVALID_HANDLE_VALUE_) + || (rhs == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)) + return false; + + if (lhs == rhs) + return true; + + ::boost::detail::winapi::BY_HANDLE_FILE_INFORMATION_ lhs_info{0,{0,0},{0,0},{0,0},0,0,0,0,0,0}; + ::boost::detail::winapi::BY_HANDLE_FILE_INFORMATION_ rhs_info{0,{0,0},{0,0},{0,0},0,0,0,0,0,0}; + + if (!::boost::detail::winapi::GetFileInformationByHandle(lhs, &lhs_info)) + ::boost::process::detail::throw_last_error("GetFileInformationByHandle"); + + if (!::boost::detail::winapi::GetFileInformationByHandle(rhs, &rhs_info)) + ::boost::process::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_ */ diff --git a/boost/process/detail/windows/env_init.hpp b/boost/process/detail/windows/env_init.hpp new file mode 100644 index 0000000000..036a29809f --- /dev/null +++ b/boost/process/detail/windows/env_init.hpp @@ -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/detail/winapi/error_codes.hpp> +#include <boost/detail/winapi/process.hpp> + + +#include <boost/process/detail/config.hpp> +#include <boost/process/detail/handler_base.hpp> +#include <boost/process/environment.hpp> + +namespace boost { namespace process { namespace detail { namespace windows { + +template<typename Char> +struct env_init : public ::boost::process::detail::handler_base +{ + boost::process::basic_environment<Char> env; + + env_init(boost::process::basic_environment<Char> && env) : env(std::move(env)) {}; + env_init(const boost::process::basic_environment<Char> & env) : env(env) {}; + + constexpr static ::boost::detail::winapi::DWORD_ creation_flag(char) {return 0u;} + constexpr static ::boost::detail::winapi::DWORD_ creation_flag(wchar_t) + { + return ::boost::detail::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::detail::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_ */ diff --git a/boost/process/detail/windows/environment.hpp b/boost/process/detail/windows/environment.hpp new file mode 100644 index 0000000000..b73da1bd42 --- /dev/null +++ b/boost/process/detail/windows/environment.hpp @@ -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/detail/winapi/error_codes.hpp>
+#include <boost/detail/winapi/environment.hpp>
+#include <boost/process/detail/config.hpp>
+#include <boost/detail/winapi/get_current_process.hpp>
+#include <boost/detail/winapi/get_current_process_id.hpp>
+#include <algorithm>
+#include <boost/process/locale.hpp>
+ +namespace boost { namespace process { namespace detail { namespace windows {
+ +template<typename Char>
+class native_environment_impl
+{
+ static void _deleter(Char* p) {boost::detail::winapi::free_environment_strings(p);};
+ std::unique_ptr<Char[], void(*)(Char*)> _buf{boost::detail::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::detail::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::detail::winapi::get_environment_variable(id, buf, sizeof(buf));
+ if (size == 0) //failed
+ {
+ auto err = ::boost::detail::winapi::GetLastError();
+ if (err == ::boost::detail::winapi::ERROR_ENVVAR_NOT_FOUND_)//well, then we consider that an empty value
+ return "";
+ 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::detail::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::detail::throw_last_error("GetEnvironmentVariable() failed");
+ else
+ return std::basic_string<Char>(
+ buf.data(), buf.data()+ size + 1);
+ + }
+ + }
+ return std::basic_string<Char>(buf, buf+size+1);
+}
+ +template<typename Char>
+inline void native_environment_impl<Char>::set(const pointer_type id, const pointer_type value)
+{
+ boost::detail::winapi::set_environment_variable(id, value);
+}
+ +template<typename Char>
+inline void native_environment_impl<Char>::reset(const pointer_type id)
+{
+ boost::detail::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::codecvt_type & cv = ::boost::process::codecvt())
+ : _data(::boost::process::detail::convert(rhs._data, cv))
+ {
+ }
+ + template<typename CharR>
+ basic_environment_impl & operator=(const basic_environment_impl<CharR>& rhs)
+ {
+ _data = ::boost::process::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 behing 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 (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's 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')
+ end++;
+ + end ++; //to point behind the last null-char
+ + _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::detail::winapi::GetCurrentProcessId();}
+inline void* native_handle() {return boost::detail::winapi::GetCurrentProcess(); }
+ +typedef void* native_handle_t;
+ +}
+ +}
+}
+}
+ + + + +#endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_ */
diff --git a/boost/process/detail/windows/executor.hpp b/boost/process/detail/windows/executor.hpp new file mode 100644 index 0000000000..30b1e46369 --- /dev/null +++ b/boost/process/detail/windows/executor.hpp @@ -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/detail/child_decl.hpp> +#include <boost/process/detail/windows/is_running.hpp> +#include <boost/process/detail/traits.hpp> +#include <boost/process/error.hpp> +#include <boost/fusion/algorithm/iteration/for_each.hpp> +#include <boost/detail/winapi/handles.hpp> +#include <boost/detail/winapi/process.hpp> +#include <boost/none.hpp> +#include <system_error> +#include <memory> +#include <atomic> +#include <cstring> + +namespace boost { namespace process { + +namespace detail { namespace windows { + +template<typename CharType> struct startup_info; +#if !defined( BOOST_NO_ANSI_APIS ) + +template<> struct startup_info<char> +{ + typedef ::boost::detail::winapi::STARTUPINFOA_ type; +}; +#endif + +template<> struct startup_info<wchar_t> +{ + typedef ::boost::detail::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::detail::winapi::STARTUPINFOEXA_ type; +}; +#endif + +template<> struct startup_info_ex<wchar_t> +{ + typedef ::boost::detail::winapi::STARTUPINFOEXW_ type; +}; + + +#endif + +#if ( BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 ) + +template<typename CharT> +struct startup_info_impl +{ + ::boost::detail::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::detail::winapi::invalid_handle_value, + ::boost::detail::winapi::invalid_handle_value, + ::boost::detail::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::detail::winapi::EXTENDED_STARTUPINFO_PRESENT_; + } +}; + + +#else + +template<typename CharT> +struct startup_info_impl +{ + typedef typename startup_info<CharT>::type startup_info_t; + + ::boost::detail::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::detail::winapi::invalid_handle_value, + ::boost::detail::winapi::invalid_handle_value, + ::boost::detail::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::detail::has_error_handler<Sequence>::type has_error_handler; + typedef typename ::boost::process::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::detail::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::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::detail::winapi::LPSECURITY_ATTRIBUTES_ proc_attrs = nullptr; + ::boost::detail::winapi::LPSECURITY_ATTRIBUTES_ thread_attrs = nullptr; + ::boost::detail::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::detail::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 diff --git a/boost/process/detail/windows/file_descriptor.hpp b/boost/process/detail/windows/file_descriptor.hpp new file mode 100644 index 0000000000..337e634781 --- /dev/null +++ b/boost/process/detail/windows/file_descriptor.hpp @@ -0,0 +1,104 @@ +// 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/detail/winapi/basic_types.hpp>
+#include <boost/detail/winapi/handles.hpp>
+#include <boost/detail/winapi/file_management.hpp>
+#include <string>
+#include <boost/filesystem/path.hpp>
+ +namespace boost { namespace process { namespace detail { namespace windows {
+ +struct file_descriptor
+{
+ enum mode_t
+ {
+ read = 1,
+ write = 2,
+ read_write = 3
+ };
+ static ::boost::detail::winapi::DWORD_ desired_access(mode_t mode)
+ {
+ switch(mode)
+ {
+ case read:
+ return ::boost::detail::winapi::GENERIC_READ_;
+ case write:
+ return ::boost::detail::winapi::GENERIC_WRITE_;
+ case read_write:
+ return ::boost::detail::winapi::GENERIC_READ_
+ | ::boost::detail::winapi::GENERIC_WRITE_;
+ default:
+ return 0u;
+ }
+ }
+ + file_descriptor() = default;
+ file_descriptor(const boost::filesystem::path& p, mode_t mode = read_write)
+ : file_descriptor(p.native(), mode)
+ {
+ }
+ + file_descriptor(const std::string & path , mode_t mode = read_write)
+ : file_descriptor(path.c_str(), mode) {}
+ 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)
+ : _handle(
+ ::boost::detail::winapi::create_file(
+ path,
+ desired_access(mode),
+ ::boost::detail::winapi::FILE_SHARE_READ_ |
+ ::boost::detail::winapi::FILE_SHARE_WRITE_,
+ nullptr,
+ ::boost::detail::winapi::OPEN_ALWAYS_,
+ + ::boost::detail::winapi::FILE_ATTRIBUTE_NORMAL_,
+ nullptr
+ ))
+ {
+ + }
+ file_descriptor(const wchar_t * path, mode_t mode = read_write)
+ : _handle(
+ ::boost::detail::winapi::create_file(
+ path,
+ desired_access(mode),
+ ::boost::detail::winapi::FILE_SHARE_READ_ |
+ ::boost::detail::winapi::FILE_SHARE_WRITE_,
+ nullptr,
+ ::boost::detail::winapi::OPEN_ALWAYS_,
+ + ::boost::detail::winapi::FILE_ATTRIBUTE_NORMAL_,
+ nullptr
+ ))
+{
+ +}
+ file_descriptor(const file_descriptor & ) = delete;
+ file_descriptor(file_descriptor && ) = default;
+ + file_descriptor& operator=(const file_descriptor & ) = delete;
+ file_descriptor& operator=(file_descriptor && ) = default;
+ + ~file_descriptor()
+ {
+ if (_handle != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
+ ::boost::detail::winapi::CloseHandle(_handle);
+ }
+ + ::boost::detail::winapi::HANDLE_ handle() const { return _handle;}
+ +private:
+ ::boost::detail::winapi::HANDLE_ _handle = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
+};
+ +}}}}
+ +#endif /* BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_ */
diff --git a/boost/process/detail/windows/file_in.hpp b/boost/process/detail/windows/file_in.hpp new file mode 100644 index 0000000000..b092d278c2 --- /dev/null +++ b/boost/process/detail/windows/file_in.hpp @@ -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_DETAIL_WINDOWS_FILE_IN_HPP
+#define BOOST_PROCESS_DETAIL_WINDOWS_FILE_IN_HPP
+ +#include <boost/detail/winapi/process.hpp>
+#include <boost/detail/winapi/handles.hpp>
+#include <boost/process/detail/handler_base.hpp>
+#include <boost/process/detail/windows/file_descriptor.hpp>
+#include <io.h>
+ +namespace boost { namespace process { namespace detail { namespace windows {
+ +struct file_in : public ::boost::process::detail::handler_base
+{
+ file_descriptor file;
+ ::boost::detail::winapi::HANDLE_ handle = file.handle();
+ + template<typename T>
+ file_in(T&& t) : file(std::forward<T>(t), file_descriptor::read) {}
+ file_in(FILE * f) : handle(reinterpret_cast<::boost::detail::winapi::HANDLE_>(_get_osfhandle(_fileno(f)))) {}
+ + template <class WindowsExecutor>
+ void on_setup(WindowsExecutor &e) const
+ {
+ boost::detail::winapi::SetHandleInformation(handle,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_);
+ e.startup_info.hStdInput = handle;
+ e.startup_info.dwFlags |= boost::detail::winapi::STARTF_USESTDHANDLES_;
+ e.inherit_handles = true;
+ }
+};
+ +}}}}
+ +#endif
diff --git a/boost/process/detail/windows/file_out.hpp b/boost/process/detail/windows/file_out.hpp new file mode 100644 index 0000000000..2e2cc198cf --- /dev/null +++ b/boost/process/detail/windows/file_out.hpp @@ -0,0 +1,77 @@ +// 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/detail/winapi/process.hpp>
+#include <boost/detail/winapi/handles.hpp>
+#include <boost/detail/winapi/handle_info.hpp>
+#include <boost/process/detail/handler_base.hpp>
+#include <boost/process/detail/windows/file_descriptor.hpp>
+ +namespace boost { namespace process { namespace detail { namespace windows {
+ +template<int p1, int p2>
+struct file_out : public ::boost::process::detail::handler_base
+{
+ file_descriptor file;
+ ::boost::detail::winapi::HANDLE_ handle = file.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::detail::winapi::SetHandleInformation(handle,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_);
+ + e.startup_info.hStdOutput = handle;
+ e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
+ e.inherit_handles = true;
+}
+ +template<>
+template<typename WindowsExecutor>
+void file_out<2,-1>::on_setup(WindowsExecutor &e) const
+{
+ boost::detail::winapi::SetHandleInformation(handle,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_);
+ + e.startup_info.hStdError = handle;
+ e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
+ e.inherit_handles = true;
+}
+ +template<>
+template<typename WindowsExecutor>
+void file_out<1,2>::on_setup(WindowsExecutor &e) const
+{
+ boost::detail::winapi::SetHandleInformation(handle,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_);
+ + e.startup_info.hStdOutput = handle;
+ e.startup_info.hStdError = handle;
+ e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
+ e.inherit_handles = true;
+}
+ +}}}}
+ +#endif
diff --git a/boost/process/detail/windows/group_handle.hpp b/boost/process/detail/windows/group_handle.hpp new file mode 100644 index 0000000000..e289263cad --- /dev/null +++ b/boost/process/detail/windows/group_handle.hpp @@ -0,0 +1,191 @@ +// 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/detail/windows/handler.hpp> +#include <boost/detail/winapi/jobs.hpp> +#include <boost/process/detail/windows/child_handle.hpp> +#include <boost/process/detail/windows/job_workaround.hpp> +#include <system_error> + +namespace boost { namespace process { namespace detail { namespace windows { + +inline bool break_away_enabled(::boost::detail::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::detail::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::detail::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; + } + + +} + + +struct group_handle +{ + ::boost::detail::winapi::HANDLE_ _job_object; + + typedef ::boost::detail::winapi::HANDLE_ handle_t; + handle_t handle() const { return _job_object; } + + explicit group_handle(handle_t h) : + _job_object(h) + { + enable_break_away(_job_object); + } + + + group_handle() : group_handle(::boost::detail::winapi::CreateJobObjectA(nullptr, nullptr)) + { + + } + ~group_handle() + { + ::boost::detail::winapi::CloseHandle(_job_object); + } + group_handle(const group_handle & c) = delete; + group_handle(group_handle && c) : _job_object(c._job_object) + { + c._job_object = ::boost::detail::winapi::invalid_handle_value; + } + group_handle &operator=(const group_handle & c) = delete; + group_handle &operator=(group_handle && c) + { + + ::boost::detail::winapi::CloseHandle(_job_object); + _job_object = c._job_object; + c._job_object = ::boost::detail::winapi::invalid_handle_value; + return *this; + } + + void add(handle_t proc) + { + if (!::boost::detail::winapi::AssignProcessToJobObject(_job_object, proc)) + throw_last_error(); + } + void add(handle_t proc, std::error_code & ec) noexcept + { + if (!::boost::detail::winapi::AssignProcessToJobObject(_job_object, proc)) + ec = get_last_error(); + } + + bool has(handle_t proc) + { + ::boost::detail::winapi::BOOL_ is; + if (!::boost::detail::winapi::IsProcessInJob(proc, _job_object, &is)) + throw_last_error(); + + return is!=0; + } + bool has(handle_t proc, std::error_code & ec) noexcept + { + ::boost::detail::winapi::BOOL_ is; + if (!::boost::detail::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::detail::winapi::TerminateJobObject(p.handle(), EXIT_FAILURE)) + boost::process::detail::throw_last_error("TerminateJobObject() failed"); +} + +inline void terminate(const group_handle &p, std::error_code &ec) noexcept +{ + if (!::boost::detail::winapi::TerminateJobObject(p.handle(), EXIT_FAILURE)) + ec = boost::process::detail::get_last_error(); + else + ec.clear(); +} + +inline bool in_group() +{ + ::boost::detail::winapi::BOOL_ res; + if (!::boost::detail::winapi::IsProcessInJob(boost::detail::winapi::GetCurrentProcess(), nullptr, &res)) + throw_last_error("IsProcessInJob failed"); + + return res!=0; +} + + + +}}}} + + +#endif /* BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_ */ diff --git a/boost/process/detail/windows/group_ref.hpp b/boost/process/detail/windows/group_ref.hpp new file mode 100644 index 0000000000..1f62c4dcb0 --- /dev/null +++ b/boost/process/detail/windows/group_ref.hpp @@ -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_DETAIL_WINDOWS_GROUP_REF_HPP_ +#define BOOST_PROCESS_DETAIL_WINDOWS_GROUP_REF_HPP_ + +#include <boost/process/detail/config.hpp> +#include <boost/process/detail/windows/group_handle.hpp> +#include <boost/detail/winapi/process.hpp> +#include <boost/process/detail/windows/handler.hpp> + +namespace boost { namespace process { + +namespace detail { namespace windows { + + + +struct group_ref : handler_base_ext +{ + ::boost::detail::winapi::HANDLE_ 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::detail::winapi::CREATE_BREAKAWAY_FROM_JOB_; + } + + + template <class Executor> + void on_success(Executor& exec) const + { + if (!::boost::detail::winapi::AssignProcessToJobObject(handle, exec.proc_info.hProcess)) + exec.set_error(::boost::process::detail::get_last_error(), + "AssignProcessToJobObject() failed."); + + } + +}; + +}}}} + + +#endif /* BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_ */ diff --git a/boost/process/detail/windows/handler.hpp b/boost/process/detail/windows/handler.hpp new file mode 100644 index 0000000000..f8ef89f016 --- /dev/null +++ b/boost/process/detail/windows/handler.hpp @@ -0,0 +1,20 @@ +// 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/detail/handler_base.hpp>
+ +namespace boost { namespace process { namespace detail { namespace windows {
+ +//does not extend anything.
+struct handler_base_ext : handler_base {};
+ +}}}}
+ + + +#endif /* BOOST_PROCESS_DETAIL_WINDOWS_HANDLER_HPP_ */
diff --git a/boost/process/detail/windows/io_service_ref.hpp b/boost/process/detail/windows/io_service_ref.hpp new file mode 100644 index 0000000000..6b61c7ca2c --- /dev/null +++ b/boost/process/detail/windows/io_service_ref.hpp @@ -0,0 +1,160 @@ +// 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_SERVICE_REF_HPP_
+#define BOOST_PROCESS_WINDOWS_IO_SERVICE_REF_HPP_
+ +#include <boost/process/detail/handler_base.hpp>
+#include <boost/process/detail/windows/async_handler.hpp>
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/windows/object_handle.hpp>
+#include <boost/detail/winapi/process.hpp>
+#include <boost/detail/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 { 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_service_ref : boost::process::detail::handler_base
+{
+ + io_service_ref(boost::asio::io_service & ios)
+ : ios(ios)
+ {
+ }
+ boost::asio::io_service &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::detail::winapi::PROCESS_INFORMATION_ & proc = exec.proc_info;
+ auto this_proc = ::boost::detail::winapi::GetCurrentProcess();
+ + auto proc_in = proc.hProcess;;
+ ::boost::detail::winapi::HANDLE_ process_handle;
+ + if (!::boost::detail::winapi::DuplicateHandle(
+ this_proc, proc_in, this_proc, &process_handle, 0,
+ static_cast<::boost::detail::winapi::BOOL_>(true),
+ ::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
+ + exec.set_error(::boost::process::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);
+ + 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_service & ios, void * handle,
+ const std::shared_ptr<std::atomic<int>> &exit_status)
+ : funcs(std::move(funcs)),
+ handle(new boost::asio::windows::object_handle(ios, 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::detail::winapi::DWORD_ code;
+ ::boost::detail::winapi::GetExitCodeProcess(handle->native(), &code);
+ exit_status->store(code);
+ + for (auto & func : funcs)
+ func(code, ec);
+ }
+ + };
+ +private:
+ boost::asio::io_service &ios;
+};
+ +}}}}
+ +#endif /* BOOST_PROCESS_WINDOWS_IO_SERVICE_REF_HPP_ */
diff --git a/boost/process/detail/windows/is_running.hpp b/boost/process/detail/windows/is_running.hpp new file mode 100644 index 0000000000..66cc6837ae --- /dev/null +++ b/boost/process/detail/windows/is_running.hpp @@ -0,0 +1,64 @@ +// Copyright (c) 2106 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/detail/config.hpp> +#include <system_error> +#include <cstdlib> +#include <boost/detail/winapi/process.hpp> + +namespace boost { namespace process { namespace detail { namespace windows { + +constexpr static ::boost::detail::winapi::DWORD_ still_active = 259; + + +struct child_handle; + +inline bool is_running(const child_handle &p, int & exit_code) +{ + ::boost::detail::winapi::DWORD_ code; + //single value, not needed in the winapi. + if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &code)) + ::boost::process::detail::throw_last_error("GetExitCodeProcess() failed"); + + 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) noexcept +{ + ::boost::detail::winapi::DWORD_ code; + //single value, not needed in the winapi. + if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &code)) + ec = ::boost::process::detail::get_last_error(); + else + ec.clear(); + + if (code == still_active) + return true; + else + { + exit_code = code; + return false; + } +} + +inline bool is_running(int code) +{ + return code == still_active; +} + +inline int eval_exit_status(int in ) {return in;} + +}}}} + +#endif diff --git a/boost/process/detail/windows/job_workaround.hpp b/boost/process/detail/windows/job_workaround.hpp new file mode 100644 index 0000000000..b915d0c088 --- /dev/null +++ b/boost/process/detail/windows/job_workaround.hpp @@ -0,0 +1,139 @@ +// 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/detail/winapi/config.hpp> +#include <boost/detail/winapi/basic_types.hpp> +#include <boost/detail/winapi/dll.hpp> + +namespace boost { namespace process { namespace detail { namespace windows { namespace workaround { + +//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::detail::winapi::LARGE_INTEGER_ PerProcessUserTimeLimit; + ::boost::detail::winapi::LARGE_INTEGER_ PerJobUserTimeLimit; + ::boost::detail::winapi::DWORD_ LimitFlags; + ::boost::detail::winapi::SIZE_T_ MinimumWorkingSetSize; + ::boost::detail::winapi::SIZE_T_ MaximumWorkingSetSize; + ::boost::detail::winapi::DWORD_ ActiveProcessLimit; + ::boost::detail::winapi::ULONG_PTR_ Affinity; + ::boost::detail::winapi::DWORD_ PriorityClass; + ::boost::detail::winapi::DWORD_ SchedulingClass; +} JOBOBJECT_BASIC_LIMIT_INFORMATION_; + + +typedef struct _IO_COUNTERS_ { + ::boost::detail::winapi::ULONGLONG_ ReadOperationCount; + ::boost::detail::winapi::ULONGLONG_ WriteOperationCount; + ::boost::detail::winapi::ULONGLONG_ OtherOperationCount; + ::boost::detail::winapi::ULONGLONG_ ReadTransferCount; + ::boost::detail::winapi::ULONGLONG_ WriteTransferCount; + ::boost::detail::winapi::ULONGLONG_ OtherTransferCount; +} IO_COUNTERS_; + + +typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ { + JOBOBJECT_BASIC_LIMIT_INFORMATION_ BasicLimitInformation; + IO_COUNTERS_ IoInfo; + ::boost::detail::winapi::SIZE_T_ ProcessMemoryLimit; + ::boost::detail::winapi::SIZE_T_ JobMemoryLimit; + ::boost::detail::winapi::SIZE_T_ PeakProcessMemoryUsed; + ::boost::detail::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::detail::winapi::BOOL_ ( WINAPI *query_information_job_object_p)( + ::boost::detail::winapi::HANDLE_, + JOBOBJECTINFOCLASS_, + void *, + ::boost::detail::winapi::DWORD_, + ::boost::detail::winapi::DWORD_ *); + + +inline ::boost::detail::winapi::BOOL_ WINAPI query_information_job_object( + ::boost::detail::winapi::HANDLE_ hJob, + JOBOBJECTINFOCLASS_ JobObjectInfoClass, + void * lpJobObjectInfo, + ::boost::detail::winapi::DWORD_ cbJobObjectInfoLength, + ::boost::detail::winapi::DWORD_ *lpReturnLength) +{ + static ::boost::detail::winapi::HMODULE_ h = ::boost::detail::winapi::get_module_handle("Kernel32.dll"); + static query_information_job_object_p f = reinterpret_cast<query_information_job_object_p>(::boost::detail::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::detail::winapi::BOOL_ ( WINAPI *set_information_job_object_p)( + ::boost::detail::winapi::HANDLE_, + JOBOBJECTINFOCLASS_, + void *, + ::boost::detail::winapi::DWORD_); + +} + +inline ::boost::detail::winapi::BOOL_ WINAPI set_information_job_object( + ::boost::detail::winapi::HANDLE_ hJob, + JOBOBJECTINFOCLASS_ JobObjectInfoClass, + void * lpJobObjectInfo, + ::boost::detail::winapi::DWORD_ cbJobObjectInfoLength) +{ + static ::boost::detail::winapi::HMODULE_ h = ::boost::detail::winapi::get_module_handle("Kernel32.dll"); + static set_information_job_object_p f = reinterpret_cast<set_information_job_object_p>(::boost::detail::winapi::get_proc_address(h, "SetInformationJobObject")); + + return (*f)(hJob, JobObjectInfoClass, lpJobObjectInfo, cbJobObjectInfoLength); +} + +constexpr static ::boost::detail::winapi::DWORD_ JOB_OBJECT_LIMIT_BREAKAWAY_OK_ = 0x00000800; + +}}}}} + + + +#endif /* BOOST_PROCESS_DETAIL_WINDOWS_JOB_WORKAROUND_HPP_ */ diff --git a/boost/process/detail/windows/locale.hpp b/boost/process/detail/windows/locale.hpp new file mode 100644 index 0000000000..34da2a69d3 --- /dev/null +++ b/boost/process/detail/windows/locale.hpp @@ -0,0 +1,103 @@ +// 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 <locale>
+#include <boost/core/ignore_unused.hpp>
+#include <boost/detail/winapi/file_management.hpp>
+#include <boost/detail/winapi/character_code_conversion.hpp>
+ +namespace boost
+{
+namespace process
+{
+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);
+ ::boost::detail::winapi::UINT_ codepage = AreFileApisANSI() ?
+ ::boost::detail::winapi::CP_ACP_ :
+ ::boost::detail::winapi::CP_OEMCP_;
+ + int count;
+ if ((count = ::boost::detail::winapi::MultiByteToWideChar(codepage,
+ ::boost::detail::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 = ::boost::detail::winapi::AreFileApisANSI() ?
+ ::boost::detail::winapi::CP_ACP_ :
+ ::boost::detail::winapi::CP_OEMCP_;
+ + int count;
+ if ((count = ::boost::detail::winapi::WideCharToMultiByte(codepage,
+ ::boost::detail::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_ */
diff --git a/boost/process/detail/windows/null_in.hpp b/boost/process/detail/windows/null_in.hpp new file mode 100644 index 0000000000..f5c0ae6bf7 --- /dev/null +++ b/boost/process/detail/windows/null_in.hpp @@ -0,0 +1,41 @@ +// 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/detail/winapi/process.hpp>
+#include <boost/detail/winapi/handles.hpp>
+#include <boost/detail/winapi/handle_info.hpp>
+#include <boost/process/detail/handler_base.hpp>
+#include <boost/process/detail/windows/file_descriptor.hpp>
+ +namespace boost { namespace process { namespace detail { namespace windows {
+ +struct null_in : public ::boost::process::detail::handler_base
+{
+ file_descriptor source{"NUL", file_descriptor::read};
+ +public:
+ template <class WindowsExecutor>
+ void on_setup(WindowsExecutor &e) const
+ {
+ boost::detail::winapi::SetHandleInformation(source.handle(),
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_);
+ + e.startup_info.hStdInput = source.handle();
+ e.startup_info.dwFlags |= boost::detail::winapi::STARTF_USESTDHANDLES_;
+ e.inherit_handles = true;
+ }
+};
+ +}}}}
+ +#endif
diff --git a/boost/process/detail/windows/null_out.hpp b/boost/process/detail/windows/null_out.hpp new file mode 100644 index 0000000000..1bc19586c1 --- /dev/null +++ b/boost/process/detail/windows/null_out.hpp @@ -0,0 +1,75 @@ +// 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/detail/winapi/process.hpp>
+#include <boost/detail/winapi/handles.hpp>
+#include <boost/detail/winapi/handle_info.hpp>
+#include <boost/process/detail/handler_base.hpp>
+#include <boost/process/detail/windows/file_descriptor.hpp>
+ +namespace boost { namespace process { namespace detail { namespace windows {
+ +template<int p1, int p2>
+struct null_out : public ::boost::process::detail::handler_base
+{
+ file_descriptor sink {"NUL", file_descriptor::write}; //works because it gets destroyed AFTER launch.
+ + template <typename WindowsExecutor>
+ void on_setup(WindowsExecutor &e) const;
+};
+ +template<>
+template<typename WindowsExecutor>
+void null_out<1,-1>::on_setup(WindowsExecutor &e) const
+{
+ boost::detail::winapi::SetHandleInformation(sink.handle(),
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_);
+ + e.startup_info.hStdOutput = sink.handle();
+ e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
+ e.inherit_handles = true;
+ +}
+ +template<>
+template<typename WindowsExecutor>
+void null_out<2,-1>::on_setup(WindowsExecutor &e) const
+{
+ boost::detail::winapi::SetHandleInformation(sink.handle(),
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_);
+ + e.startup_info.hStdError = sink.handle();
+ e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
+ e.inherit_handles = true;
+ +}
+ +template<>
+template<typename WindowsExecutor>
+void null_out<1,2>::on_setup(WindowsExecutor &e) const
+{
+ boost::detail::winapi::SetHandleInformation(sink.handle(),
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_);
+ + e.startup_info.hStdOutput = sink.handle();
+ e.startup_info.hStdError = sink.handle();
+ e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
+ e.inherit_handles = true;
+ +}
+ +}}}}
+ +#endif
diff --git a/boost/process/detail/windows/on_exit.hpp b/boost/process/detail/windows/on_exit.hpp new file mode 100644 index 0000000000..751f6a5f85 --- /dev/null +++ b/boost/process/detail/windows/on_exit.hpp @@ -0,0 +1,40 @@ +// Copyright (c) 2016 Klemens D. Morgenstern
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+ +#ifndef BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_
+#define BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_
+ +#include <boost/process/detail/config.hpp>
+#include <boost/process/detail/handler_base.hpp>
+#include <boost/process/detail/windows/async_handler.hpp>
+#include <boost/detail/winapi/process.hpp>
+#include <system_error>
+#include <functional>
+ +namespace boost { namespace process { namespace detail { namespace windows {
+ +struct on_exit_ : boost::process::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&)
+ {
+ auto handler = this->handler;
+ return [handler](int exit_code, const std::error_code & ec)
+ {
+ handler(static_cast<int>(exit_code), ec);
+ };
+ + }
+};
+ + +}}}}
+#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_ */
diff --git a/boost/process/detail/windows/pipe_in.hpp b/boost/process/detail/windows/pipe_in.hpp new file mode 100644 index 0000000000..cd8c186e15 --- /dev/null +++ b/boost/process/detail/windows/pipe_in.hpp @@ -0,0 +1,89 @@ +// 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/detail/winapi/process.hpp>
+#include <boost/detail/winapi/handles.hpp>
+#include <boost/process/detail/handler_base.hpp>
+ +namespace boost { namespace process { namespace detail { namespace windows {
+ +struct pipe_in : public ::boost::process::detail::handler_base
+{
+ ::boost::detail::winapi::HANDLE_ handle;
+ + pipe_in(::boost::detail::winapi::HANDLE_ handle) : handle(handle) {}
+ + template<typename T> //async_pipe
+ pipe_in(T & p) : handle(p.native_source())
+ {
+ p.assign_source(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
+ }
+ + template <class WindowsExecutor>
+ void on_setup(WindowsExecutor &e) const
+ {
+ boost::detail::winapi::SetHandleInformation(handle,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_);
+ + e.startup_info.hStdInput = handle;
+ e.startup_info.dwFlags |= boost::detail::winapi::STARTF_USESTDHANDLES_;
+ e.inherit_handles = true;
+ }
+ template<typename WindowsExecutor>
+ void on_error(WindowsExecutor &, const std::error_code &) const
+ {
+ ::boost::detail::winapi::CloseHandle(handle);
+ }
+ + template<typename WindowsExecutor>
+ void on_success(WindowsExecutor &) const
+ {
+ ::boost::detail::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
diff --git a/boost/process/detail/windows/pipe_out.hpp b/boost/process/detail/windows/pipe_out.hpp new file mode 100644 index 0000000000..c32f0a604e --- /dev/null +++ b/boost/process/detail/windows/pipe_out.hpp @@ -0,0 +1,122 @@ +// 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/detail/winapi/process.hpp>
+#include <boost/detail/winapi/handles.hpp>
+#include <boost/process/detail/handler_base.hpp>
+ +namespace boost { namespace process { namespace detail { namespace windows {
+ + + +template<int p1, int p2>
+struct pipe_out : public ::boost::process::detail::handler_base
+{
+ ::boost::detail::winapi::HANDLE_ handle;
+ + pipe_out(::boost::detail::winapi::HANDLE_ handle) : handle(handle) {}
+ template<typename T>
+ pipe_out(T & p) : handle(p.native_sink())
+ {
+ p.assign_sink(::boost::detail::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::detail::winapi::CloseHandle(handle);
+ }
+ + template<typename WindowsExecutor>
+ void on_success(WindowsExecutor &) const
+ {
+ ::boost::detail::winapi::CloseHandle(handle);
+ }
+};
+ +template<>
+template<typename WindowsExecutor>
+void pipe_out<1,-1>::on_setup(WindowsExecutor &e) const
+{
+ boost::detail::winapi::SetHandleInformation(handle,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_);
+ + e.startup_info.hStdOutput = handle;
+ e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
+ e.inherit_handles = true;
+}
+ +template<>
+template<typename WindowsExecutor>
+void pipe_out<2,-1>::on_setup(WindowsExecutor &e) const
+{
+ boost::detail::winapi::SetHandleInformation(handle,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_);
+ + + e.startup_info.hStdError = handle;
+ e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
+ e.inherit_handles = true;
+}
+ +template<>
+template<typename WindowsExecutor>
+void pipe_out<1,2>::on_setup(WindowsExecutor &e) const
+{
+ boost::detail::winapi::SetHandleInformation(handle,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_,
+ boost::detail::winapi::HANDLE_FLAG_INHERIT_);
+ + e.startup_info.hStdOutput = handle;
+ e.startup_info.hStdError = handle;
+ e.startup_info.dwFlags |= ::boost::detail::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
diff --git a/boost/process/detail/windows/search_path.hpp b/boost/process/detail/windows/search_path.hpp new file mode 100644 index 0000000000..53fb966784 --- /dev/null +++ b/boost/process/detail/windows/search_path.hpp @@ -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_SEARCH_PATH_HPP +#define BOOST_PROCESS_WINDOWS_SEARCH_PATH_HPP + +#include <boost/process/detail/config.hpp> +#include <boost/filesystem/path.hpp> +#include <boost/filesystem/operations.hpp> +#include <boost/system/error_code.hpp> +#include <string> +#include <stdexcept> +#include <array> +#include <atomic> +#include <cstdlib> +#include <boost/detail/winapi/shell.hpp> + + + +namespace boost { namespace process { namespace detail { namespace windows { + +inline boost::filesystem::path search_path( + const boost::filesystem::path &filename, + const std::vector<boost::filesystem::path> &path) +{ + for (const boost::filesystem::path & pp : path) + { + auto full = pp / filename; + std::array<std::string, 4> extensions {{ "", ".exe", ".com", ".bat" }}; + for (boost::filesystem::path ext : extensions) + { + auto p = full; + p += ext; + boost::system::error_code ec; + bool file = boost::filesystem::is_regular_file(p, ec); + if (!ec && file && + ::boost::detail::winapi::sh_get_file_info(p.string().c_str(), 0, 0, 0, ::boost::detail::winapi::SHGFI_EXETYPE_)) + { + return p; + } + } + } + return ""; +} + +}}}} + +#endif diff --git a/boost/process/detail/windows/shell_path.hpp b/boost/process/detail/windows/shell_path.hpp new file mode 100644 index 0000000000..7cce445292 --- /dev/null +++ b/boost/process/detail/windows/shell_path.hpp @@ -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/detail/config.hpp> +#include <system_error> +#include <boost/filesystem/path.hpp> +#include <boost/detail/winapi/basic_types.hpp> +#include <boost/detail/winapi/get_system_directory.hpp> + +namespace boost { namespace process { namespace detail { namespace windows { + +inline boost::filesystem::path shell_path() +{ + ::boost::detail::winapi::WCHAR_ sysdir[260]; + unsigned int size = ::boost::detail::winapi::get_system_directory(sysdir, sizeof(sysdir)); + if (!size) + throw_last_error("GetSystemDirectory() failed"); + + boost::filesystem::path p = sysdir; + return p / "cmd.exe"; +} + +inline boost::filesystem::path shell_path(std::error_code &ec) noexcept +{ + + ::boost::detail::winapi::WCHAR_ sysdir[260]; + unsigned int size = ::boost::detail::winapi::get_system_directory(sysdir, sizeof(sysdir)); + boost::filesystem::path p; + if (!size) + ec = std::error_code( + ::boost::detail::winapi::GetLastError(), + std::system_category()); + else + { + ec.clear(); + p = sysdir; + p /= "cmd.exe"; + } + return p; +} + +}}}} + +#endif diff --git a/boost/process/detail/windows/show_window.hpp b/boost/process/detail/windows/show_window.hpp new file mode 100644 index 0000000000..ed42ebc56e --- /dev/null +++ b/boost/process/detail/windows/show_window.hpp @@ -0,0 +1,39 @@ +// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
+// 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/detail/winapi/process.hpp>
+#include <boost/detail/winapi/show_window.hpp>
+#include <boost/process/detail/handler_base.hpp>
+ + +namespace boost { namespace process { namespace detail { namespace windows {
+ +template<::boost::detail::winapi::WORD_ Flags>
+struct show_window : ::boost::process::detail::handler_base
+{
+ template <class WindowsExecutor>
+ void on_setup(WindowsExecutor &e) const
+ {
+ e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESHOWWINDOW_;
+ e.startup_info.wShowWindow |= Flags;
+ }
+};
+ + + + + +}}}}
+ +#endif
+ diff --git a/boost/process/detail/windows/start_dir.hpp b/boost/process/detail/windows/start_dir.hpp new file mode 100644 index 0000000000..06629ed1f8 --- /dev/null +++ b/boost/process/detail/windows/start_dir.hpp @@ -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/detail/windows/handler.hpp>
+ +namespace boost { namespace process { 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
diff --git a/boost/process/detail/windows/terminate.hpp b/boost/process/detail/windows/terminate.hpp new file mode 100644 index 0000000000..a10b074078 --- /dev/null +++ b/boost/process/detail/windows/terminate.hpp @@ -0,0 +1,49 @@ +// 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/detail/config.hpp> +#include <system_error> +#include <cstdlib> +#include <boost/detail/winapi/process.hpp> +#include <boost/detail/winapi/get_last_error.hpp> + +namespace boost { namespace process { namespace detail { namespace windows { + +struct child_handle; + +inline void terminate(child_handle &p) +{ + if (!::boost::detail::winapi::TerminateProcess(p.process_handle(), EXIT_FAILURE)) + boost::process::detail::throw_last_error("TerminateProcess() failed"); + + ::boost::detail::winapi::CloseHandle(p.proc_info.hProcess); + p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; +} + +inline void terminate(child_handle &p, std::error_code &ec) noexcept +{ + if (!::boost::detail::winapi::TerminateProcess(p.process_handle(), EXIT_FAILURE)) + ec = boost::process::detail::get_last_error(); + else + { + ec.clear(); + ::boost::detail::winapi::CloseHandle(p.proc_info.hProcess); + p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + } +} + + + + +}}}} + +#endif diff --git a/boost/process/detail/windows/wait_for_exit.hpp b/boost/process/detail/windows/wait_for_exit.hpp new file mode 100644 index 0000000000..decdb51172 --- /dev/null +++ b/boost/process/detail/windows/wait_for_exit.hpp @@ -0,0 +1,193 @@ +// 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/detail/config.hpp> +#include <system_error> +#include <boost/detail/winapi/synchronization.hpp> +#include <boost/detail/winapi/process.hpp> +#include <boost/process/detail/windows/child_handle.hpp> +#include <chrono> + +namespace boost { namespace process { namespace detail { namespace windows { + +inline void wait(child_handle &p, int & exit_code) +{ + if (::boost::detail::winapi::WaitForSingleObject(p.process_handle(), + ::boost::detail::winapi::infinite) == ::boost::detail::winapi::wait_failed) + throw_last_error("WaitForSingleObject() failed"); + + ::boost::detail::winapi::DWORD_ _exit_code; + if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code)) + throw_last_error("GetExitCodeProcess() failed"); + + ::boost::detail::winapi::CloseHandle(p.proc_info.hProcess); + p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + exit_code = static_cast<int>(_exit_code); +} + +inline void wait(child_handle &p, int & exit_code, std::error_code &ec) noexcept +{ + ::boost::detail::winapi::DWORD_ _exit_code = 1; + + if (::boost::detail::winapi::WaitForSingleObject(p.process_handle(), + ::boost::detail::winapi::infinite) == ::boost::detail::winapi::wait_failed) + ec = std::error_code( + ::boost::detail::winapi::GetLastError(), + std::system_category()); + else if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code)) + ec = std::error_code( + ::boost::detail::winapi::GetLastError(), + std::system_category()); + else + ec.clear(); + + ::boost::detail::winapi::CloseHandle(p.proc_info.hProcess); + p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + exit_code = static_cast<int>(_exit_code); +} + + +template< class Rep, class Period > +inline bool wait_for( + child_handle &p, + int & exit_code, + const std::chrono::duration<Rep, Period>& rel_time) +{ + + std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time); + + ::boost::detail::winapi::DWORD_ wait_code; + wait_code = ::boost::detail::winapi::WaitForSingleObject(p.process_handle(), + static_cast<::boost::detail::winapi::DWORD_>(ms.count())); + if (wait_code == ::boost::detail::winapi::wait_failed) + throw_last_error("WaitForSingleObject() failed"); + else if (wait_code == ::boost::detail::winapi::wait_timeout) + return false; // + + ::boost::detail::winapi::DWORD_ _exit_code; + if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code)) + throw_last_error("GetExitCodeProcess() failed"); + + exit_code = static_cast<int>(_exit_code); + ::boost::detail::winapi::CloseHandle(p.proc_info.hProcess); + p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + return true; +} + + +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 +{ + + std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time); + + + ::boost::detail::winapi::DWORD_ wait_code; + wait_code = ::boost::detail::winapi::WaitForSingleObject(p.process_handle(), + static_cast<::boost::detail::winapi::DWORD_>(ms.count())); + if (wait_code == ::boost::detail::winapi::wait_failed) + ec = std::error_code( + ::boost::detail::winapi::GetLastError(), + std::system_category()); + else if (wait_code == ::boost::detail::winapi::wait_timeout) + return false; // + + ::boost::detail::winapi::DWORD_ _exit_code = 1; + if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code)) + { + ec = std::error_code( + ::boost::detail::winapi::GetLastError(), + std::system_category()); + return false; + } + else + ec.clear(); + + exit_code = static_cast<int>(_exit_code); + ::boost::detail::winapi::CloseHandle(p.proc_info.hProcess); + p.proc_info.hProcess = ::boost::detail::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::chrono::milliseconds ms = + std::chrono::duration_cast<std::chrono::milliseconds>( + timeout_time - std::chrono::system_clock::now()); + + ::boost::detail::winapi::DWORD_ wait_code; + wait_code = ::boost::detail::winapi::WaitForSingleObject(p.process_handle(), + static_cast<::boost::detail::winapi::DWORD_>(ms.count())); + + if (wait_code == ::boost::detail::winapi::wait_failed) + throw_last_error("WaitForSingleObject() failed"); + else if (wait_code == ::boost::detail::winapi::wait_timeout) + return false; + + ::boost::detail::winapi::DWORD_ _exit_code; + if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code)) + throw_last_error("GetExitCodeProcess() failed"); + + exit_code = static_cast<int>(_exit_code); + ::boost::detail::winapi::CloseHandle(p.proc_info.hProcess); + p.proc_info.hProcess = ::boost::detail::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) noexcept +{ + std::chrono::milliseconds ms = + std::chrono::duration_cast<std::chrono::milliseconds>( + timeout_time - std::chrono::system_clock::now()); + + ::boost::detail::winapi::DWORD_ _exit_code = 1; + + if (::boost::detail::winapi::WaitForSingleObject(p.process_handle(), + static_cast<::boost::detail::winapi::DWORD_>(ms.count())) + == ::boost::detail::winapi::wait_failed) + ec = std::error_code( + ::boost::detail::winapi::GetLastError(), + std::system_category()); + else if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code)) + ec = std::error_code( + ::boost::detail::winapi::GetLastError(), + std::system_category()); + else + ec.clear(); + + exit_code = static_cast<int>(exit_code); + ::boost::detail::winapi::CloseHandle(p.proc_info.hProcess); + p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; + return true; +; +} + + +}}}} + +#endif diff --git a/boost/process/detail/windows/wait_group.hpp b/boost/process/detail/windows/wait_group.hpp new file mode 100644 index 0000000000..449985f2fc --- /dev/null +++ b/boost/process/detail/windows/wait_group.hpp @@ -0,0 +1,121 @@ +// 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/detail/config.hpp> +#include <boost/detail/winapi/jobs.hpp> +#include <boost/detail/winapi/wait.hpp> + + +namespace boost { namespace process { namespace detail { namespace windows { + +struct group_handle; + +inline void wait(const group_handle &p) +{ + if (::boost::detail::winapi::WaitForSingleObject(p.handle(), + ::boost::detail::winapi::infinite) == ::boost::detail::winapi::wait_failed) + throw_last_error("WaitForSingleObject() failed"); + +} + +inline void wait(const group_handle &p, std::error_code &ec) +{ + if (::boost::detail::winapi::WaitForSingleObject(p.handle(), + ::boost::detail::winapi::infinite) == ::boost::detail::winapi::wait_failed) + ec = get_last_error(); +} + + +template< class Rep, class Period > +inline bool wait_for( + const group_handle &p, + const std::chrono::duration<Rep, Period>& rel_time) +{ + + std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time); + + ::boost::detail::winapi::DWORD_ wait_code; + wait_code = ::boost::detail::winapi::WaitForSingleObject(p.handle(), ms.count()); + if (wait_code == ::boost::detail::winapi::wait_failed) + throw_last_error("WaitForSingleObject() failed"); + else if (wait_code == ::boost::detail::winapi::wait_timeout) + return false; // + + return true; +} + + +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) +{ + + std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time); + + + ::boost::detail::winapi::DWORD_ wait_code; + wait_code = ::boost::detail::winapi::WaitForSingleObject(p.handle(), ms.count()); + if (wait_code == ::boost::detail::winapi::wait_failed) + ec = get_last_error(); + + else if (wait_code == ::boost::detail::winapi::wait_timeout) + return false; // + + return true; +} + +template< class Clock, class Duration > +inline bool wait_until( + const group_handle &p, + const std::chrono::time_point<Clock, Duration>& timeout_time) +{ + std::chrono::milliseconds ms = + std::chrono::duration_cast<std::chrono::milliseconds>( + timeout_time - std::chrono::system_clock::now()); + + ::boost::detail::winapi::DWORD_ wait_code; + wait_code = ::boost::detail::winapi::WaitForSingleObject(p.handle(), ms.count()); + + if (wait_code == ::boost::detail::winapi::wait_failed) + throw_last_error("WaitForSingleObject() failed"); + + else if (wait_code == ::boost::detail::winapi::wait_timeout) + return false; // + + return true; +} + + +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 - std::chrono::system_clock::now()); + + ::boost::detail::winapi::DWORD_ wait_code; + wait_code = ::boost::detail::winapi::WaitForSingleObject(p.handle(), ms.count()); + + if (wait_code == ::boost::detail::winapi::wait_failed) + ec = get_last_error(); + + else if (wait_code == ::boost::detail::winapi::wait_timeout) + return false; // + + return true; +; +} + +}}}} + +#endif /* BOOST_PROCESS_DETAIL_WINDOWS_WAIT_GROUP_HPP_ */ |