mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-10 04:30:12 +02:00
Move the host guard handler to PluginBridge
This commit is contained in:
@@ -37,8 +37,8 @@ class PluginBridge {
|
|||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Sets up everything needed to start the host process. Classes deriving
|
* Sets up everything needed to start the host process. Classes deriving
|
||||||
* from this should call `log_init_message()` themselves after their
|
* from this should call `log_init_message()` and
|
||||||
* initialization list.
|
* `connect_sockets_guarded()` themselves after their initialization list.
|
||||||
*
|
*
|
||||||
* @param plugin_type The type of the plugin we're handling.
|
* @param plugin_type The type of the plugin we're handling.
|
||||||
* @param plugin_path The path to the plugin. For VST2 plugins this is the
|
* @param plugin_path The path to the plugin. For VST2 plugins this is the
|
||||||
@@ -197,6 +197,47 @@ class PluginBridge {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect the sockets, while starting another thread that will terminate
|
||||||
|
* the plugin (through `std::terminate`/SIGABRT) when the host process fails
|
||||||
|
* to start. This is the only way to stop listening on our sockets without
|
||||||
|
* moving everything over to asynchronous listeners (which may actually be a
|
||||||
|
* good idea just for this use case). Otherwise the plugin would be stuck
|
||||||
|
* loading indefinitely when Wine is not configured correctly.
|
||||||
|
*
|
||||||
|
* TODO: Asynchronously connect our sockets so we can interrupt it, maybe
|
||||||
|
*/
|
||||||
|
void connect_sockets_guarded() {
|
||||||
|
#ifndef WITH_WINEDBG
|
||||||
|
// If the Wine process fails to start, then nothing will connect to the
|
||||||
|
// sockets and we'll be hanging here indefinitely. To prevent this,
|
||||||
|
// 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
|
||||||
|
// using `async_accept`, Boost.Asio timers, and another IO context, but
|
||||||
|
// I feel like this a much simpler solution.
|
||||||
|
host_guard_handler = std::jthread([&](std::stop_token st) {
|
||||||
|
using namespace std::literals::chrono_literals;
|
||||||
|
|
||||||
|
while (!st.stop_requested()) {
|
||||||
|
if (!plugin_host->running()) {
|
||||||
|
generic_logger.log(
|
||||||
|
"The Wine host process has exited unexpectedly. Check "
|
||||||
|
"the "
|
||||||
|
"output above for more information.");
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(20ms);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
|
||||||
|
sockets.connect();
|
||||||
|
#ifndef WITH_WINEDBG
|
||||||
|
host_guard_handler.request_stop();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the plugin we're dealing with. Passed to the host process and
|
* The type of the plugin we're dealing with. Passed to the host process and
|
||||||
* printed in the initialisation message.
|
* printed in the initialisation message.
|
||||||
@@ -224,7 +265,10 @@ class PluginBridge {
|
|||||||
/**
|
/**
|
||||||
* The sockets used for communication with the Wine process.
|
* The sockets used for communication with the Wine process.
|
||||||
*
|
*
|
||||||
* @see PluginBridge::log_init_message
|
* @remark `sockets.connect()` should not be called directly.
|
||||||
|
* `connect_sockets_guarded()` should be used instead.
|
||||||
|
*
|
||||||
|
* @see PluginBridge::connect_sockets_guarded
|
||||||
*/
|
*/
|
||||||
TSockets sockets;
|
TSockets sockets;
|
||||||
|
|
||||||
@@ -263,4 +307,14 @@ class PluginBridge {
|
|||||||
* STDOUT and STDERR messages.
|
* STDOUT and STDERR messages.
|
||||||
*/
|
*/
|
||||||
std::jthread wine_io_handler;
|
std::jthread wine_io_handler;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* A thread used during the initialisation process to terminate listening on
|
||||||
|
* the sockets if the Wine process cannot start for whatever reason. This
|
||||||
|
* has to be defined here instead of in the constructor we can't simply
|
||||||
|
* detach the thread as it has to check whether the VST host is still
|
||||||
|
* running.
|
||||||
|
*/
|
||||||
|
std::jthread host_guard_handler;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -61,36 +61,9 @@ Vst2PluginBridge::Vst2PluginBridge(audioMasterCallback host_callback)
|
|||||||
create_logger_prefix(sockets.base_dir)))) {
|
create_logger_prefix(sockets.base_dir)))) {
|
||||||
log_init_message();
|
log_init_message();
|
||||||
|
|
||||||
// TODO: Also move his to `PluginHost`
|
|
||||||
#ifndef WITH_WINEDBG
|
|
||||||
// If the Wine process fails to start, then nothing will connect to the
|
|
||||||
// sockets and we'll be hanging here indefinitely. To prevent this, 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 using
|
|
||||||
// `async_accept`, Boost.Asio timers, and another IO context, but I feel
|
|
||||||
// like this a much simpler solution.
|
|
||||||
host_guard_handler = std::jthread([&](std::stop_token st) {
|
|
||||||
using namespace std::literals::chrono_literals;
|
|
||||||
|
|
||||||
while (!st.stop_requested()) {
|
|
||||||
if (!plugin_host->running()) {
|
|
||||||
logger.log(
|
|
||||||
"The Wine host process has exited unexpectedly. Check the "
|
|
||||||
"output above for more information.");
|
|
||||||
std::terminate();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::this_thread::sleep_for(20ms);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// This will block until all sockets have been connected to by the Wine VST
|
// This will block until all sockets have been connected to by the Wine VST
|
||||||
// host
|
// host
|
||||||
sockets.connect();
|
connect_sockets_guarded();
|
||||||
#ifndef WITH_WINEDBG
|
|
||||||
host_guard_handler.request_stop();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Set up all pointers for our `AEffect` struct. We will fill this with data
|
// Set up all pointers for our `AEffect` struct. We will fill this with data
|
||||||
// from the VST plugin loaded in Wine at the end of this constructor.
|
// from the VST plugin loaded in Wine at the end of this constructor.
|
||||||
|
|||||||
@@ -148,15 +148,6 @@ class Vst2PluginBridge : PluginBridge<Vst2Sockets<std::jthread>> {
|
|||||||
*/
|
*/
|
||||||
Vst2Logger logger;
|
Vst2Logger logger;
|
||||||
|
|
||||||
/**
|
|
||||||
* A thread used during the initialisation process to terminate listening on
|
|
||||||
* the sockets if the Wine process cannot start for whatever reason. This
|
|
||||||
* has to be defined here instead of in the constructor we can't simply
|
|
||||||
* detach the thread as it has to check whether the VST host is still
|
|
||||||
* running.
|
|
||||||
*/
|
|
||||||
std::jthread host_guard_handler;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A scratch buffer for sending and receiving data during `process`,
|
* A scratch buffer for sending and receiving data during `process`,
|
||||||
* `processReplacing` and `processDoubleReplacing` calls.
|
* `processReplacing` and `processDoubleReplacing` calls.
|
||||||
|
|||||||
@@ -34,5 +34,7 @@ Vst3PluginBridge::Vst3PluginBridge()
|
|||||||
create_logger_prefix(sockets.base_dir)))) {
|
create_logger_prefix(sockets.base_dir)))) {
|
||||||
log_init_message();
|
log_init_message();
|
||||||
|
|
||||||
// TODO: Call the host guard handler
|
// This will block until all sockets have been connected to by the Wine VST
|
||||||
|
// host
|
||||||
|
connect_sockets_guarded();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user