mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-06-15 07:53:55 +02:00
Get rid of the ugly Win32 threads in group host
Running the audio processing and midi dispatcher loops in a regular `std::thread` causes weird memory corruption issues (likely because of calling conventions are not being respected). Luckily this does not cause any issues here, so we can get rid of a lot of ugly glue code and manual memory management.
This commit is contained in:
@@ -59,17 +59,6 @@ boost::asio::local::stream_protocol::acceptor create_acceptor_if_inactive(
|
|||||||
*/
|
*/
|
||||||
std::string create_logger_prefix(const fs::path& socket_path);
|
std::string create_logger_prefix(const fs::path& socket_path);
|
||||||
|
|
||||||
uint32_t WINAPI handle_plugin_dispatch_proxy(void* param);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CreateThread() is great and allows you to pass a single value to the
|
|
||||||
* function, so we'll use this to pass both `this` and the parameters to the
|
|
||||||
* below thread function so it can do its thing.
|
|
||||||
*
|
|
||||||
* @relates handle_plugin_dispatch_proxy
|
|
||||||
*/
|
|
||||||
using handle_plugin_dispatch_parameters = std::pair<GroupBridge*, GroupRequest>;
|
|
||||||
|
|
||||||
StdIoCapture::StdIoCapture(boost::asio::io_context& io_context,
|
StdIoCapture::StdIoCapture(boost::asio::io_context& io_context,
|
||||||
int file_descriptor)
|
int file_descriptor)
|
||||||
: pipe(io_context),
|
: pipe(io_context),
|
||||||
@@ -131,11 +120,17 @@ void GroupBridge::handle_plugin_dispatch(const GroupRequest request) {
|
|||||||
bridge->handle_dispatch();
|
bridge->handle_dispatch();
|
||||||
logger.log("'" + request.plugin_path + "' has exited");
|
logger.log("'" + request.plugin_path + "' has exited");
|
||||||
|
|
||||||
// After the plugin has exited, we'll remove this thread's plugin from the
|
// After the plugin has exited we'll remove this thread's plugin from the
|
||||||
// active plugins. If no active plugins remain, then we'll terminate the
|
// active plugins. This is done within the IO context so we can properly
|
||||||
// process.
|
// join the thread again. If no active plugins remain, then we'll terminate
|
||||||
std::lock_guard lock(active_plugins_mutex);
|
// the process.
|
||||||
active_plugins.erase(request);
|
boost::asio::post(plugin_context, [&, request]() {
|
||||||
|
std::lock_guard lock(active_plugins_mutex);
|
||||||
|
|
||||||
|
auto& [thread, bridge] = active_plugins.at(request);
|
||||||
|
thread.join();
|
||||||
|
active_plugins.erase(request);
|
||||||
|
});
|
||||||
|
|
||||||
// Defer actually shutting down the process to allow for fast plugin
|
// Defer actually shutting down the process to allow for fast plugin
|
||||||
// scanning by allowing plugins to reuse the same group host process
|
// scanning by allowing plugins to reuse the same group host process
|
||||||
@@ -219,13 +214,14 @@ void GroupBridge::accept_requests() {
|
|||||||
logger.log("Finished initializing '" + request.plugin_path +
|
logger.log("Finished initializing '" + request.plugin_path +
|
||||||
"'");
|
"'");
|
||||||
|
|
||||||
// CreateThread() doesn't support multiple arguments and
|
// Start listening for dispatcher events sent to the plugin's
|
||||||
// requires manualy memory management.
|
// socket on another thread. The actual event handling will
|
||||||
handle_plugin_dispatch_parameters* thread_params =
|
// still occur within this IO context.
|
||||||
new std::pair<GroupBridge*, GroupRequest>(this, request);
|
active_plugins[request] =
|
||||||
active_plugins[request] = std::pair(
|
std::pair(std::thread([&, request]() {
|
||||||
Win32Thread(handle_plugin_dispatch_proxy, thread_params),
|
handle_plugin_dispatch(request);
|
||||||
std::move(bridge));
|
}),
|
||||||
|
std::move(bridge));
|
||||||
} catch (const std::runtime_error& error) {
|
} catch (const std::runtime_error& error) {
|
||||||
logger.log("Error while initializing '" + request.plugin_path +
|
logger.log("Error while initializing '" + request.plugin_path +
|
||||||
"':");
|
"':");
|
||||||
@@ -258,8 +254,6 @@ void GroupBridge::async_handle_events() {
|
|||||||
|
|
||||||
// Handle Win32 messages unless plugins are in the middle of opening
|
// Handle Win32 messages unless plugins are in the middle of opening
|
||||||
// their editor
|
// their editor
|
||||||
// TODO: Check if those same weird crashes with Serum are happening
|
|
||||||
// again with these normal threads
|
|
||||||
if (!should_skip_message_loop()) {
|
if (!should_skip_message_loop()) {
|
||||||
std::lock_guard lock(active_plugins_mutex);
|
std::lock_guard lock(active_plugins_mutex);
|
||||||
|
|
||||||
@@ -360,16 +354,3 @@ std::string create_logger_prefix(const fs::path& socket_path) {
|
|||||||
|
|
||||||
return "[" + socket_name + "] ";
|
return "[" + socket_name + "] ";
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t WINAPI handle_plugin_dispatch_proxy(void* param) {
|
|
||||||
// The Win32 API only allows you to pass a void pointer to threads, so we
|
|
||||||
// need to use manual memory management.
|
|
||||||
auto thread_params = static_cast<handle_plugin_dispatch_parameters*>(param);
|
|
||||||
GroupBridge* instance = thread_params->first;
|
|
||||||
GroupRequest parameters = thread_params->second;
|
|
||||||
delete thread_params;
|
|
||||||
|
|
||||||
instance->handle_plugin_dispatch(parameters);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -127,9 +127,7 @@ class GroupBridge {
|
|||||||
* Run a plugin's dispatcher and message loop, processing all events on the
|
* Run a plugin's dispatcher and message loop, processing all events on the
|
||||||
* main IO context. The plugin will have already been created in
|
* main IO context. The plugin will have already been created in
|
||||||
* `accept_requests` since it has to be initiated inside of the IO context's
|
* `accept_requests` since it has to be initiated inside of the IO context's
|
||||||
* thread. Called by proxy using `handle_plugin_dispatch_proxy()` in
|
* thread.
|
||||||
* `./group.cpp` because the Win32 `CreateThread` API only allows passing a
|
|
||||||
* single pointer to the function and does not allow lambdas.
|
|
||||||
*
|
*
|
||||||
* Once the plugin has exited, this thread will then remove itself from the
|
* Once the plugin has exited, this thread will then remove itself from the
|
||||||
* `active_plugins` map. If this causes the vector to become empty, we will
|
* `active_plugins` map. If this causes the vector to become empty, we will
|
||||||
@@ -264,7 +262,7 @@ class GroupBridge {
|
|||||||
* conventions were nto being respected.
|
* conventions were nto being respected.
|
||||||
*/
|
*/
|
||||||
std::unordered_map<GroupRequest,
|
std::unordered_map<GroupRequest,
|
||||||
std::pair<Win32Thread, std::unique_ptr<Vst2Bridge>>>
|
std::pair<std::thread, std::unique_ptr<Vst2Bridge>>>
|
||||||
active_plugins;
|
active_plugins;
|
||||||
/**
|
/**
|
||||||
* A mutex to prevent two threads from simultaneously accessing the plugins
|
* A mutex to prevent two threads from simultaneously accessing the plugins
|
||||||
|
|||||||
Reference in New Issue
Block a user