mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-09 20:29:10 +02:00
Replace Boost.Asio with standalone Asio library
We had to add an even hackier hack now to get Boost.Process to interoperate with Asio's IO contexts. This will be replaced later when we replace Boost.Process.
This commit is contained in:
@@ -23,6 +23,8 @@ Versioning](https://semver.org/spec/v2.0.0.html).
|
|||||||
- Added a dependency on the headers-only
|
- Added a dependency on the headers-only
|
||||||
[`ghc::filesystem`](https://github.com/gulrak/filesystem) library to replace
|
[`ghc::filesystem`](https://github.com/gulrak/filesystem) library to replace
|
||||||
Boost.Filesystem.
|
Boost.Filesystem.
|
||||||
|
- Added a dependency on the headers-only [Asio](http://think-async.com/Asio/)
|
||||||
|
library to replace Boost.Asio.
|
||||||
- Fixed a deprecation warning in the Meson build, causing the minimum supported
|
- Fixed a deprecation warning in the Meson build, causing the minimum supported
|
||||||
Meson version to be bumped up to **Meson 0.56** from 0.55.
|
Meson version to be bumped up to **Meson 0.56** from 0.55.
|
||||||
|
|
||||||
|
|||||||
@@ -770,6 +770,7 @@ the following dependencies:
|
|||||||
|
|
||||||
The following dependencies are included in the repository as a Meson wrap:
|
The following dependencies are included in the repository as a Meson wrap:
|
||||||
|
|
||||||
|
- [Asio](http://think-async.com/Asio/)
|
||||||
- [bitsery](https://github.com/fraillt/bitsery)
|
- [bitsery](https://github.com/fraillt/bitsery)
|
||||||
- [function2](https://github.com/Naios/function2)
|
- [function2](https://github.com/Naios/function2)
|
||||||
- [`ghc::filesystem`](https://github.com/gulrak/filesystem)
|
- [`ghc::filesystem`](https://github.com/gulrak/filesystem)
|
||||||
|
|||||||
+4
-1
@@ -46,7 +46,7 @@ compiler_options = [
|
|||||||
'-fvisibility-inlines-hidden',
|
'-fvisibility-inlines-hidden',
|
||||||
# Disable the use of concepts in Boost.Asio until Boost 1.73 gets released
|
# Disable the use of concepts in Boost.Asio until Boost 1.73 gets released
|
||||||
# https://github.com/boostorg/asio/issues/312
|
# https://github.com/boostorg/asio/issues/312
|
||||||
# TODO: Rename after switching to non-Boost ASIO
|
# TODO: Rename after switching out Boost.Process
|
||||||
'-DBOOST_ASIO_DISABLE_CONCEPTS',
|
'-DBOOST_ASIO_DISABLE_CONCEPTS',
|
||||||
# Boost.Process's auto detection for vfork() support doesn't seem to work
|
# Boost.Process's auto detection for vfork() support doesn't seem to work
|
||||||
# TODO: Remove after adding our own library
|
# TODO: Remove after adding our own library
|
||||||
@@ -232,6 +232,7 @@ endif
|
|||||||
# These are all headers-only libraries, and thus won't require separate 32-bit
|
# These are all headers-only libraries, and thus won't require separate 32-bit
|
||||||
# and 64-bit versions
|
# and 64-bit versions
|
||||||
|
|
||||||
|
asio_dep = dependency('asio', version : '>=1.22.0')
|
||||||
boost_dep = dependency('boost', version : '>=1.66', static : with_static_boost)
|
boost_dep = dependency('boost', version : '>=1.66', static : with_static_boost)
|
||||||
if meson.version().version_compare('>=0.60')
|
if meson.version().version_compare('>=0.60')
|
||||||
# Bitsery's CMake build definition is capitalized for some reason
|
# Bitsery's CMake build definition is capitalized for some reason
|
||||||
@@ -295,6 +296,7 @@ shared_library(
|
|||||||
dependencies : [
|
dependencies : [
|
||||||
configuration_dep,
|
configuration_dep,
|
||||||
|
|
||||||
|
asio_dep,
|
||||||
boost_dep,
|
boost_dep,
|
||||||
with_32bit_libraries
|
with_32bit_libraries
|
||||||
? boost_filesystem_32bit_dep
|
? boost_filesystem_32bit_dep
|
||||||
@@ -320,6 +322,7 @@ if with_vst3
|
|||||||
dependencies : [
|
dependencies : [
|
||||||
configuration_dep,
|
configuration_dep,
|
||||||
|
|
||||||
|
asio_dep,
|
||||||
boost_dep,
|
boost_dep,
|
||||||
with_32bit_libraries
|
with_32bit_libraries
|
||||||
? boost_filesystem_32bit_dep
|
? boost_filesystem_32bit_dep
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#ifdef __WINE__
|
#ifdef __WINE__
|
||||||
#include "../wine-host/boost-fix.h"
|
#include "../wine-host/asio-fix.h"
|
||||||
#endif
|
#endif
|
||||||
#include <boost/interprocess/mapped_region.hpp>
|
#include <boost/interprocess/mapped_region.hpp>
|
||||||
#include <boost/interprocess/shared_memory_object.hpp>
|
#include <boost/interprocess/shared_memory_object.hpp>
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
#include <random>
|
#include <random>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include "../utils.h"
|
#include "../utils.h"
|
||||||
|
|
||||||
|
|||||||
@@ -24,12 +24,12 @@
|
|||||||
#include <bitsery/traits/vector.h>
|
#include <bitsery/traits/vector.h>
|
||||||
|
|
||||||
#ifdef __WINE__
|
#ifdef __WINE__
|
||||||
#include "../wine-host/boost-fix.h"
|
#include "../wine-host/asio-fix.h"
|
||||||
#endif
|
#endif
|
||||||
#include <boost/asio/io_context.hpp>
|
#include <asio/io_context.hpp>
|
||||||
#include <boost/asio/local/stream_protocol.hpp>
|
#include <asio/local/stream_protocol.hpp>
|
||||||
#include <boost/asio/read.hpp>
|
#include <asio/read.hpp>
|
||||||
#include <boost/asio/write.hpp>
|
#include <asio/write.hpp>
|
||||||
#include <boost/container/small_vector.hpp>
|
#include <boost/container/small_vector.hpp>
|
||||||
#include <ghc/filesystem.hpp>
|
#include <ghc/filesystem.hpp>
|
||||||
|
|
||||||
@@ -79,51 +79,49 @@ using SerializationBuffer = boost::container::small_vector<uint8_t, N>;
|
|||||||
*/
|
*/
|
||||||
using SerializationBufferBase = boost::container::small_vector_base<uint8_t>;
|
using SerializationBufferBase = boost::container::small_vector_base<uint8_t>;
|
||||||
|
|
||||||
namespace boost {
|
|
||||||
namespace asio {
|
namespace asio {
|
||||||
|
|
||||||
template <typename PodType, typename Allocator>
|
template <typename PodType, typename Allocator>
|
||||||
inline BOOST_ASIO_MUTABLE_BUFFER buffer(
|
inline ASIO_MUTABLE_BUFFER buffer(
|
||||||
boost::container::small_vector_base<PodType, Allocator>& data)
|
boost::container::small_vector_base<PodType, Allocator>& data)
|
||||||
BOOST_ASIO_NOEXCEPT {
|
ASIO_NOEXCEPT {
|
||||||
return BOOST_ASIO_MUTABLE_BUFFER(
|
return ASIO_MUTABLE_BUFFER(
|
||||||
data.size() ? &data[0] : 0, data.size() * sizeof(PodType)
|
data.size() ? &data[0] : 0, data.size() * sizeof(PodType)
|
||||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||||
,
|
,
|
||||||
detail::buffer_debug_check<typename boost::container::small_vector_base<
|
detail::buffer_debug_check<typename boost::container::small_vector_base<
|
||||||
PodType, Allocator>::iterator>(data.begin())
|
PodType, Allocator>::iterator>(data.begin())
|
||||||
#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
|
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are copied verbatim `boost::asio::buffer(std::vector<PodType,
|
// These are copied verbatim `asio::buffer(std::vector<PodType,
|
||||||
// Allocator>&, std::size_t)`, since `boost::container::small_vector` is
|
// Allocator>&, std::size_t)`, since `boost::container::small_vector` is
|
||||||
// compatible with the STL vector.
|
// compatible with the STL vector.
|
||||||
template <typename PodType, typename Allocator>
|
template <typename PodType, typename Allocator>
|
||||||
inline BOOST_ASIO_MUTABLE_BUFFER buffer(
|
inline ASIO_MUTABLE_BUFFER buffer(
|
||||||
boost::container::small_vector_base<PodType, Allocator>& data,
|
boost::container::small_vector_base<PodType, Allocator>& data,
|
||||||
std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT {
|
std::size_t max_size_in_bytes) ASIO_NOEXCEPT {
|
||||||
return BOOST_ASIO_MUTABLE_BUFFER(
|
return ASIO_MUTABLE_BUFFER(
|
||||||
data.size() ? &data[0] : 0,
|
data.size() ? &data[0] : 0,
|
||||||
data.size() * sizeof(PodType) < max_size_in_bytes
|
data.size() * sizeof(PodType) < max_size_in_bytes
|
||||||
? data.size() * sizeof(PodType)
|
? data.size() * sizeof(PodType)
|
||||||
: max_size_in_bytes
|
: max_size_in_bytes
|
||||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||||
,
|
,
|
||||||
detail::buffer_debug_check<typename boost::container::small_vector_base<
|
detail::buffer_debug_check<typename boost::container::small_vector_base<
|
||||||
PodType, Allocator>::iterator>(data.begin())
|
PodType, Allocator>::iterator>(data.begin())
|
||||||
#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
|
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace asio
|
} // namespace asio
|
||||||
} // namespace boost
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serialize an object using bitsery and write it to a socket. This will write
|
* Serialize an object using bitsery and write it to a socket. This will write
|
||||||
* both the size of the serialized object and the object itself over the socket.
|
* both the size of the serialized object and the object itself over the socket.
|
||||||
*
|
*
|
||||||
* @param socket The Boost.Asio socket to write to.
|
* @param socket The Asio socket to write to.
|
||||||
* @param object The object to write to the stream.
|
* @param object The object to write to the stream.
|
||||||
* @param buffer The buffer to write to. This is useful for sending audio and
|
* @param buffer The buffer to write to. This is useful for sending audio and
|
||||||
* chunk data since that can vary in size by a lot.
|
* chunk data since that can vary in size by a lot.
|
||||||
@@ -149,10 +147,9 @@ inline void write_object(Socket& socket,
|
|||||||
// bit bridge. This won't make any function difference aside from the
|
// bit bridge. This won't make any function difference aside from the
|
||||||
// 32-bit host application having to convert between 64 and 32 bit
|
// 32-bit host application having to convert between 64 and 32 bit
|
||||||
// integers.
|
// integers.
|
||||||
boost::asio::write(socket,
|
asio::write(socket, asio::buffer(std::array<uint64_t, 1>{size}));
|
||||||
boost::asio::buffer(std::array<uint64_t, 1>{size}));
|
|
||||||
const size_t bytes_written =
|
const size_t bytes_written =
|
||||||
boost::asio::write(socket, boost::asio::buffer(buffer, size));
|
asio::write(socket, asio::buffer(buffer, size));
|
||||||
assert(bytes_written == size);
|
assert(bytes_written == size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,7 +168,7 @@ inline void write_object(Socket& socket, const T& object) {
|
|||||||
* Deserialize an object by reading it from a socket. This should be used
|
* Deserialize an object by reading it from a socket. This should be used
|
||||||
* together with `write_object`. This will block until the object is available.
|
* together with `write_object`. This will block until the object is available.
|
||||||
*
|
*
|
||||||
* @param socket The Boost.Asio socket to read from.
|
* @param socket The Asio socket to read from.
|
||||||
* @param object The object to serialize into. There are also overrides that
|
* @param object The object to serialize into. There are also overrides that
|
||||||
* create a new default initialized `T`
|
* create a new default initialized `T`
|
||||||
* @param buffer The buffer to read into. This is useful for sending audio and
|
* @param buffer The buffer to read into. This is useful for sending audio and
|
||||||
@@ -180,7 +177,7 @@ inline void write_object(Socket& socket, const T& object) {
|
|||||||
* @return The deserialized object.
|
* @return The deserialized object.
|
||||||
*
|
*
|
||||||
* @throw std::runtime_error If the conversion to an object was not successful.
|
* @throw std::runtime_error If the conversion to an object was not successful.
|
||||||
* @throw boost::system::system_error If the socket is closed or gets closed
|
* @throw std::system_error If the socket is closed or gets closed
|
||||||
* while reading.
|
* while reading.
|
||||||
*
|
*
|
||||||
* @relates write_object
|
* @relates write_object
|
||||||
@@ -191,18 +188,17 @@ inline T& read_object(Socket& socket,
|
|||||||
SerializationBufferBase& buffer) {
|
SerializationBufferBase& buffer) {
|
||||||
// See the note above on the use of `uint64_t` instead of `size_t`
|
// See the note above on the use of `uint64_t` instead of `size_t`
|
||||||
std::array<uint64_t, 1> message_length;
|
std::array<uint64_t, 1> message_length;
|
||||||
boost::asio::read(socket, boost::asio::buffer(message_length),
|
asio::read(socket, asio::buffer(message_length),
|
||||||
boost::asio::transfer_exactly(sizeof(message_length)));
|
asio::transfer_exactly(sizeof(message_length)));
|
||||||
|
|
||||||
// Make sure the buffer is large enough
|
// Make sure the buffer is large enough
|
||||||
const size_t size = message_length[0];
|
const size_t size = message_length[0];
|
||||||
buffer.resize(size);
|
buffer.resize(size);
|
||||||
|
|
||||||
// `boost::asio::read/write` will handle all the packet splitting and
|
// `asio::read/write` will handle all the packet splitting and
|
||||||
// merging for us, since local domain sockets have packet limits somewhere
|
// merging for us, since local domain sockets have packet limits somewhere
|
||||||
// in the hundreds of kilobytes
|
// in the hundreds of kilobytes
|
||||||
boost::asio::read(socket, boost::asio::buffer(buffer),
|
asio::read(socket, asio::buffer(buffer), asio::transfer_exactly(size));
|
||||||
boost::asio::transfer_exactly(size));
|
|
||||||
|
|
||||||
auto [_, success] =
|
auto [_, success] =
|
||||||
bitsery::quickDeserialization<InputAdapter<SerializationBufferBase>>(
|
bitsery::quickDeserialization<InputAdapter<SerializationBufferBase>>(
|
||||||
@@ -371,8 +367,8 @@ class SocketHandler {
|
|||||||
*
|
*
|
||||||
* @see Sockets::connect
|
* @see Sockets::connect
|
||||||
*/
|
*/
|
||||||
SocketHandler(boost::asio::io_context& io_context,
|
SocketHandler(asio::io_context& io_context,
|
||||||
boost::asio::local::stream_protocol::endpoint endpoint,
|
asio::local::stream_protocol::endpoint endpoint,
|
||||||
bool listen)
|
bool listen)
|
||||||
: endpoint_(endpoint), socket_(io_context) {
|
: endpoint_(endpoint), socket_(io_context) {
|
||||||
if (listen) {
|
if (listen) {
|
||||||
@@ -397,13 +393,13 @@ class SocketHandler {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Close the socket. Both sides that are actively listening will be thrown a
|
* Close the socket. Both sides that are actively listening will be thrown a
|
||||||
* `boost::system_error` when this happens.
|
* `std::system_error` when this happens.
|
||||||
*/
|
*/
|
||||||
void close() {
|
void close() {
|
||||||
// The shutdown can fail when the socket is already closed
|
// The shutdown can fail when the socket is already closed
|
||||||
boost::system::error_code err;
|
std::error_code err;
|
||||||
socket_.shutdown(
|
socket_.shutdown(asio::local::stream_protocol::socket::shutdown_both,
|
||||||
boost::asio::local::stream_protocol::socket::shutdown_both, err);
|
err);
|
||||||
socket_.close();
|
socket_.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,7 +410,7 @@ class SocketHandler {
|
|||||||
* @param buffer The buffer to use for the serialization. This is used to
|
* @param buffer The buffer to use for the serialization. This is used to
|
||||||
* prevent excess allocations when sending audio.
|
* prevent excess allocations when sending audio.
|
||||||
*
|
*
|
||||||
* @throw boost::system::system_error If the socket is closed or gets closed
|
* @throw std::system_error If the socket is closed or gets closed
|
||||||
* during sending.
|
* during sending.
|
||||||
*
|
*
|
||||||
* @warning This operation is not atomic, and calling this function with the
|
* @warning This operation is not atomic, and calling this function with the
|
||||||
@@ -454,7 +450,7 @@ class SocketHandler {
|
|||||||
*
|
*
|
||||||
* @throw std::runtime_error If the conversion to an object was not
|
* @throw std::runtime_error If the conversion to an object was not
|
||||||
* successful.
|
* successful.
|
||||||
* @throw boost::system::system_error If the socket is closed or gets closed
|
* @throw std::system_error If the socket is closed or gets closed
|
||||||
* while reading.
|
* while reading.
|
||||||
*
|
*
|
||||||
* @note This function can safely be called within the lambda of
|
* @note This function can safely be called within the lambda of
|
||||||
@@ -513,7 +509,7 @@ class SocketHandler {
|
|||||||
receive_single<T>(object, buffer);
|
receive_single<T>(object, buffer);
|
||||||
|
|
||||||
callback(object, buffer);
|
callback(object, buffer);
|
||||||
} catch (const boost::system::system_error&) {
|
} catch (const std::system_error&) {
|
||||||
// This happens when the sockets got closed because the plugin
|
// This happens when the sockets got closed because the plugin
|
||||||
// is being shut down
|
// is being shut down
|
||||||
break;
|
break;
|
||||||
@@ -522,14 +518,14 @@ class SocketHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
boost::asio::local::stream_protocol::endpoint endpoint_;
|
asio::local::stream_protocol::endpoint endpoint_;
|
||||||
boost::asio::local::stream_protocol::socket socket_;
|
asio::local::stream_protocol::socket socket_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will be used in `connect()` on the listening side to establish the
|
* Will be used in `connect()` on the listening side to establish the
|
||||||
* connection.
|
* connection.
|
||||||
*/
|
*/
|
||||||
std::optional<boost::asio::local::stream_protocol::acceptor> acceptor_;
|
std::optional<asio::local::stream_protocol::acceptor> acceptor_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -572,8 +568,8 @@ class AdHocSocketHandler {
|
|||||||
*
|
*
|
||||||
* @see Sockets::connect
|
* @see Sockets::connect
|
||||||
*/
|
*/
|
||||||
AdHocSocketHandler(boost::asio::io_context& io_context,
|
AdHocSocketHandler(asio::io_context& io_context,
|
||||||
boost::asio::local::stream_protocol::endpoint endpoint,
|
asio::local::stream_protocol::endpoint endpoint,
|
||||||
bool listen)
|
bool listen)
|
||||||
: io_context_(io_context), endpoint_(endpoint), socket_(io_context) {
|
: io_context_(io_context), endpoint_(endpoint), socket_(io_context) {
|
||||||
if (listen) {
|
if (listen) {
|
||||||
@@ -606,13 +602,13 @@ class AdHocSocketHandler {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Close the socket. Both sides that are actively listening will be thrown a
|
* Close the socket. Both sides that are actively listening will be thrown a
|
||||||
* `boost::system_error` when this happens.
|
* `std::system_error` when this happens.
|
||||||
*/
|
*/
|
||||||
void close() {
|
void close() {
|
||||||
// The shutdown can fail when the socket is already closed
|
// The shutdown can fail when the socket is already closed
|
||||||
boost::system::error_code err;
|
std::error_code err;
|
||||||
socket_.shutdown(
|
socket_.shutdown(asio::local::stream_protocol::socket::shutdown_both,
|
||||||
boost::asio::local::stream_protocol::socket::shutdown_both, err);
|
err);
|
||||||
socket_.close();
|
socket_.close();
|
||||||
|
|
||||||
while (currently_listening_) {
|
while (currently_listening_) {
|
||||||
@@ -637,15 +633,15 @@ class AdHocSocketHandler {
|
|||||||
* socket. This is either the primary `socket`, or a new ad hock socket if
|
* socket. This is either the primary `socket`, or a new ad hock socket if
|
||||||
* this function is currently being called from another thread.
|
* this function is currently being called from another thread.
|
||||||
*/
|
*/
|
||||||
template <std::invocable<boost::asio::local::stream_protocol::socket&> F>
|
template <std::invocable<asio::local::stream_protocol::socket&> F>
|
||||||
std::invoke_result_t<F, boost::asio::local::stream_protocol::socket&> send(
|
std::invoke_result_t<F, asio::local::stream_protocol::socket&> send(
|
||||||
F&& callback) {
|
F&& callback) {
|
||||||
// A bit of template and constexpr nastiness to allow us to either
|
// A bit of template and constexpr nastiness to allow us to either
|
||||||
// return a value from the callback (for when writing the response to a
|
// return a value from the callback (for when writing the response to a
|
||||||
// new object) or to return void (when we deserialize into an existing
|
// new object) or to return void (when we deserialize into an existing
|
||||||
// object)
|
// object)
|
||||||
constexpr bool returns_void = std::is_void_v<std::invoke_result_t<
|
constexpr bool returns_void = std::is_void_v<
|
||||||
F, boost::asio::local::stream_protocol::socket&>>;
|
std::invoke_result_t<F, asio::local::stream_protocol::socket&>>;
|
||||||
|
|
||||||
// XXX: Maybe at some point we should benchmark how often this
|
// XXX: Maybe at some point we should benchmark how often this
|
||||||
// ad hoc socket spawning mechanism gets used. If some hosts
|
// ad hoc socket spawning mechanism gets used. If some hosts
|
||||||
@@ -667,12 +663,12 @@ class AdHocSocketHandler {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
boost::asio::local::stream_protocol::socket secondary_socket(
|
asio::local::stream_protocol::socket secondary_socket(
|
||||||
io_context_);
|
io_context_);
|
||||||
secondary_socket.connect(endpoint_);
|
secondary_socket.connect(endpoint_);
|
||||||
|
|
||||||
return callback(secondary_socket);
|
return callback(secondary_socket);
|
||||||
} catch (const boost::system::system_error&) {
|
} catch (const std::system_error&) {
|
||||||
// So, what do we do when noone is listening on the endpoint
|
// So, what do we do when noone is listening on the endpoint
|
||||||
// yet? This can happen with plugin groups when the Wine
|
// yet? This can happen with plugin groups when the Wine
|
||||||
// host process does an `audioMaster()` call before the
|
// host process does an `audioMaster()` call before the
|
||||||
@@ -721,8 +717,8 @@ class AdHocSocketHandler {
|
|||||||
* same thing as `primary_callback`, but secondary sockets may need some
|
* same thing as `primary_callback`, but secondary sockets may need some
|
||||||
* different handling.
|
* different handling.
|
||||||
*/
|
*/
|
||||||
template <std::invocable<boost::asio::local::stream_protocol::socket&> F,
|
template <std::invocable<asio::local::stream_protocol::socket&> F,
|
||||||
std::invocable<boost::asio::local::stream_protocol::socket&> G>
|
std::invocable<asio::local::stream_protocol::socket&> G>
|
||||||
void receive_multi(std::optional<std::reference_wrapper<Logger>> logger,
|
void receive_multi(std::optional<std::reference_wrapper<Logger>> logger,
|
||||||
F&& primary_callback,
|
F&& primary_callback,
|
||||||
G&& secondary_callback) {
|
G&& secondary_callback) {
|
||||||
@@ -738,7 +734,7 @@ class AdHocSocketHandler {
|
|||||||
// thread to handle the request. When `socket` closes and this loop
|
// thread to handle the request. When `socket` closes and this loop
|
||||||
// breaks, the listener and any still active threads will be cleaned up
|
// breaks, the listener and any still active threads will be cleaned up
|
||||||
// before this function exits.
|
// before this function exits.
|
||||||
boost::asio::io_context secondary_context{};
|
asio::io_context secondary_context{};
|
||||||
|
|
||||||
// The previous acceptor has already been shut down by
|
// The previous acceptor has already been shut down by
|
||||||
// `AdHocSocketHandler::connect()`
|
// `AdHocSocketHandler::connect()`
|
||||||
@@ -751,21 +747,21 @@ class AdHocSocketHandler {
|
|||||||
std::mutex active_secondary_requests_mutex{};
|
std::mutex active_secondary_requests_mutex{};
|
||||||
accept_requests(
|
accept_requests(
|
||||||
*acceptor_, logger,
|
*acceptor_, logger,
|
||||||
[&](boost::asio::local::stream_protocol::socket secondary_socket) {
|
[&](asio::local::stream_protocol::socket secondary_socket) {
|
||||||
const size_t request_id = next_request_id.fetch_add(1);
|
const size_t request_id = next_request_id.fetch_add(1);
|
||||||
|
|
||||||
// We have to make sure to keep moving these sockets into the
|
// We have to make sure to keep moving these sockets into the
|
||||||
// threads that will handle them
|
// threads that will handle them
|
||||||
std::lock_guard lock(active_secondary_requests_mutex);
|
std::lock_guard lock(active_secondary_requests_mutex);
|
||||||
active_secondary_requests[request_id] = Thread(
|
active_secondary_requests[request_id] = Thread(
|
||||||
[&, request_id](boost::asio::local::stream_protocol::socket
|
[&, request_id](
|
||||||
secondary_socket) {
|
asio::local::stream_protocol::socket secondary_socket) {
|
||||||
secondary_callback(secondary_socket);
|
secondary_callback(secondary_socket);
|
||||||
|
|
||||||
// When we have processed this request, we'll join the
|
// When we have processed this request, we'll join the
|
||||||
// thread again with the thread that's handling
|
// thread again with the thread that's handling
|
||||||
// `secondary_context`
|
// `secondary_context`
|
||||||
boost::asio::post(secondary_context, [&, request_id]() {
|
asio::post(secondary_context, [&, request_id]() {
|
||||||
std::lock_guard lock(
|
std::lock_guard lock(
|
||||||
active_secondary_requests_mutex);
|
active_secondary_requests_mutex);
|
||||||
|
|
||||||
@@ -791,7 +787,7 @@ class AdHocSocketHandler {
|
|||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
primary_callback(socket_);
|
primary_callback(socket_);
|
||||||
} catch (const boost::system::system_error&) {
|
} catch (const std::system_error&) {
|
||||||
// This happens when the sockets got closed because the plugin
|
// This happens when the sockets got closed because the plugin
|
||||||
// is being shut down
|
// is being shut down
|
||||||
break;
|
break;
|
||||||
@@ -814,7 +810,7 @@ class AdHocSocketHandler {
|
|||||||
*
|
*
|
||||||
* @overload
|
* @overload
|
||||||
*/
|
*/
|
||||||
template <std::invocable<boost::asio::local::stream_protocol::socket&> F>
|
template <std::invocable<asio::local::stream_protocol::socket&> F>
|
||||||
void receive_multi(std::optional<std::reference_wrapper<Logger>> logger,
|
void receive_multi(std::optional<std::reference_wrapper<Logger>> logger,
|
||||||
F&& callback) {
|
F&& callback) {
|
||||||
receive_multi(logger, callback, std::forward<F>(callback));
|
receive_multi(logger, callback, std::forward<F>(callback));
|
||||||
@@ -831,16 +827,15 @@ class AdHocSocketHandler {
|
|||||||
* should only be passed on the plugin side.
|
* should only be passed on the plugin side.
|
||||||
* @param callback A function that handles the new socket connection.
|
* @param callback A function that handles the new socket connection.
|
||||||
*/
|
*/
|
||||||
template <std::invocable<boost::asio::local::stream_protocol::socket> F>
|
template <std::invocable<asio::local::stream_protocol::socket> F>
|
||||||
void accept_requests(
|
void accept_requests(asio::local::stream_protocol::acceptor& acceptor,
|
||||||
boost::asio::local::stream_protocol::acceptor& acceptor,
|
std::optional<std::reference_wrapper<Logger>> logger,
|
||||||
std::optional<std::reference_wrapper<Logger>> logger,
|
F&& callback) {
|
||||||
F&& callback) {
|
|
||||||
acceptor.async_accept(
|
acceptor.async_accept(
|
||||||
[&, logger, callback](
|
[&, logger, callback](
|
||||||
const boost::system::error_code& error,
|
const std::error_code& error,
|
||||||
boost::asio::local::stream_protocol::socket secondary_socket) {
|
asio::local::stream_protocol::socket secondary_socket) {
|
||||||
if (error.failed()) {
|
if (error) {
|
||||||
// On the Wine side it's expected that the primary socket
|
// On the Wine side it's expected that the primary socket
|
||||||
// connection will be dropped during shutdown, so we can
|
// connection will be dropped during shutdown, so we can
|
||||||
// silently ignore any related socket errors on the Wine
|
// silently ignore any related socket errors on the Wine
|
||||||
@@ -865,10 +860,10 @@ class AdHocSocketHandler {
|
|||||||
* bound to this context. In `receive_multi()` we'll create a new IO context
|
* bound to this context. In `receive_multi()` we'll create a new IO context
|
||||||
* since we want to do all listening there on a dedicated thread.
|
* since we want to do all listening there on a dedicated thread.
|
||||||
*/
|
*/
|
||||||
boost::asio::io_context& io_context_;
|
asio::io_context& io_context_;
|
||||||
|
|
||||||
boost::asio::local::stream_protocol::endpoint endpoint_;
|
asio::local::stream_protocol::endpoint endpoint_;
|
||||||
boost::asio::local::stream_protocol::socket socket_;
|
asio::local::stream_protocol::socket socket_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This acceptor will be used once synchronously on the listening side
|
* This acceptor will be used once synchronously on the listening side
|
||||||
@@ -880,7 +875,7 @@ class AdHocSocketHandler {
|
|||||||
* but all additional incoming connections of course have to be listened for
|
* but all additional incoming connections of course have to be listened for
|
||||||
* on the plugin side.
|
* on the plugin side.
|
||||||
*/
|
*/
|
||||||
std::optional<boost::asio::local::stream_protocol::acceptor> acceptor_;
|
std::optional<asio::local::stream_protocol::acceptor> acceptor_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* After the socket gets closed, we do some cleanup at the end of
|
* After the socket gets closed, we do some cleanup at the end of
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ intptr_t DefaultDataConverter::return_value(const int /*opcode*/,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Vst2EventResult DefaultDataConverter::send_event(
|
Vst2EventResult DefaultDataConverter::send_event(
|
||||||
boost::asio::local::stream_protocol::socket& socket,
|
asio::local::stream_protocol::socket& socket,
|
||||||
const Vst2Event& event,
|
const Vst2Event& event,
|
||||||
SerializationBufferBase& buffer) const {
|
SerializationBufferBase& buffer) const {
|
||||||
write_object(socket, event, buffer);
|
write_object(socket, event, buffer);
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ class DefaultDataConverter {
|
|||||||
* specific opcodes to allow mutually recursive calling sequences.
|
* specific opcodes to allow mutually recursive calling sequences.
|
||||||
*/
|
*/
|
||||||
virtual Vst2EventResult send_event(
|
virtual Vst2EventResult send_event(
|
||||||
boost::asio::local::stream_protocol::socket& socket,
|
asio::local::stream_protocol::socket& socket,
|
||||||
const Vst2Event& event,
|
const Vst2Event& event,
|
||||||
SerializationBufferBase& buffer) const;
|
SerializationBufferBase& buffer) const;
|
||||||
};
|
};
|
||||||
@@ -137,8 +137,8 @@ class Vst2EventHandler : public AdHocSocketHandler<Thread> {
|
|||||||
*
|
*
|
||||||
* @see Sockets::connect
|
* @see Sockets::connect
|
||||||
*/
|
*/
|
||||||
Vst2EventHandler(boost::asio::io_context& io_context,
|
Vst2EventHandler(asio::io_context& io_context,
|
||||||
boost::asio::local::stream_protocol::endpoint endpoint,
|
asio::local::stream_protocol::endpoint endpoint,
|
||||||
bool listen)
|
bool listen)
|
||||||
: AdHocSocketHandler<Thread>(io_context, endpoint, listen) {}
|
: AdHocSocketHandler<Thread>(io_context, endpoint, listen) {}
|
||||||
|
|
||||||
@@ -206,7 +206,7 @@ class Vst2EventHandler : public AdHocSocketHandler<Thread> {
|
|||||||
// that potentially need to have their responses handled on the same
|
// that potentially need to have their responses handled on the same
|
||||||
// calling thread (i.e. mutual recursion).
|
// calling thread (i.e. mutual recursion).
|
||||||
const Vst2EventResult response = this->send(
|
const Vst2EventResult response = this->send(
|
||||||
[&](boost::asio::local::stream_protocol::socket& socket) {
|
[&](asio::local::stream_protocol::socket& socket) {
|
||||||
return data_converter.send_event(socket, event,
|
return data_converter.send_event(socket, event,
|
||||||
serialization_buffer());
|
serialization_buffer());
|
||||||
});
|
});
|
||||||
@@ -250,7 +250,7 @@ class Vst2EventHandler : public AdHocSocketHandler<Thread> {
|
|||||||
// Reading, processing, and writing back event data from the sockets
|
// Reading, processing, and writing back event data from the sockets
|
||||||
// works in the same way regardless of which socket we're using
|
// works in the same way regardless of which socket we're using
|
||||||
const auto process_event =
|
const auto process_event =
|
||||||
[&](boost::asio::local::stream_protocol::socket& socket,
|
[&](asio::local::stream_protocol::socket& socket,
|
||||||
bool on_main_thread) {
|
bool on_main_thread) {
|
||||||
SerializationBufferBase& buffer = serialization_buffer();
|
SerializationBufferBase& buffer = serialization_buffer();
|
||||||
|
|
||||||
@@ -276,10 +276,10 @@ class Vst2EventHandler : public AdHocSocketHandler<Thread> {
|
|||||||
this->receive_multi(
|
this->receive_multi(
|
||||||
logging ? std::optional(std::ref(logging->first.logger_))
|
logging ? std::optional(std::ref(logging->first.logger_))
|
||||||
: std::nullopt,
|
: std::nullopt,
|
||||||
[&](boost::asio::local::stream_protocol::socket& socket) {
|
[&](asio::local::stream_protocol::socket& socket) {
|
||||||
process_event(socket, true);
|
process_event(socket, true);
|
||||||
},
|
},
|
||||||
[&](boost::asio::local::stream_protocol::socket& socket) {
|
[&](asio::local::stream_protocol::socket& socket) {
|
||||||
process_event(socket, false);
|
process_event(socket, false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -342,7 +342,7 @@ class Vst2Sockets final : public Sockets {
|
|||||||
*
|
*
|
||||||
* @see Vst2Sockets::connect
|
* @see Vst2Sockets::connect
|
||||||
*/
|
*/
|
||||||
Vst2Sockets(boost::asio::io_context& io_context,
|
Vst2Sockets(asio::io_context& io_context,
|
||||||
const ghc::filesystem::path& endpoint_base_dir,
|
const ghc::filesystem::path& endpoint_base_dir,
|
||||||
bool listen)
|
bool listen)
|
||||||
: Sockets(endpoint_base_dir),
|
: Sockets(endpoint_base_dir),
|
||||||
|
|||||||
@@ -57,8 +57,8 @@ class Vst3MessageHandler : public AdHocSocketHandler<Thread> {
|
|||||||
*
|
*
|
||||||
* @see Sockets::connect
|
* @see Sockets::connect
|
||||||
*/
|
*/
|
||||||
Vst3MessageHandler(boost::asio::io_context& io_context,
|
Vst3MessageHandler(asio::io_context& io_context,
|
||||||
boost::asio::local::stream_protocol::endpoint endpoint,
|
asio::local::stream_protocol::endpoint endpoint,
|
||||||
bool listen)
|
bool listen)
|
||||||
: AdHocSocketHandler<Thread>(io_context, endpoint, listen) {}
|
: AdHocSocketHandler<Thread>(io_context, endpoint, listen) {}
|
||||||
|
|
||||||
@@ -138,7 +138,7 @@ class Vst3MessageHandler : public AdHocSocketHandler<Thread> {
|
|||||||
// messages from arriving out of order. `AdHocSocketHandler::send()`
|
// messages from arriving out of order. `AdHocSocketHandler::send()`
|
||||||
// will either use a long-living primary socket, or if that's currently
|
// will either use a long-living primary socket, or if that's currently
|
||||||
// in use it will spawn a new socket for us.
|
// in use it will spawn a new socket for us.
|
||||||
this->send([&](boost::asio::local::stream_protocol::socket& socket) {
|
this->send([&](asio::local::stream_protocol::socket& socket) {
|
||||||
write_object(socket, Request(object), buffer);
|
write_object(socket, Request(object), buffer);
|
||||||
read_object<TResponse>(socket, response_object, buffer);
|
read_object<TResponse>(socket, response_object, buffer);
|
||||||
});
|
});
|
||||||
@@ -205,7 +205,7 @@ class Vst3MessageHandler : public AdHocSocketHandler<Thread> {
|
|||||||
// we receive works in the same way regardless of which socket we're
|
// we receive works in the same way regardless of which socket we're
|
||||||
// using
|
// using
|
||||||
const auto process_message =
|
const auto process_message =
|
||||||
[&](boost::asio::local::stream_protocol::socket& socket) {
|
[&](asio::local::stream_protocol::socket& socket) {
|
||||||
// The persistent buffer is only used when the
|
// The persistent buffer is only used when the
|
||||||
// `persistent_buffers` template value is enabled, but we'll
|
// `persistent_buffers` template value is enabled, but we'll
|
||||||
// always use the thread local persistent object. Because of
|
// always use the thread local persistent object. Because of
|
||||||
@@ -310,7 +310,7 @@ class Vst3Sockets final : public Sockets {
|
|||||||
*
|
*
|
||||||
* @see Vst3Sockets::connect
|
* @see Vst3Sockets::connect
|
||||||
*/
|
*/
|
||||||
Vst3Sockets(boost::asio::io_context& io_context,
|
Vst3Sockets(asio::io_context& io_context,
|
||||||
const ghc::filesystem::path& endpoint_base_dir,
|
const ghc::filesystem::path& endpoint_base_dir,
|
||||||
bool listen)
|
bool listen)
|
||||||
: Sockets(endpoint_base_dir),
|
: Sockets(endpoint_base_dir),
|
||||||
@@ -513,7 +513,7 @@ class Vst3Sockets final : public Sockets {
|
|||||||
audio_processor_buffer);
|
audio_processor_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::asio::io_context& io_context_;
|
asio::io_context& io_context_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Every `IAudioProcessor` or `IComponent` instance (which likely implements
|
* Every `IAudioProcessor` or `IComponent` instance (which likely implements
|
||||||
|
|||||||
+208
-11
@@ -21,12 +21,21 @@
|
|||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
#ifdef __WINE__
|
#ifdef __WINE__
|
||||||
#include "../wine-host/boost-fix.h"
|
#include "../wine-host/asio-fix.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <boost/asio/read_until.hpp>
|
#include <asio/read_until.hpp>
|
||||||
#include <boost/asio/streambuf.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/async_pipe.hpp>
|
||||||
|
#include <boost/process/detail/posix/pipe_out.hpp>
|
||||||
|
#include <boost/process/posix.hpp>
|
||||||
|
|
||||||
#include "../utils.h"
|
#include "../utils.h"
|
||||||
|
|
||||||
@@ -39,12 +48,200 @@
|
|||||||
*
|
*
|
||||||
* Check if this is still needed for other distros after Arch starts packaging
|
* Check if this is still needed for other distros after Arch starts packaging
|
||||||
* Boost 1.73.
|
* 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 : public boost::process::async_pipe {
|
class patched_async_pipe {
|
||||||
public:
|
::asio::posix::stream_descriptor _source;
|
||||||
using boost::process::async_pipe::async_pipe;
|
::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;
|
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) {}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -160,21 +357,21 @@ class Logger {
|
|||||||
* Write output from an async pipe to the log on a line by line basis.
|
* Write output from an async pipe to the log on a line by line basis.
|
||||||
* Useful for logging the Wine process's STDOUT and STDERR streams.
|
* Useful for logging the Wine process's STDOUT and STDERR streams.
|
||||||
*
|
*
|
||||||
* @param pipe Some Boost.Asio stream that can be read from. Probably either
|
* @param pipe Some Asio stream that can be read from. Probably either
|
||||||
* `patched_async_pipe` or a stream descriptor.
|
* `patched_async_pipe` or a stream descriptor.
|
||||||
* @param buffer The buffer that will be used to read from `pipe`.
|
* @param buffer The buffer that will be used to read from `pipe`.
|
||||||
* @param prefix Text to prepend to the line before writing to the log.
|
* @param prefix Text to prepend to the line before writing to the log.
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void async_log_pipe_lines(T& pipe,
|
void async_log_pipe_lines(T& pipe,
|
||||||
boost::asio::streambuf& buffer,
|
asio::streambuf& buffer,
|
||||||
std::string prefix = "") {
|
std::string prefix = "") {
|
||||||
boost::asio::async_read_until(
|
asio::async_read_until(
|
||||||
pipe, buffer, '\n',
|
pipe, buffer, '\n',
|
||||||
[&, prefix](const boost::system::error_code& error, size_t) {
|
[&, prefix](const std::error_code& error, size_t) {
|
||||||
// When we get an error code then that likely means that the
|
// When we get an error code then that likely means that the
|
||||||
// pipe has been clsoed and we have reached the end of the file
|
// pipe has been clsoed and we have reached the end of the file
|
||||||
if (error.failed()) {
|
if (error) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,10 +21,10 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
#ifdef __WINE__
|
#ifdef __WINE__
|
||||||
#include "../wine-host/boost-fix.h"
|
#include "../wine-host/asio-fix.h"
|
||||||
#endif
|
#endif
|
||||||
#include <boost/asio/dispatch.hpp>
|
#include <asio/dispatch.hpp>
|
||||||
#include <boost/asio/io_context.hpp>
|
#include <asio/io_context.hpp>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A helper to allow mutually recursive calling sequences with remote function
|
* A helper to allow mutually recursive calling sequences with remote function
|
||||||
@@ -83,8 +83,8 @@ class MutualRecursionHelper {
|
|||||||
// as we need to support multiple levels of mutual recursion. This can
|
// as we need to support multiple levels of mutual recursion. This can
|
||||||
// for instance happen during `IPlugView::attached() ->
|
// for instance happen during `IPlugView::attached() ->
|
||||||
// IPlugFrame::resizeView() -> IPlugView::onSize()`.
|
// IPlugFrame::resizeView() -> IPlugView::onSize()`.
|
||||||
std::shared_ptr<boost::asio::io_context> current_io_context =
|
std::shared_ptr<asio::io_context> current_io_context =
|
||||||
std::make_shared<boost::asio::io_context>();
|
std::make_shared<asio::io_context>();
|
||||||
{
|
{
|
||||||
std::unique_lock lock(mutual_recursion_contexts_mutex_);
|
std::unique_lock lock(mutual_recursion_contexts_mutex_);
|
||||||
mutual_recursion_contexts_.push_back(current_io_context);
|
mutual_recursion_contexts_.push_back(current_io_context);
|
||||||
@@ -93,7 +93,7 @@ class MutualRecursionHelper {
|
|||||||
// Instead of directly stopping the IO context, we'll reset this work
|
// Instead of directly stopping the IO context, we'll reset this work
|
||||||
// guard instead. This prevents us from accidentally cancelling any
|
// guard instead. This prevents us from accidentally cancelling any
|
||||||
// outstanding tasks.
|
// outstanding tasks.
|
||||||
auto work_guard = boost::asio::make_work_guard(*current_io_context);
|
auto work_guard = asio::make_work_guard(*current_io_context);
|
||||||
|
|
||||||
// We will call the function from another thread so we can handle calls
|
// We will call the function from another thread so we can handle calls
|
||||||
// to `handle()`/`maybe_handle()` from this thread
|
// to `handle()`/`maybe_handle()` from this thread
|
||||||
@@ -168,7 +168,7 @@ class MutualRecursionHelper {
|
|||||||
// pretend that we're not doing any async things here
|
// pretend that we're not doing any async things here
|
||||||
std::packaged_task<Result()> do_call(std::forward<F>(fn));
|
std::packaged_task<Result()> do_call(std::forward<F>(fn));
|
||||||
std::future<Result> do_call_response = do_call.get_future();
|
std::future<Result> do_call_response = do_call.get_future();
|
||||||
boost::asio::dispatch(*mutual_recursion_contexts_.back(),
|
asio::dispatch(*mutual_recursion_contexts_.back(),
|
||||||
std::move(do_call));
|
std::move(do_call));
|
||||||
mutual_recursion_lock.unlock();
|
mutual_recursion_lock.unlock();
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ class MutualRecursionHelper {
|
|||||||
* active one. If the stack is empty, then there's currently no mutual
|
* active one. If the stack is empty, then there's currently no mutual
|
||||||
* recursion going on.
|
* recursion going on.
|
||||||
*/
|
*/
|
||||||
std::vector<std::shared_ptr<boost::asio::io_context>>
|
std::vector<std::shared_ptr<asio::io_context>>
|
||||||
mutual_recursion_contexts_;
|
mutual_recursion_contexts_;
|
||||||
std::mutex mutual_recursion_contexts_mutex_;
|
std::mutex mutual_recursion_contexts_mutex_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ class PluginBridge {
|
|||||||
* found, or if it could not locate and load a VST3 module.
|
* found, or if it could not locate and load a VST3 module.
|
||||||
*/
|
*/
|
||||||
template <invocable_returning<TSockets,
|
template <invocable_returning<TSockets,
|
||||||
boost::asio::io_context&,
|
asio::io_context&,
|
||||||
const PluginInfo&> F>
|
const PluginInfo&> F>
|
||||||
PluginBridge(PluginType plugin_type, F&& create_socket_instance)
|
PluginBridge(PluginType plugin_type, F&& create_socket_instance)
|
||||||
// This is still correct for VST3 plugins because we can configure an
|
// This is still correct for VST3 plugins because we can configure an
|
||||||
@@ -367,7 +367,7 @@ class PluginBridge {
|
|||||||
// sockets and we'll be hanging here indefinitely. To prevent this,
|
// sockets and we'll be hanging here indefinitely. To prevent this,
|
||||||
// we'll periodically poll whether the Wine process is still running,
|
// we'll periodically poll whether the Wine process is still running,
|
||||||
// and throw when it is not. The alternative would be to rewrite this to
|
// and throw when it is not. The alternative would be to rewrite this to
|
||||||
// using `async_accept`, Boost.Asio timers, and another IO context, but
|
// using `async_accept`, Asio timers, and another IO context, but
|
||||||
// I feel like this a much simpler solution.
|
// I feel like this a much simpler solution.
|
||||||
host_watchdog_handler_ = std::jthread([&](std::stop_token st) {
|
host_watchdog_handler_ = std::jthread([&](std::stop_token st) {
|
||||||
using namespace std::literals::chrono_literals;
|
using namespace std::literals::chrono_literals;
|
||||||
@@ -441,7 +441,7 @@ class PluginBridge {
|
|||||||
*/
|
*/
|
||||||
const PluginInfo info_;
|
const PluginInfo info_;
|
||||||
|
|
||||||
boost::asio::io_context io_context_;
|
asio::io_context io_context_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The sockets used for communication with the Wine process.
|
* The sockets used for communication with the Wine process.
|
||||||
@@ -485,7 +485,7 @@ class PluginBridge {
|
|||||||
std::future<bool> has_realtime_priority_;
|
std::future<bool> has_realtime_priority_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs the Boost.Asio `io_context_` thread for logging the Wine process
|
* Runs the Asio `io_context_` thread for logging the Wine process
|
||||||
* STDOUT and STDERR messages.
|
* STDOUT and STDERR messages.
|
||||||
*/
|
*/
|
||||||
std::jthread wine_io_handler_;
|
std::jthread wine_io_handler_;
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ Vst2PluginBridge& get_bridge_instance(const AEffect& plugin) noexcept {
|
|||||||
Vst2PluginBridge::Vst2PluginBridge(audioMasterCallback host_callback)
|
Vst2PluginBridge::Vst2PluginBridge(audioMasterCallback host_callback)
|
||||||
: PluginBridge(
|
: PluginBridge(
|
||||||
PluginType::vst2,
|
PluginType::vst2,
|
||||||
[](boost::asio::io_context& io_context, const PluginInfo& info) {
|
[](asio::io_context& io_context, const PluginInfo& info) {
|
||||||
return Vst2Sockets<std::jthread>(
|
return Vst2Sockets<std::jthread>(
|
||||||
io_context,
|
io_context,
|
||||||
generate_endpoint_base(info.native_library_path_.filename()
|
generate_endpoint_base(info.native_library_path_.filename()
|
||||||
@@ -199,7 +199,7 @@ Vst2PluginBridge::~Vst2PluginBridge() noexcept {
|
|||||||
// The `stop()` method will cause the IO context to just drop all of its
|
// The `stop()` method will cause the IO context to just drop all of its
|
||||||
// outstanding work immediately
|
// outstanding work immediately
|
||||||
io_context_.stop();
|
io_context_.stop();
|
||||||
} catch (const boost::system::system_error&) {
|
} catch (const std::system_error&) {
|
||||||
// It could be that the sockets have already been closed or that the
|
// It could be that the sockets have already been closed or that the
|
||||||
// process has already exited (at which point we probably won't be
|
// process has already exited (at which point we probably won't be
|
||||||
// executing this, but maybe if all the stars align)
|
// executing this, but maybe if all the stars align)
|
||||||
@@ -538,7 +538,7 @@ intptr_t Vst2PluginBridge::dispatch(AEffect* /*plugin*/,
|
|||||||
return_value = sockets_.host_vst_dispatch_.send_event(
|
return_value = sockets_.host_vst_dispatch_.send_event(
|
||||||
converter, std::pair<Vst2Logger&, bool>(logger_, true),
|
converter, std::pair<Vst2Logger&, bool>(logger_, true),
|
||||||
opcode, index, value, data, option);
|
opcode, index, value, data, option);
|
||||||
} catch (const boost::system::system_error&) {
|
} catch (const std::system_error&) {
|
||||||
// Thrown when the socket gets closed because the VST plugin
|
// Thrown when the socket gets closed because the VST plugin
|
||||||
// loaded into the Wine process crashed during shutdown
|
// loaded into the Wine process crashed during shutdown
|
||||||
logger_.log("The plugin crashed during shutdown, ignoring");
|
logger_.log("The plugin crashed during shutdown, ignoring");
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
#include <vestige/aeffectx.h>
|
#include <vestige/aeffectx.h>
|
||||||
|
|
||||||
#include <boost/asio/io_context.hpp>
|
#include <asio/io_context.hpp>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "../../common/communication/vst2.h"
|
#include "../../common/communication/vst2.h"
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class RunLoopTasks : public Steinberg::Linux::IEventHandler {
|
|||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Register an event handler in the host's run loop so we can schedule tasks
|
* Register an event handler in the host's run loop so we can schedule tasks
|
||||||
* to be run from there. This works very much like how we use Boost.Asio IO
|
* to be run from there. This works very much like how we use Asio IO
|
||||||
* contexts everywhere else to run functions on other threads. All of this
|
* contexts everywhere else to run functions on other threads. All of this
|
||||||
* is backed by a dummy Unix domain socket, although REAPER will call the
|
* is backed by a dummy Unix domain socket, although REAPER will call the
|
||||||
* event handler regardless of whether the file descriptor is ready or not.
|
* event handler regardless of whether the file descriptor is ready or not.
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ using namespace std::literals::string_literals;
|
|||||||
Vst3PluginBridge::Vst3PluginBridge()
|
Vst3PluginBridge::Vst3PluginBridge()
|
||||||
: PluginBridge(
|
: PluginBridge(
|
||||||
PluginType::vst3,
|
PluginType::vst3,
|
||||||
[](boost::asio::io_context& io_context, const PluginInfo& info) {
|
[](asio::io_context& io_context, const PluginInfo& info) {
|
||||||
return Vst3Sockets<std::jthread>(
|
return Vst3Sockets<std::jthread>(
|
||||||
io_context,
|
io_context,
|
||||||
generate_endpoint_base(info.native_library_path_.filename()
|
generate_endpoint_base(info.native_library_path_.filename()
|
||||||
@@ -415,7 +415,7 @@ Vst3PluginBridge::~Vst3PluginBridge() noexcept {
|
|||||||
// Drop all work make sure all sockets are closed
|
// Drop all work make sure all sockets are closed
|
||||||
plugin_host_->terminate();
|
plugin_host_->terminate();
|
||||||
io_context_.stop();
|
io_context_.stop();
|
||||||
} catch (const boost::system::system_error&) {
|
} catch (const std::system_error&) {
|
||||||
// It could be that the sockets have already been closed or that the
|
// It could be that the sockets have already been closed or that the
|
||||||
// process has already exited (at which point we probably won't be
|
// process has already exited (at which point we probably won't be
|
||||||
// executing this, but maybe if all the stars align)
|
// executing this, but maybe if all the stars align)
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#include "host-process.h"
|
#include "host-process.h"
|
||||||
|
|
||||||
#include <boost/asio/read_until.hpp>
|
#include <asio/read_until.hpp>
|
||||||
#include <boost/process/env.hpp>
|
#include <boost/process/env.hpp>
|
||||||
#include <boost/process/start_dir.hpp>
|
#include <boost/process/start_dir.hpp>
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
namespace bp = boost::process;
|
namespace bp = boost::process;
|
||||||
namespace fs = ghc::filesystem;
|
namespace fs = ghc::filesystem;
|
||||||
|
|
||||||
HostProcess::HostProcess(boost::asio::io_context& io_context,
|
HostProcess::HostProcess(asio::io_context& io_context,
|
||||||
Logger& logger,
|
Logger& logger,
|
||||||
const Configuration& config,
|
const Configuration& config,
|
||||||
Sockets& sockets)
|
Sockets& sockets)
|
||||||
@@ -53,7 +53,7 @@ HostProcess::HostProcess(boost::asio::io_context& io_context,
|
|||||||
|
|
||||||
HostProcess::~HostProcess() noexcept {}
|
HostProcess::~HostProcess() noexcept {}
|
||||||
|
|
||||||
IndividualHost::IndividualHost(boost::asio::io_context& io_context,
|
IndividualHost::IndividualHost(asio::io_context& io_context,
|
||||||
Logger& logger,
|
Logger& logger,
|
||||||
const Configuration& config,
|
const Configuration& config,
|
||||||
Sockets& sockets,
|
Sockets& sockets,
|
||||||
@@ -115,7 +115,7 @@ void IndividualHost::terminate() {
|
|||||||
host_.wait();
|
host_.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupHost::GroupHost(boost::asio::io_context& io_context,
|
GroupHost::GroupHost(asio::io_context& io_context,
|
||||||
Logger& logger,
|
Logger& logger,
|
||||||
const Configuration& config,
|
const Configuration& config,
|
||||||
Sockets& sockets,
|
Sockets& sockets,
|
||||||
@@ -140,7 +140,7 @@ GroupHost::GroupHost(boost::asio::io_context& io_context,
|
|||||||
plugin_info.plugin_arch_);
|
plugin_info.plugin_arch_);
|
||||||
const auto connect = [&io_context, host_request, endpoint_base_dir,
|
const auto connect = [&io_context, host_request, endpoint_base_dir,
|
||||||
group_socket_path]() {
|
group_socket_path]() {
|
||||||
boost::asio::local::stream_protocol::socket group_socket(io_context);
|
asio::local::stream_protocol::socket group_socket(io_context);
|
||||||
group_socket.connect(group_socket_path.string());
|
group_socket.connect(group_socket_path.string());
|
||||||
|
|
||||||
write_object(group_socket, host_request);
|
write_object(group_socket, host_request);
|
||||||
@@ -151,7 +151,7 @@ GroupHost::GroupHost(boost::asio::io_context& io_context,
|
|||||||
try {
|
try {
|
||||||
// Request an existing group host process to host our plugin
|
// Request an existing group host process to host our plugin
|
||||||
connect();
|
connect();
|
||||||
} catch (const boost::system::system_error&) {
|
} catch (const std::system_error&) {
|
||||||
// In case we could not connect to the socket, then we'll start a
|
// In case we could not connect to the socket, then we'll start a
|
||||||
// new group host process. This process is detached immediately
|
// new group host process. This process is detached immediately
|
||||||
// because it should run independently of this yabridge instance as
|
// because it should run independently of this yabridge instance as
|
||||||
@@ -178,7 +178,7 @@ GroupHost::GroupHost(boost::asio::io_context& io_context,
|
|||||||
try {
|
try {
|
||||||
connect();
|
connect();
|
||||||
return;
|
return;
|
||||||
} catch (const boost::system::system_error&) {
|
} catch (const std::system_error&) {
|
||||||
// Keep trying to connect until either connection gets
|
// Keep trying to connect until either connection gets
|
||||||
// accepted or the group host crashes
|
// accepted or the group host crashes
|
||||||
}
|
}
|
||||||
@@ -191,7 +191,7 @@ GroupHost::GroupHost(boost::asio::io_context& io_context,
|
|||||||
// connect once more, before concluding that we failed.
|
// connect once more, before concluding that we failed.
|
||||||
try {
|
try {
|
||||||
connect();
|
connect();
|
||||||
} catch (const boost::system::system_error&) {
|
} catch (const std::system_error&) {
|
||||||
startup_failed_ = true;
|
startup_failed_ = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,8 +18,8 @@
|
|||||||
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include <boost/asio/local/stream_protocol.hpp>
|
#include <asio/local/stream_protocol.hpp>
|
||||||
#include <boost/asio/streambuf.hpp>
|
#include <asio/streambuf.hpp>
|
||||||
#include <boost/process/child.hpp>
|
#include <boost/process/child.hpp>
|
||||||
#include <boost/process/extend.hpp>
|
#include <boost/process/extend.hpp>
|
||||||
#include <boost/process/io.hpp>
|
#include <boost/process/io.hpp>
|
||||||
@@ -91,8 +91,11 @@ class HostProcess {
|
|||||||
// FIXME: Replace Boost.Filesystem
|
// FIXME: Replace Boost.Filesystem
|
||||||
host_path.string(),
|
host_path.string(),
|
||||||
#endif // WITH_WINEDBG
|
#endif // WITH_WINEDBG
|
||||||
boost::process::std_out = stdout_pipe_,
|
// FIXME: This won't work with our patched async_pipe version
|
||||||
boost::process::std_err = stderr_pipe_,
|
// boost::process::std_out = stdout_pipe_,
|
||||||
|
// boost::process::std_err = stderr_pipe_,
|
||||||
|
patched_async_pipe_out<1, -1>(stdout_pipe_),
|
||||||
|
patched_async_pipe_out<2, -1>(stderr_pipe_),
|
||||||
// NOTE: If the Wine process outlives the host, then it may cause
|
// NOTE: If the Wine process outlives the host, then it may cause
|
||||||
// issues if our process is still keeping the host's file
|
// issues if our process is still keeping the host's file
|
||||||
// descriptors alive that. This can prevent Ardour from
|
// descriptors alive that. This can prevent Ardour from
|
||||||
@@ -140,7 +143,7 @@ class HostProcess {
|
|||||||
* with the plugin. When the plugin shuts down, we'll close all of the
|
* with the plugin. When the plugin shuts down, we'll close all of the
|
||||||
* sockets used by the plugin.
|
* sockets used by the plugin.
|
||||||
*/
|
*/
|
||||||
HostProcess(boost::asio::io_context& io_context,
|
HostProcess(asio::io_context& io_context,
|
||||||
Logger& logger,
|
Logger& logger,
|
||||||
const Configuration& config,
|
const Configuration& config,
|
||||||
Sockets& sockets);
|
Sockets& sockets);
|
||||||
@@ -171,8 +174,8 @@ class HostProcess {
|
|||||||
*/
|
*/
|
||||||
Logger& logger_;
|
Logger& logger_;
|
||||||
|
|
||||||
boost::asio::streambuf stdout_buffer_;
|
asio::streambuf stdout_buffer_;
|
||||||
boost::asio::streambuf stderr_buffer_;
|
asio::streambuf stderr_buffer_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -201,7 +204,7 @@ class IndividualHost : public HostProcess {
|
|||||||
* @throw std::runtime_error When `plugin_path` does not point to a valid
|
* @throw std::runtime_error When `plugin_path` does not point to a valid
|
||||||
* 32-bit or 64-bit .dll file.
|
* 32-bit or 64-bit .dll file.
|
||||||
*/
|
*/
|
||||||
IndividualHost(boost::asio::io_context& io_context,
|
IndividualHost(asio::io_context& io_context,
|
||||||
Logger& logger,
|
Logger& logger,
|
||||||
const Configuration& config,
|
const Configuration& config,
|
||||||
Sockets& sockets,
|
Sockets& sockets,
|
||||||
@@ -249,7 +252,7 @@ class GroupHost : public HostProcess {
|
|||||||
* @param host_request The information about the plugin we should launch a
|
* @param host_request The information about the plugin we should launch a
|
||||||
* host process for. This object will be sent to the group host process.
|
* host process for. This object will be sent to the group host process.
|
||||||
*/
|
*/
|
||||||
GroupHost(boost::asio::io_context& io_context,
|
GroupHost(asio::io_context& io_context,
|
||||||
Logger& logger,
|
Logger& logger,
|
||||||
const Configuration& config,
|
const Configuration& config,
|
||||||
Sockets& sockets,
|
Sockets& sockets,
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
#include <boost/dll/runtime_symbol_info.hpp>
|
#include <boost/dll/runtime_symbol_info.hpp>
|
||||||
#include <boost/process/io.hpp>
|
#include <boost/process/io.hpp>
|
||||||
#include <boost/process/pipe.hpp>
|
#include <boost/process/pipe.hpp>
|
||||||
#include <boost/process/posix.hpp>
|
|
||||||
#include <boost/process/search_path.hpp>
|
#include <boost/process/search_path.hpp>
|
||||||
#include <boost/process/system.hpp>
|
#include <boost/process/system.hpp>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -466,7 +465,7 @@ bool send_notification(const std::string& title,
|
|||||||
<< "\">"
|
<< "\">"
|
||||||
<< xml_escape(this_library.filename().string())
|
<< xml_escape(this_library.filename().string())
|
||||||
<< "</a>";
|
<< "</a>";
|
||||||
} catch (const boost::system::system_error&) {
|
} catch (const std::system_error&) {
|
||||||
// I don't think this can fail in the way we're using it, but the
|
// I don't think this can fail in the way we're using it, but the
|
||||||
// last thing we want is our notification informing the user of an
|
// last thing we want is our notification informing the user of an
|
||||||
// exception to trigger another exception
|
// exception to trigger another exception
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
// yabridge: a Wine VST bridge
|
||||||
|
// Copyright (C) 2020-2022 Robbert van der Helm
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Libraries like (Boost.)Asio think we're compiling on Windows or using a MSVC
|
||||||
|
// toolchain. This will cause them to make incorrect assumptions which platform
|
||||||
|
// specific features are available. The only way around this I could think of
|
||||||
|
// was to just temporarily undefine the macros these libraries use to detect
|
||||||
|
// it's running under a WIN32 environment. If anyone knows a better way to do
|
||||||
|
// this, please let me know!
|
||||||
|
|
||||||
|
#pragma push_macro("WIN32")
|
||||||
|
#pragma push_macro("_WIN32")
|
||||||
|
#pragma push_macro("__WIN32__")
|
||||||
|
#pragma push_macro("_WIN64")
|
||||||
|
|
||||||
|
#undef WIN32
|
||||||
|
#undef _WIN32
|
||||||
|
#undef __WIN32__
|
||||||
|
#undef _WIN64
|
||||||
|
|
||||||
|
// This would be the minimal include needed to get Asio to work. The commented
|
||||||
|
// out includes are the actual header that would cause compile errors if not
|
||||||
|
// included here, but including headers from the detail directory directly
|
||||||
|
// didn't sound like a great idea.
|
||||||
|
|
||||||
|
// FIXME: Remove Boost stuff
|
||||||
|
#include <boost/predef.h>
|
||||||
|
#include <asio/basic_socket_streambuf.hpp>
|
||||||
|
#include <boost/asio/basic_socket_streambuf.hpp>
|
||||||
|
#include <boost/interprocess/mapped_region.hpp>
|
||||||
|
// #include <asio/asio/detail/timer_queue_ptime.hpp>
|
||||||
|
// #include <boost/interprocess/detail/workaround.hpp>
|
||||||
|
|
||||||
|
#pragma pop_macro("WIN32")
|
||||||
|
#pragma pop_macro("_WIN32")
|
||||||
|
#pragma pop_macro("__WIN32__")
|
||||||
|
#pragma pop_macro("_WIN64")
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../boost-fix.h"
|
#include "../asio-fix.h"
|
||||||
|
|
||||||
#include <ghc/filesystem.hpp>
|
#include <ghc/filesystem.hpp>
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#include "group.h"
|
#include "group.h"
|
||||||
|
|
||||||
#include "../boost-fix.h"
|
#include "../asio-fix.h"
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
@@ -49,23 +49,23 @@ using namespace std::literals::chrono_literals;
|
|||||||
* @throw std::runtime_error If another process is already listening on the
|
* @throw std::runtime_error If another process is already listening on the
|
||||||
* endpoint.
|
* endpoint.
|
||||||
*/
|
*/
|
||||||
boost::asio::local::stream_protocol::acceptor create_acceptor_if_inactive(
|
asio::local::stream_protocol::acceptor create_acceptor_if_inactive(
|
||||||
boost::asio::io_context& io_context,
|
asio::io_context& io_context,
|
||||||
boost::asio::local::stream_protocol::endpoint& endpoint);
|
asio::local::stream_protocol::endpoint& endpoint);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a logger prefix containing the group name based on the socket path.
|
* Create a logger prefix containing the group name based on the socket path.
|
||||||
*/
|
*/
|
||||||
std::string create_logger_prefix(const fs::path& socket_path);
|
std::string create_logger_prefix(const fs::path& socket_path);
|
||||||
|
|
||||||
StdIoCapture::StdIoCapture(boost::asio::io_context& io_context,
|
StdIoCapture::StdIoCapture(asio::io_context& io_context, int file_descriptor)
|
||||||
int file_descriptor)
|
|
||||||
: pipe_(io_context),
|
: pipe_(io_context),
|
||||||
target_fd_(file_descriptor),
|
target_fd_(file_descriptor),
|
||||||
original_fd_copy_(dup(file_descriptor)) {
|
original_fd_copy_(dup(file_descriptor)) {
|
||||||
// We'll use the second element of these two file descriptors to reopen
|
// We'll use the second element of these two file descriptors to reopen
|
||||||
// `file_descriptor`, and the first one to read the captured contents from
|
// `file_descriptor`, and the first one to read the captured contents from
|
||||||
if (::pipe(pipe_fd_) != 0) {
|
if (::pipe(pipe_fd_) != 0) {
|
||||||
|
std::cerr << "Could not create pipe" << std::endl;
|
||||||
throw std::system_error(errno, std::system_category());
|
throw std::system_error(errno, std::system_category());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,12 +171,12 @@ void GroupBridge::handle_incoming_connections() {
|
|||||||
|
|
||||||
void GroupBridge::accept_requests() {
|
void GroupBridge::accept_requests() {
|
||||||
group_socket_acceptor_.async_accept(
|
group_socket_acceptor_.async_accept(
|
||||||
[&](const boost::system::error_code& error,
|
[&](const std::error_code& error,
|
||||||
boost::asio::local::stream_protocol::socket socket) {
|
asio::local::stream_protocol::socket socket) {
|
||||||
std::lock_guard lock(active_plugins_mutex_);
|
std::lock_guard lock(active_plugins_mutex_);
|
||||||
|
|
||||||
// Stop the whole process when the socket gets closed unexpectedly
|
// Stop the whole process when the socket gets closed unexpectedly
|
||||||
if (error.failed()) {
|
if (error) {
|
||||||
logger_.log("Error while listening for incoming connections:");
|
logger_.log("Error while listening for incoming connections:");
|
||||||
logger_.log(error.message());
|
logger_.log(error.message());
|
||||||
|
|
||||||
@@ -284,14 +284,13 @@ void GroupBridge::async_handle_events() {
|
|||||||
[&]() { return !is_event_loop_inhibited(); });
|
[&]() { return !is_event_loop_inhibited(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::asio::local::stream_protocol::acceptor create_acceptor_if_inactive(
|
asio::local::stream_protocol::acceptor create_acceptor_if_inactive(
|
||||||
boost::asio::io_context& io_context,
|
asio::io_context& io_context,
|
||||||
boost::asio::local::stream_protocol::endpoint& endpoint) {
|
asio::local::stream_protocol::endpoint& endpoint) {
|
||||||
// First try to listen on the endpoint normally
|
// First try to listen on the endpoint normally
|
||||||
try {
|
try {
|
||||||
return boost::asio::local::stream_protocol::acceptor(io_context,
|
return asio::local::stream_protocol::acceptor(io_context, endpoint);
|
||||||
endpoint);
|
} catch (const std::system_error&) {
|
||||||
} catch (const boost::system::system_error&) {
|
|
||||||
// If this failed, then either there is a stale socket file or another
|
// If this failed, then either there is a stale socket file or another
|
||||||
// process is already is already listening. In the last case we will
|
// process is already is already listening. In the last case we will
|
||||||
// simply throw so the other process can handle the request.
|
// simply throw so the other process can handle the request.
|
||||||
@@ -312,8 +311,7 @@ boost::asio::local::stream_protocol::acceptor create_acceptor_if_inactive(
|
|||||||
|
|
||||||
// At this point we can remove the stale socket and start listening
|
// At this point we can remove the stale socket and start listening
|
||||||
fs::remove(endpoint_path);
|
fs::remove(endpoint_path);
|
||||||
return boost::asio::local::stream_protocol::acceptor(io_context,
|
return asio::local::stream_protocol::acceptor(io_context, endpoint);
|
||||||
endpoint);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,10 +320,10 @@ void GroupBridge::maybe_schedule_shutdown(
|
|||||||
std::lock_guard lock(shutdown_timer_mutex_);
|
std::lock_guard lock(shutdown_timer_mutex_);
|
||||||
|
|
||||||
shutdown_timer_.expires_after(delay);
|
shutdown_timer_.expires_after(delay);
|
||||||
shutdown_timer_.async_wait([this](const boost::system::error_code& error) {
|
shutdown_timer_.async_wait([this](const std::error_code& error) {
|
||||||
// A previous timer gets canceled automatically when another plugin
|
// A previous timer gets canceled automatically when another plugin
|
||||||
// exits
|
// exits
|
||||||
if (error.failed()) {
|
if (error) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,9 +19,9 @@
|
|||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "../boost-fix.h"
|
#include "../asio-fix.h"
|
||||||
|
|
||||||
#include <boost/asio/local/stream_protocol.hpp>
|
#include <asio/local/stream_protocol.hpp>
|
||||||
|
|
||||||
#include "../common/logging/common.h"
|
#include "../common/logging/common.h"
|
||||||
#include "../utils.h"
|
#include "../utils.h"
|
||||||
@@ -49,7 +49,7 @@ class StdIoCapture {
|
|||||||
*
|
*
|
||||||
* @throw std::system_error If the pipe could not be created.
|
* @throw std::system_error If the pipe could not be created.
|
||||||
*/
|
*/
|
||||||
StdIoCapture(boost::asio::io_context& io_context, int file_descriptor);
|
StdIoCapture(asio::io_context& io_context, int file_descriptor);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On cleanup, close the outgoing file descriptor from the pipe and restore
|
* On cleanup, close the outgoing file descriptor from the pipe and restore
|
||||||
@@ -65,9 +65,9 @@ class StdIoCapture {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The pipe endpoint where all output from the original file descriptor gets
|
* The pipe endpoint where all output from the original file descriptor gets
|
||||||
* redirected to. This can be read from like any other `Boost.Asio` stream.
|
* redirected to. This can be read from like any other Asio stream.
|
||||||
*/
|
*/
|
||||||
boost::asio::posix::stream_descriptor pipe_;
|
asio::posix::stream_descriptor pipe_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
@@ -116,7 +116,7 @@ class GroupBridge {
|
|||||||
* where `<wine_prefix_id>` is a numerical hash as explained in the
|
* where `<wine_prefix_id>` is a numerical hash as explained in the
|
||||||
* `create_logger_prefix()` function in `./group.cpp`.
|
* `create_logger_prefix()` function in `./group.cpp`.
|
||||||
*
|
*
|
||||||
* @throw boost::system::system_error If we can't listen on the socket.
|
* @throw std::system_error If we can't listen on the socket.
|
||||||
* @throw std::system_error If the pipe could not be created.
|
* @throw std::system_error If the pipe could not be created.
|
||||||
*
|
*
|
||||||
* @note Creating an `GroupBridge` instance has the side effect that the
|
* @note Creating an `GroupBridge` instance has the side effect that the
|
||||||
@@ -220,10 +220,10 @@ class GroupBridge {
|
|||||||
* related operation should be run from the same thread, we can't just add
|
* related operation should be run from the same thread, we can't just add
|
||||||
* another thread to the main IO context.
|
* another thread to the main IO context.
|
||||||
*/
|
*/
|
||||||
boost::asio::io_context stdio_context_;
|
asio::io_context stdio_context_;
|
||||||
|
|
||||||
boost::asio::streambuf stdout_buffer_;
|
asio::streambuf stdout_buffer_;
|
||||||
boost::asio::streambuf stderr_buffer_;
|
asio::streambuf stderr_buffer_;
|
||||||
/**
|
/**
|
||||||
* Contains a pipe used for capturing this process's STDOUT stream. Needed
|
* Contains a pipe used for capturing this process's STDOUT stream. Needed
|
||||||
* to be able to process the output generated by Wine and plugins and to be
|
* to be able to process the output generated by Wine and plugins and to be
|
||||||
@@ -241,12 +241,12 @@ class GroupBridge {
|
|||||||
*/
|
*/
|
||||||
Win32Thread stdio_handler_;
|
Win32Thread stdio_handler_;
|
||||||
|
|
||||||
boost::asio::local::stream_protocol::endpoint group_socket_endpoint_;
|
asio::local::stream_protocol::endpoint group_socket_endpoint_;
|
||||||
/**
|
/**
|
||||||
* The UNIX domain socket acceptor that will be used to listen for incoming
|
* The UNIX domain socket acceptor that will be used to listen for incoming
|
||||||
* connections to spawn new plugins within this process.
|
* connections to spawn new plugins within this process.
|
||||||
*/
|
*/
|
||||||
boost::asio::local::stream_protocol::acceptor group_socket_acceptor_;
|
asio::local::stream_protocol::acceptor group_socket_acceptor_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A map of threads that are currently hosting a plugin within this process
|
* A map of threads that are currently hosting a plugin within this process
|
||||||
@@ -281,7 +281,7 @@ class GroupBridge {
|
|||||||
*
|
*
|
||||||
* @see handle_plugin_run
|
* @see handle_plugin_run
|
||||||
*/
|
*/
|
||||||
boost::asio::steady_timer shutdown_timer_;
|
asio::steady_timer shutdown_timer_;
|
||||||
/**
|
/**
|
||||||
* A mutex to prevent two threads from simultaneously modifying the shutdown
|
* A mutex to prevent two threads from simultaneously modifying the shutdown
|
||||||
* timer when multiple plugins exit at the same time.
|
* timer when multiple plugins exit at the same time.
|
||||||
|
|||||||
@@ -623,7 +623,7 @@ class HostCallbackDataConverter : public DefaultDataConverter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Vst2EventResult send_event(
|
Vst2EventResult send_event(
|
||||||
boost::asio::local::stream_protocol::socket& socket,
|
asio::local::stream_protocol::socket& socket,
|
||||||
const Vst2Event& event,
|
const Vst2Event& event,
|
||||||
SerializationBufferBase& buffer) const override {
|
SerializationBufferBase& buffer) const override {
|
||||||
if (mutually_recursive_callbacks.contains(event.opcode)) {
|
if (mutually_recursive_callbacks.contains(event.opcode)) {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../boost-fix.h"
|
#include "../asio-fix.h"
|
||||||
|
|
||||||
#include <vestige/aeffectx.h>
|
#include <vestige/aeffectx.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|||||||
@@ -228,17 +228,17 @@ DeferredWin32Window::~DeferredWin32Window() noexcept {
|
|||||||
// `IPlugView::~IPlugView`. Delaying this seems to be a best of both
|
// `IPlugView::~IPlugView`. Delaying this seems to be a best of both
|
||||||
// worlds solution that works as expected in every host I've tested.
|
// worlds solution that works as expected in every host I've tested.
|
||||||
try {
|
try {
|
||||||
std::shared_ptr<boost::asio::steady_timer> destroy_timer =
|
std::shared_ptr<asio::steady_timer> destroy_timer =
|
||||||
std::make_shared<boost::asio::steady_timer>(main_context_.context_);
|
std::make_shared<asio::steady_timer>(main_context_.context_);
|
||||||
destroy_timer->expires_after(1s);
|
destroy_timer->expires_after(1s);
|
||||||
|
|
||||||
// Note that we capture a copy of `destroy_timer` here. This way we
|
// Note that we capture a copy of `destroy_timer` here. This way we
|
||||||
// don't have to manage the timer instance ourselves as it will just
|
// don't have to manage the timer instance ourselves as it will just
|
||||||
// clean itself up after this lambda gets called.
|
// clean itself up after this lambda gets called.
|
||||||
destroy_timer->async_wait(
|
destroy_timer->async_wait(
|
||||||
[destroy_timer, handle = handle_, x11_connection = x11_connection_](
|
[destroy_timer, handle = handle_,
|
||||||
const boost::system::error_code& error) {
|
x11_connection = x11_connection_](const std::error_code& error) {
|
||||||
if (error.failed()) {
|
if (error) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,21 +76,19 @@ __cdecl
|
|||||||
|
|
||||||
// Blocks the main thread until all plugins have exited
|
// Blocks the main thread until all plugins have exited
|
||||||
bridge.handle_incoming_connections();
|
bridge.handle_incoming_connections();
|
||||||
} catch (const boost::system::system_error& error) {
|
} catch (const std::system_error& error) {
|
||||||
// If another process is already listening on the socket, we'll just
|
// If another process is already listening on the socket, we'll just
|
||||||
// print a message and exit quietly. This could happen if the host
|
// print a message and exit quietly. This could happen if the host
|
||||||
// starts multiple yabridge instances that all use the same plugin group
|
// starts multiple yabridge instances that all use the same plugin group
|
||||||
// at the same time.
|
// at the same time.
|
||||||
|
// The same error is also used if we could not create a pipe. Since that
|
||||||
|
// error is so rare, we'll just print to STDERR before that happens to
|
||||||
|
// differentiate the two cases.
|
||||||
std::cerr << "Another process is already listening on this group's "
|
std::cerr << "Another process is already listening on this group's "
|
||||||
"socket, connecting to the existing process:"
|
"socket, connecting to the existing process:"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
std::cerr << error.what() << std::endl;
|
std::cerr << error.what() << std::endl;
|
||||||
|
|
||||||
return 0;
|
|
||||||
} catch (const std::system_error& error) {
|
|
||||||
std::cerr << "Could not create pipe:" << std::endl;
|
|
||||||
std::cerr << error.what() << std::endl;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ if is_64bit_system
|
|||||||
host_64bit_deps = [
|
host_64bit_deps = [
|
||||||
configuration_dep,
|
configuration_dep,
|
||||||
|
|
||||||
|
asio_dep,
|
||||||
boost_dep,
|
boost_dep,
|
||||||
bitsery_dep,
|
bitsery_dep,
|
||||||
function2_dep,
|
function2_dep,
|
||||||
@@ -35,6 +36,7 @@ if with_bitbridge
|
|||||||
host_32bit_deps = [
|
host_32bit_deps = [
|
||||||
configuration_dep,
|
configuration_dep,
|
||||||
|
|
||||||
|
asio_dep,
|
||||||
boost_dep,
|
boost_dep,
|
||||||
ghc_filesystem_dep,
|
ghc_filesystem_dep,
|
||||||
bitsery_dep,
|
bitsery_dep,
|
||||||
|
|||||||
@@ -175,8 +175,8 @@ void MainContext::async_handle_watchdog_timer(
|
|||||||
// Try to keep a steady framerate, but add in delays to let other events
|
// Try to keep a steady framerate, but add in delays to let other events
|
||||||
// get handled if the GUI message handling somehow takes very long.
|
// get handled if the GUI message handling somehow takes very long.
|
||||||
watchdog_timer_.expires_at(std::chrono::steady_clock::now() + interval);
|
watchdog_timer_.expires_at(std::chrono::steady_clock::now() + interval);
|
||||||
watchdog_timer_.async_wait([&](const boost::system::error_code& error) {
|
watchdog_timer_.async_wait([&](const std::error_code& error) {
|
||||||
if (error.failed()) {
|
if (error) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-12
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "boost-fix.h"
|
#include "asio-fix.h"
|
||||||
|
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -24,8 +24,8 @@
|
|||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <boost/asio/dispatch.hpp>
|
#include <asio/dispatch.hpp>
|
||||||
#include <boost/asio/io_context.hpp>
|
#include <asio/io_context.hpp>
|
||||||
#include <function2/function2.hpp>
|
#include <function2/function2.hpp>
|
||||||
|
|
||||||
#include "../common/utils.h"
|
#include "../common/utils.h"
|
||||||
@@ -152,7 +152,7 @@ class Win32Timer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A wrapper around `boost::asio::io_context()` to serve as the application's
|
* A wrapper around `asio::io_context()` to serve as the application's
|
||||||
* main IO context, run from the GUI thread. A single instance is shared for all
|
* main IO context, run from the GUI thread. A single instance is shared for all
|
||||||
* plugins in a plugin group so that several important events can be handled on
|
* plugins in a plugin group so that several important events can be handled on
|
||||||
* the main thread, which can be required because in the Win32 model all GUI
|
* the main thread, which can be required because in the Win32 model all GUI
|
||||||
@@ -254,7 +254,7 @@ class MainContext {
|
|||||||
|
|
||||||
std::packaged_task<Result()> call_fn(std::forward<F>(fn));
|
std::packaged_task<Result()> call_fn(std::forward<F>(fn));
|
||||||
std::future<Result> result = call_fn.get_future();
|
std::future<Result> result = call_fn.get_future();
|
||||||
boost::asio::dispatch(context_, std::move(call_fn));
|
asio::dispatch(context_, std::move(call_fn));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -266,7 +266,7 @@ class MainContext {
|
|||||||
*/
|
*/
|
||||||
template <std::invocable F>
|
template <std::invocable F>
|
||||||
void schedule_task(F&& fn) {
|
void schedule_task(F&& fn) {
|
||||||
boost::asio::post(context_, std::forward<F>(fn));
|
asio::post(context_, std::forward<F>(fn));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -294,8 +294,8 @@ class MainContext {
|
|||||||
std::max(events_timer_.expiry() + timer_interval_,
|
std::max(events_timer_.expiry() + timer_interval_,
|
||||||
std::chrono::steady_clock::now() + timer_interval_ / 4));
|
std::chrono::steady_clock::now() + timer_interval_ / 4));
|
||||||
events_timer_.async_wait(
|
events_timer_.async_wait(
|
||||||
[&, handler, predicate](const boost::system::error_code& error) {
|
[&, handler, predicate](const std::error_code& error) {
|
||||||
if (error.failed()) {
|
if (error) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,7 +311,7 @@ class MainContext {
|
|||||||
* The raw IO context. Used to bind our sockets onto. Running things within
|
* The raw IO context. Used to bind our sockets onto. Running things within
|
||||||
* this IO context should be done with the functions above.
|
* this IO context should be done with the functions above.
|
||||||
*/
|
*/
|
||||||
boost::asio::io_context context_;
|
asio::io_context context_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
@@ -334,7 +334,7 @@ class MainContext {
|
|||||||
/**
|
/**
|
||||||
* The timer used to periodically handle X11 events and Win32 messages.
|
* The timer used to periodically handle X11 events and Win32 messages.
|
||||||
*/
|
*/
|
||||||
boost::asio::steady_timer events_timer_;
|
asio::steady_timer events_timer_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The time between timer ticks in `async_handle_events`. This gets
|
* The time between timer ticks in `async_handle_events`. This gets
|
||||||
@@ -349,7 +349,7 @@ class MainContext {
|
|||||||
/**
|
/**
|
||||||
* The IO context used for the watchdog described below.
|
* The IO context used for the watchdog described below.
|
||||||
*/
|
*/
|
||||||
boost::asio::io_context watchdog_context_;
|
asio::io_context watchdog_context_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The timer used to periodically check if the host processes are still
|
* The timer used to periodically check if the host processes are still
|
||||||
@@ -357,7 +357,7 @@ class MainContext {
|
|||||||
* itself) when the host has exited and the sockets are somehow not closed
|
* itself) when the host has exited and the sockets are somehow not closed
|
||||||
* yet..
|
* yet..
|
||||||
*/
|
*/
|
||||||
boost::asio::steady_timer watchdog_timer_;
|
asio::steady_timer watchdog_timer_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All of the bridges we're watching as part of our watchdog. We're storing
|
* All of the bridges we're watching as part of our watchdog. We're storing
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "boost-fix.h"
|
#include "asio-fix.h"
|
||||||
|
|
||||||
// Use the native version of xcb
|
// Use the native version of xcb
|
||||||
#pragma push_macro("_WIN32")
|
#pragma push_macro("_WIN32")
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/*/*
|
/*/*
|
||||||
|
|
||||||
# The above pattern doesn't match submodules
|
# The above pattern doesn't match submodules
|
||||||
|
/asio
|
||||||
/bitsery
|
/bitsery
|
||||||
/function2
|
/function2
|
||||||
/ghc_filesystem
|
/ghc_filesystem
|
||||||
@@ -8,6 +9,7 @@
|
|||||||
/vst3
|
/vst3
|
||||||
|
|
||||||
# And we obviously don't want to ignore our overlays
|
# And we obviously don't want to ignore our overlays
|
||||||
|
!/packagefiles/asio
|
||||||
!/packagefiles/bitsery
|
!/packagefiles/bitsery
|
||||||
!/packagefiles/function2
|
!/packagefiles/function2
|
||||||
!/packagefiles/ghc_filesystem
|
!/packagefiles/ghc_filesystem
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[wrap-git]
|
||||||
|
url = https://github.com/chriskohlhoff/asio.git
|
||||||
|
# This is tag asio-1-22-1
|
||||||
|
revision = bba12d10501418fd3789ce01c9f86a77d37df7ed
|
||||||
|
depth = 1
|
||||||
|
patch_directory = asio
|
||||||
|
|
||||||
|
[provide]
|
||||||
|
asio = asio_dep
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
project('asio', 'cpp', version : '1.22.1')
|
||||||
|
|
||||||
|
asio_dep = declare_dependency(include_directories : include_directories('asio/include'))
|
||||||
Reference in New Issue
Block a user