diff --git a/src/wine-host/bridges/group.cpp b/src/wine-host/bridges/group.cpp index 7cc08034..bb4eb6d5 100644 --- a/src/wine-host/bridges/group.cpp +++ b/src/wine-host/bridges/group.cpp @@ -84,14 +84,14 @@ StdIoCapture::~StdIoCapture() { GroupBridge::GroupBridge(boost::filesystem::path group_socket_path) : logger(Logger::create_from_environment( create_logger_prefix(group_socket_path))), - plugin_context(), + main_context(), stdio_context(), stdout_redirect(stdio_context, STDOUT_FILENO), stderr_redirect(stdio_context, STDERR_FILENO), group_socket_endpoint(group_socket_path.string()), - group_socket_acceptor(create_acceptor_if_inactive(plugin_context.context, + group_socket_acceptor(create_acceptor_if_inactive(main_context.context, group_socket_endpoint)), - shutdown_timer(plugin_context.context) { + shutdown_timer(main_context.context) { // Write this process's original STDOUT and STDERR streams to the logger // TODO: This works for output generated by plugins, but not for debug // messages generated by wineserver. Is it possible to catch those? @@ -125,7 +125,7 @@ void GroupBridge::handle_plugin_dispatch(size_t plugin_id) { // potentially corrupt our heap. This way we can also properly join the // thread again. If no active plugins remain, then we'll terminate the // process. - boost::asio::post(plugin_context.context, [this, plugin_id]() { + boost::asio::post(main_context.context, [this, plugin_id]() { std::lock_guard lock(active_plugins_mutex); // The join is implicit because we're using Win32Thread (which mimics @@ -147,7 +147,7 @@ void GroupBridge::handle_plugin_dispatch(size_t plugin_id) { if (active_plugins.size() == 0) { logger.log( "All plugins have exited, shutting down the group process"); - plugin_context.stop(); + main_context.stop(); } }); } @@ -158,7 +158,7 @@ void GroupBridge::handle_incoming_connections() { logger.log( "Group host is up and running, now accepting incoming connections"); - plugin_context.run(); + main_context.run(); } bool GroupBridge::should_skip_message_loop() { @@ -188,7 +188,7 @@ void GroupBridge::accept_requests() { logger.log("Error while listening for incoming connections:"); logger.log(error.message()); - plugin_context.stop(); + main_context.stop(); } // Read the parameters, and then host the plugin in this process @@ -208,7 +208,7 @@ void GroupBridge::accept_requests() { request.endpoint_base_dir + "'"); try { auto bridge = std::make_unique( - plugin_context, request.plugin_path, + main_context, request.plugin_path, request.endpoint_base_dir); logger.log("Finished initializing '" + request.plugin_path + "'"); @@ -235,7 +235,7 @@ void GroupBridge::accept_requests() { } void GroupBridge::async_handle_events() { - plugin_context.async_handle_events([&]() { + main_context.async_handle_events([&]() { { // Always handle X11 events std::lock_guard lock(active_plugins_mutex); diff --git a/src/wine-host/bridges/group.h b/src/wine-host/bridges/group.h index 5c2a8d90..13f4fcf1 100644 --- a/src/wine-host/bridges/group.h +++ b/src/wine-host/bridges/group.h @@ -179,7 +179,7 @@ class GroupBridge { * event handling and message loop interaction also has to be done from that * thread, which is why we initialize the plugin here and use the * `handle_dispatch()` function to run events within the same - * `plugin_context`. + * `main_context`. * * @see handle_plugin_dispatch */ @@ -217,13 +217,13 @@ class GroupBridge { * operations that may involve the Win32 mesasge loop (e.g. initialization * and most `AEffect::dispatcher()` calls) should be run on. */ - PluginContext plugin_context; + MainContext main_context; /** * A seperate IO context that handles the STDIO redirect through - * `StdIoCapture`. This is seperated the `plugin_context` above so that - * STDIO capture does not get blocked by blocking GUI operations. Since - * every GUI related operation should be run from the same thread, we can't - * just add another thread to the main IO context. + * `StdIoCapture`. This is separated from the `main_context` above so that + * STDIO capture does not get blocked by GUI operations. Since every GUI + * related operation should be run from the same thread, we can't just add + * another thread to the main IO context. */ boost::asio::io_context stdio_context; diff --git a/src/wine-host/bridges/vst2.cpp b/src/wine-host/bridges/vst2.cpp index 4093dd21..4f2f7601 100644 --- a/src/wine-host/bridges/vst2.cpp +++ b/src/wine-host/bridges/vst2.cpp @@ -66,13 +66,13 @@ Vst2Bridge& get_bridge_instance(const AEffect* plugin) { return *static_cast(plugin->ptr1); } -Vst2Bridge::Vst2Bridge(PluginContext& main_context, +Vst2Bridge::Vst2Bridge(MainContext& main_context, std::string plugin_dll_path, std::string endpoint_base_dir) : vst_plugin_path(plugin_dll_path), - plugin_context(main_context), + main_context(main_context), plugin_handle(LoadLibrary(plugin_dll_path.c_str()), FreeLibrary), - sockets(plugin_context.context, endpoint_base_dir, false) { + sockets(main_context.context, endpoint_base_dir, false) { // Got to love these C APIs if (!plugin_handle) { throw std::runtime_error("Could not load the Windows .dll file at '" + @@ -350,7 +350,7 @@ void Vst2Bridge::handle_dispatch() { // and where the Win32 message loop is handled. if (unsafe_opcodes.contains(opcode)) { std::promise dispatch_result; - boost::asio::dispatch(plugin_context.context, [&]() { + boost::asio::dispatch(main_context.context, [&]() { const intptr_t result = dispatch_wrapper( plugin, opcode, index, value, data, option); diff --git a/src/wine-host/bridges/vst2.h b/src/wine-host/bridges/vst2.h index ba02d8d0..2bda44bb 100644 --- a/src/wine-host/bridges/vst2.h +++ b/src/wine-host/bridges/vst2.h @@ -74,7 +74,7 @@ class Vst2Bridge { * @throw std::runtime_error Thrown when the VST plugin could not be loaded, * or if communication could not be set up. */ - Vst2Bridge(PluginContext& main_context, + Vst2Bridge(MainContext& main_context, std::string plugin_dll_path, std::string endpoint_base_dir); @@ -164,7 +164,7 @@ class Vst2Bridge { * message handling can be performed from a single thread, even when hosting * multiple plugins. */ - PluginContext& plugin_context; + MainContext& main_context; /** * The configuration for this instance of yabridge based on the `.so` file diff --git a/src/wine-host/individual-host.cpp b/src/wine-host/individual-host.cpp index e7782b3f..1fc812e7 100644 --- a/src/wine-host/individual-host.cpp +++ b/src/wine-host/individual-host.cpp @@ -65,11 +65,11 @@ int __cdecl main(int argc, char* argv[]) { // don't need to differentiate between individually hosted plugins and // plugin groups when it comes to event handling. // TODO: Update documentation once we figure out if we can safely replace - // PluginContext again with a normal `io_context`. - PluginContext plugin_context{}; + // MainContext again with a normal `io_context`. + MainContext main_context{}; std::unique_ptr bridge; try { - bridge = std::make_unique(plugin_context, plugin_dll_path, + bridge = std::make_unique(main_context, plugin_dll_path, socket_endpoint_path); } catch (const std::runtime_error& error) { std::cerr << "Error while initializing Wine VST host:" << std::endl; @@ -87,9 +87,9 @@ int __cdecl main(int argc, char* argv[]) { // Handle Win32 messages and X11 events on a timer, just like in // `GroupBridge::async_handle_events()`` - plugin_context.async_handle_events([&]() { + main_context.async_handle_events([&]() { bridge->handle_x11_events(); bridge->handle_win32_events(); }); - plugin_context.run(); + main_context.run(); } diff --git a/src/wine-host/utils.cpp b/src/wine-host/utils.cpp index 172996c0..ce0562d6 100644 --- a/src/wine-host/utils.cpp +++ b/src/wine-host/utils.cpp @@ -16,7 +16,15 @@ #include "utils.h" -PluginContext::PluginContext() : context(), events_timer(context) {} +MainContext::MainContext() : context(), events_timer(context) {} + +void MainContext::run() { + context.run(); +} + +void MainContext::stop() { + context.stop(); +} uint32_t WINAPI win32_thread_trampoline(fu2::unique_function* entry_point) { @@ -34,14 +42,6 @@ Win32Thread& Win32Thread::operator=(Win32Thread&& o) { return *this; } -void PluginContext::run() { - context.run(); -} - -void PluginContext::stop() { - context.stop(); -} - Win32Thread::Win32Thread() : handle(nullptr, nullptr) {} Win32Timer::Win32Timer(HWND window_handle, diff --git a/src/wine-host/utils.h b/src/wine-host/utils.h index b442ed0d..c2c64c5f 100644 --- a/src/wine-host/utils.h +++ b/src/wine-host/utils.h @@ -39,18 +39,16 @@ constexpr std::chrono::duration event_loop_interval = std::chrono::milliseconds(1000) / 30; /** - * A wrapper around `boost::asio::io_context()`. A single instance is shared for - * all plugins in a plugin group so that most events can be handled on the main - * thread, which can be required because all GUI related operations have to be - * handled from the same thread. If during the Win32 message loop the plugin - * performs a host callback and the host then calls a function on the plugin in - * response, then this IO context will still be busy with the message loop - * which. To prevent a deadlock in this situation, we'll allow different threads - * to handle `dispatch()` calls while the message loop is running. + * A wrapper around `boost::asio::io_context()` to serve as the application's + * main IO context. A single instance is shared for all 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 related operations + * have to be handled from the same thread. This will be run from the + * application's main thread. */ -class PluginContext { +class MainContext { public: - PluginContext(); + MainContext(); /** * Run the IO context. This rest of this class assumes that this is only @@ -60,7 +58,7 @@ class PluginContext { /** * Drop all future work from the IO context. This does not necessarily mean - * that the thread that called `plugin_context.run()` immediatly returns. + * that the thread that called `main_context.run()` immediatly returns. */ void stop(); @@ -98,6 +96,9 @@ class PluginContext { * Is `true` if the context is currently handling the Win32 message loop and * incoming `dispatch()` events should be handled on their own thread (as * posting them to the IO context will thus block). + * + * TODO: No longer used after the thread rework, we can probably just drop + * this if everything works out */ std::atomic_bool event_loop_active;