Move the host guard handler to PluginBridge

This commit is contained in:
Robbert van der Helm
2020-12-04 00:31:22 +01:00
parent c2d2ac8fbf
commit b9e63ea335
4 changed files with 61 additions and 41 deletions
+57 -3
View File
@@ -37,8 +37,8 @@ class PluginBridge {
public:
/**
* Sets up everything needed to start the host process. Classes deriving
* from this should call `log_init_message()` themselves after their
* initialization list.
* from this should call `log_init_message()` and
* `connect_sockets_guarded()` themselves after their initialization list.
*
* @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
@@ -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
* printed in the initialisation message.
@@ -224,7 +265,10 @@ class PluginBridge {
/**
* 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;
@@ -263,4 +307,14 @@ class PluginBridge {
* STDOUT and STDERR messages.
*/
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;
};
+1 -28
View File
@@ -61,36 +61,9 @@ Vst2PluginBridge::Vst2PluginBridge(audioMasterCallback host_callback)
create_logger_prefix(sockets.base_dir)))) {
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
// host
sockets.connect();
#ifndef WITH_WINEDBG
host_guard_handler.request_stop();
#endif
connect_sockets_guarded();
// 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.
-9
View File
@@ -148,15 +148,6 @@ class Vst2PluginBridge : PluginBridge<Vst2Sockets<std::jthread>> {
*/
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`,
* `processReplacing` and `processDoubleReplacing` calls.
+3 -1
View File
@@ -34,5 +34,7 @@ Vst3PluginBridge::Vst3PluginBridge()
create_logger_prefix(sockets.base_dir)))) {
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();
}