diff --git a/src/wine-host/bridges/common.cpp b/src/wine-host/bridges/common.cpp index 829be6d4..a7d52aa2 100644 --- a/src/wine-host/bridges/common.cpp +++ b/src/wine-host/bridges/common.cpp @@ -16,13 +16,17 @@ #include "common.h" +#include + #include "../editor.h" HostBridge::HostBridge(MainContext& main_context, - boost::filesystem::path plugin_path) + boost::filesystem::path plugin_path, + pid_t parent_pid) : plugin_path(plugin_path), main_context(main_context), generic_logger(Logger::create_wine_stderr()), + parent_pid(parent_pid), watchdog_guard(main_context.register_watchdog(*this)) {} void HostBridge::handle_win32_events() { @@ -37,5 +41,17 @@ void HostBridge::handle_win32_events() { } void HostBridge::shutdown_if_dangling() { - // TODO: Implement + // If the parent process has exited and this plugin bridge instance is + // outliving the process it's supposed to be connected to (because in some + // situations sockets won't get closed when this happens so we'd hang on + // `recv()`), then we'll close the sockets here so that the plugin bridge + // exits gracefully. This will be periodically called from `MainContext`'s + // watchdog thread. + if (!pid_running(parent_pid)) { + std::cerr << "WARNING: The native plugin host seems to have died." + << std::endl; + std::cerr << " This bridge will shut down now." << std::endl; + + close_sockets(); + } } diff --git a/src/wine-host/bridges/common.h b/src/wine-host/bridges/common.h index c0baec3b..14f08a77 100644 --- a/src/wine-host/bridges/common.h +++ b/src/wine-host/bridges/common.h @@ -32,7 +32,9 @@ */ class HostBridge { protected: - HostBridge(MainContext& main_context, boost::filesystem::path plugin_path); + HostBridge(MainContext& main_context, + boost::filesystem::path plugin_path, + pid_t parent_pid); public: virtual ~HostBridge(){}; @@ -127,6 +129,15 @@ class HostBridge { Logger generic_logger; private: + /** + * The process ID of the native plugin host we are bridging for. This should + * be the parent, but it might not be because of Wine's startup script, + * `WINELOADER`s and Wine's `start.exe` behaviour. We'll periodically check + * if this process is still alive, and close the sockets if it is not to + * prevent dangling processes. + */ + const pid_t parent_pid; + /** * A guard that, while in scope, will cause `shutdown_if_dangling()` to * periodically be called. diff --git a/src/wine-host/bridges/group.cpp b/src/wine-host/bridges/group.cpp index 07dc389d..e0017403 100644 --- a/src/wine-host/bridges/group.cpp +++ b/src/wine-host/bridges/group.cpp @@ -217,13 +217,13 @@ void GroupBridge::accept_requests() { case PluginType::vst2: bridge = std::make_unique( main_context, request.plugin_path, - request.endpoint_base_dir); + request.endpoint_base_dir, request.parent_pid); break; case PluginType::vst3: #ifdef WITH_VST3 bridge = std::make_unique( main_context, request.plugin_path, - request.endpoint_base_dir); + request.endpoint_base_dir, request.parent_pid); #else throw std::runtime_error( "This version of yabridge has not been compiled " diff --git a/src/wine-host/bridges/vst2.cpp b/src/wine-host/bridges/vst2.cpp index 06c78b0c..2273be39 100644 --- a/src/wine-host/bridges/vst2.cpp +++ b/src/wine-host/bridges/vst2.cpp @@ -68,8 +68,9 @@ Vst2Bridge& get_bridge_instance(const AEffect* plugin) { Vst2Bridge::Vst2Bridge(MainContext& main_context, std::string plugin_dll_path, - std::string endpoint_base_dir) - : HostBridge(main_context, plugin_dll_path), + std::string endpoint_base_dir, + pid_t parent_pid) + : HostBridge(main_context, plugin_dll_path, parent_pid), logger(generic_logger), plugin_handle(LoadLibrary(plugin_dll_path.c_str()), FreeLibrary), sockets(main_context.context, endpoint_base_dir, false) { diff --git a/src/wine-host/bridges/vst2.h b/src/wine-host/bridges/vst2.h index 426e4262..4326a436 100644 --- a/src/wine-host/bridges/vst2.h +++ b/src/wine-host/bridges/vst2.h @@ -47,6 +47,9 @@ class Vst2Bridge : public HostBridge { * to load. * @param endpoint_base_dir The base directory used for the socket * endpoints. See `Sockets` for more information. + * @param parent_pid The process ID of the native plugin host this bridge is + * supposed to communicate with. Used as part of our watchdog to prevent + * dangling Wine processes. * * @note The object has to be constructed from the same thread that calls * `main_context.run()`. @@ -56,7 +59,8 @@ class Vst2Bridge : public HostBridge { */ Vst2Bridge(MainContext& main_context, std::string plugin_dll_path, - std::string endpoint_base_dir); + std::string endpoint_base_dir, + pid_t parent_pid); bool inhibits_event_loop() override; diff --git a/src/wine-host/bridges/vst3.cpp b/src/wine-host/bridges/vst3.cpp index 96985e32..1f482269 100644 --- a/src/wine-host/bridges/vst3.cpp +++ b/src/wine-host/bridges/vst3.cpp @@ -89,8 +89,9 @@ InstanceInterfaces::InstanceInterfaces( Vst3Bridge::Vst3Bridge(MainContext& main_context, std::string plugin_dll_path, - std::string endpoint_base_dir) - : HostBridge(main_context, plugin_dll_path), + std::string endpoint_base_dir, + pid_t parent_pid) + : HostBridge(main_context, plugin_dll_path, parent_pid), logger(generic_logger), sockets(main_context.context, endpoint_base_dir, false) { std::string error; diff --git a/src/wine-host/bridges/vst3.h b/src/wine-host/bridges/vst3.h index f9505f78..5c6139ff 100644 --- a/src/wine-host/bridges/vst3.h +++ b/src/wine-host/bridges/vst3.h @@ -207,6 +207,9 @@ class Vst3Bridge : public HostBridge { * load. * @param endpoint_base_dir The base directory used for the socket * endpoints. See `Sockets` for more information. + * @param parent_pid The process ID of the native plugin host this bridge is + * supposed to communicate with. Used as part of our watchdog to prevent + * dangling Wine processes. * * @note The object has to be constructed from the same thread that calls * `main_context.run()`. @@ -216,7 +219,8 @@ class Vst3Bridge : public HostBridge { */ Vst3Bridge(MainContext& main_context, std::string plugin_dll_path, - std::string endpoint_base_dir); + std::string endpoint_base_dir, + pid_t parent_pid); /** * For VST3 plugins we'll have to check for every object in diff --git a/src/wine-host/individual-host.cpp b/src/wine-host/individual-host.cpp index 059a942c..d7cd8f5a 100644 --- a/src/wine-host/individual-host.cpp +++ b/src/wine-host/individual-host.cpp @@ -82,12 +82,14 @@ __cdecl switch (plugin_type) { case PluginType::vst2: bridge = std::make_unique( - main_context, plugin_location, socket_endpoint_path); + main_context, plugin_location, socket_endpoint_path, + parent_pid); break; case PluginType::vst3: #ifdef WITH_VST3 bridge = std::make_unique( - main_context, plugin_location, socket_endpoint_path); + main_context, plugin_location, socket_endpoint_path, + parent_pid); #else std::cerr << "This version of yabridge has not been compiled " "with VST3 support"