Replace Boost.Process for the Wine plugin host

Now we use our own library for this, so we can drop the Boost.Filesystem
dependency after a couple more changes.
This commit is contained in:
Robbert van der Helm
2022-04-14 18:45:47 +02:00
parent f79b0fd146
commit 037d6ad5aa
6 changed files with 148 additions and 413 deletions
-216
View File
@@ -27,224 +27,8 @@
#include <asio/read_until.hpp>
#include <asio/streambuf.hpp>
// FIXME: Remove when we get rid of the patched_async_pipe
#include <asio/io_context.hpp>
#include <asio/posix/stream_descriptor.hpp>
#include <asio/post.hpp>
// FIXME: Get rid of Boost.Process and all of the wrangling below
#include <boost/process/async_pipe.hpp>
#include <boost/process/detail/posix/pipe_out.hpp>
#include <boost/process/posix.hpp>
#include "../utils.h"
/**
* Boost 1.72 was released with a known breaking bug caused by a missing
* typedef: https://github.com/boostorg/process/issues/116.
*
* Luckily this is easy to fix since it's not really possible to downgrade Boost
* as it would break other applications.
*
* Check if this is still needed for other distros after Arch starts packaging
* Boost 1.73.
*
* FIXME: This has been adopted to work with standalone Asio, we should replace
* this when we replace Boost.Process
*/
class patched_async_pipe {
::asio::posix::stream_descriptor _source;
::asio::posix::stream_descriptor _sink;
public:
typedef int native_handle_type;
typedef ::asio::posix::stream_descriptor handle_type;
typedef typename handle_type::executor_type executor_type;
executor_type get_executor() { return _source.get_executor(); }
inline patched_async_pipe(asio::io_context& ios)
: patched_async_pipe(ios, ios) {}
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
inline patched_async_pipe(asio::io_context& ios_source,
asio::io_context& ios_sink)
: _source(ios_source), _sink(ios_sink) {
int fds[2];
if (pipe(fds) == -1)
boost::process::detail::throw_last_error("pipe(2) failed");
_source.assign(fds[0]);
_sink.assign(fds[1]);
};
inline patched_async_pipe(const patched_async_pipe& lhs);
patched_async_pipe(patched_async_pipe&& lhs)
: _source(std::move(lhs._source)), _sink(std::move(lhs._sink)) {
lhs._source =
::asio::posix::stream_descriptor{lhs._source.get_executor()};
lhs._sink = ::asio::posix::stream_descriptor{lhs._sink.get_executor()};
}
template <class CharT, class Traits = std::char_traits<CharT>>
explicit patched_async_pipe(
::asio::io_context& ios_source,
::asio::io_context& ios_sink,
const boost::process::detail::posix::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 patched_async_pipe(
asio::io_context& ios,
const boost::process::detail::posix::basic_pipe<CharT, Traits>& p)
: patched_async_pipe(ios, ios, p) {}
template <class CharT, class Traits = std::char_traits<CharT>>
inline patched_async_pipe& operator=(
const boost::process::detail::posix::basic_pipe<CharT, Traits>& p);
inline patched_async_pipe& operator=(const patched_async_pipe& rhs);
inline patched_async_pipe& operator=(patched_async_pipe&& lhs);
~patched_async_pipe() {
std::error_code ec;
close(ec);
}
template <class CharT, class Traits = std::char_traits<CharT>>
inline explicit
operator boost::process::detail::posix::basic_pipe<CharT, Traits>() const;
void cancel() {
if (_sink.is_open())
_sink.cancel();
if (_source.is_open())
_source.cancel();
}
void close() {
if (_sink.is_open())
_sink.close();
if (_source.is_open())
_source.close();
}
void close(std::error_code& ec) {
if (_sink.is_open())
_sink.close(ec);
if (_source.is_open())
_source.close(ec);
}
bool is_open() const { return _sink.is_open() || _source.is_open(); }
void async_close() {
if (_sink.is_open())
asio::post(_sink.get_executor(), [this] { _sink.close(); });
if (_source.is_open())
asio::post(_source.get_executor(), [this] { _source.close(); });
}
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers) {
return _source.read_some(buffers);
}
template <typename MutableBufferSequence>
std::size_t write_some(const MutableBufferSequence& buffers) {
return _sink.write_some(buffers);
}
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
std::error_code& ec) noexcept {
return _source.read_some(buffers, ec);
}
template <typename MutableBufferSequence>
std::size_t write_some(const MutableBufferSequence& buffers,
std::error_code& ec) noexcept {
return _sink.write_some(buffers, ec);
}
native_handle_type native_source() const {
return const_cast<asio::posix::stream_descriptor&>(_source)
.native_handle();
}
native_handle_type native_sink() const {
return const_cast<asio::posix::stream_descriptor&>(_sink)
.native_handle();
}
template <typename MutableBufferSequence, typename ReadHandler>
ASIO_INITFN_RESULT_TYPE(ReadHandler, void(std::error_code, std::size_t))
async_read_some(const MutableBufferSequence& buffers,
ReadHandler&& handler) {
return _source.async_read_some(buffers,
std::forward<ReadHandler>(handler));
}
template <typename ConstBufferSequence, typename WriteHandler>
ASIO_INITFN_RESULT_TYPE(WriteHandler, void(std::error_code, std::size_t))
async_write_some(const ConstBufferSequence& buffers,
WriteHandler&& handler) {
return _sink.async_write_some(buffers,
std::forward<WriteHandler>(handler));
}
const handle_type& sink() const& { return _sink; }
const handle_type& source() const& { return _source; }
handle_type&& sink() && { return std::move(_sink); }
handle_type&& source() && { return std::move(_source); }
handle_type source(::asio::io_context& ios) && {
::asio::posix::stream_descriptor stolen(ios, _source.release());
return stolen;
}
handle_type sink(::asio::io_context& ios) && {
::asio::posix::stream_descriptor stolen(ios, _sink.release());
return stolen;
}
handle_type source(::asio::io_context& ios) const& {
auto source_in = const_cast<::asio::posix::stream_descriptor&>(_source)
.native_handle();
return ::asio::posix::stream_descriptor(ios, ::dup(source_in));
}
handle_type sink(::asio::io_context& ios) const& {
auto sink_in = const_cast<::asio::posix::stream_descriptor&>(_sink)
.native_handle();
return ::asio::posix::stream_descriptor(ios, ::dup(sink_in));
}
};
// Even more of a mess, we can't use the nice `bp::std_out = ...`/`bp::std_err =
// ...` syntax anymore.
template <int p1, int p2>
struct patched_async_pipe_out
: public boost::process::detail::posix::pipe_out<p1, p2> {
patched_async_pipe& pipe;
template <typename AsyncPipe>
patched_async_pipe_out(AsyncPipe& p)
: boost::process::detail::posix::pipe_out<p1, p2>(p.native_sink(),
p.native_source()),
pipe(p) {}
template <typename Pipe, typename Executor>
static void close(Pipe& pipe, Executor&) {
std::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);
}
};
/**
* Super basic logging facility meant for debugging malfunctioning VST
* plugins. This is also used to redirect the output of the Wine process