From 484032202a5cdf8c547bac594790654cb0520397 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Sat, 9 May 2020 16:31:11 +0200 Subject: [PATCH] Stop accepting sockets if Wine crashes on startup --- CHANGELOG.md | 5 +++++ src/plugin/plugin-bridge.cpp | 24 ++++++++++++++++++++++++ src/plugin/plugin-bridge.h | 9 +++++++++ 3 files changed, 38 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8720a2cc..4f20260b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,11 @@ Versioning](https://semver.org/spec/v2.0.0.html). that support individually sandboxed plugins. - Respect `YABRIDGE_DEBUG_FILE` when printing initialization errors. +### Fixed + +- Stop waiting for the Wine VST host process on startup if the process has + crashed or if Wine was not able to start. + ## [1.1.0] - 2020-05-07 ### Added diff --git a/src/plugin/plugin-bridge.cpp b/src/plugin/plugin-bridge.cpp index a4583066..ee0bc134 100644 --- a/src/plugin/plugin-bridge.cpp +++ b/src/plugin/plugin-bridge.cpp @@ -134,6 +134,29 @@ PluginBridge::PluginBridge(audioMasterCallback host_callback) async_log_pipe_lines(wine_stderr, wine_stderr_buffer, "[Wine STDERR] "); wine_io_handler = std::thread([&]() { io_context.run(); }); + // 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. + std::thread([&]() { + using namespace std::literals::chrono_literals; + + while (true) { + if (finished_accepting_sockets) { + return; + } + if (!vst_host.running()) { + throw std::runtime_error( + "The Wine process failed to start. Check the output above " + "for more information."); + } + + std::this_thread::sleep_for(1s); + } + }).detach(); + // It's very important that these sockets are connected to in the same // order in the Wine VST host socket_acceptor.accept(host_vst_dispatch); @@ -142,6 +165,7 @@ PluginBridge::PluginBridge(audioMasterCallback host_callback) socket_acceptor.accept(host_vst_parameters); socket_acceptor.accept(host_vst_process_replacing); socket_acceptor.accept(vst_host_aeffect); + finished_accepting_sockets = true; // There's no need to keep the socket endpoint file around after accepting // all the sockets, and RAII won't clean these files up for us diff --git a/src/plugin/plugin-bridge.h b/src/plugin/plugin-bridge.h index 24e24c05..9cfa7ec9 100644 --- a/src/plugin/plugin-bridge.h +++ b/src/plugin/plugin-bridge.h @@ -152,6 +152,15 @@ class PluginBridge { */ boost::asio::local::stream_protocol::socket vst_host_aeffect; + /** + * Whether we're done accepting sockets. The plugin may hang indefinitely if + * the Wine process fails to start, since then nothing will connect to our + * sockets. While we're waiting for our sockets we'll periodically poll the + * Wine process to see if it's still running, and terminate the socket + * accepting if it is not. + */ + std::atomic_bool finished_accepting_sockets; + /** * The thread that handles host callbacks. */