Handle all dispatch calls from the main thread

Some plugins apparently assume that all events (or at least some
specific ones) are sent from the thread it was created on and will
segfault otherwise. The is the case for Melda plugins.
This commit is contained in:
Robbert van der Helm
2020-03-23 23:41:00 +01:00
parent 5552fc3009
commit 096e36dfdc
3 changed files with 30 additions and 29 deletions
+22 -21
View File
@@ -118,19 +118,6 @@ PluginBridge::PluginBridge(std::string plugin_dll_path,
current_bridge_isntance = nullptr;
plugin->ptr1 = this;
// For our communication we use simple threads and blocking operations
// instead of asynchronous IO since communication has to be handled in
// lockstep anyway
dispatch_handler = std::thread([&]() {
using namespace std::placeholders;
while (true) {
passthrough_event(host_vst_dispatch, std::nullopt, plugin,
std::bind(&PluginBridge::dispatch_wrapper, this,
_1, _2, _3, _4, _5, _6));
}
});
parameters_handler = std::thread([&]() {
while (true) {
// Both `getParameter` and `setParameter` functions are passed
@@ -189,6 +176,26 @@ PluginBridge::PluginBridge(std::string plugin_dll_path,
<< std::endl;
}
void PluginBridge::handle_dispatch() {
using namespace std::placeholders;
// For our communication we use simple threads and blocking operations
// instead of asynchronous IO since communication has to be handled in
// lockstep anyway
try {
while (true) {
passthrough_event(host_vst_dispatch, std::nullopt, plugin,
std::bind(&PluginBridge::dispatch_wrapper, this,
_1, _2, _3, _4, _5, _6));
}
} catch (const boost::system::system_error&) {
// This happens when the sockets got closed because the plugin is being
// shut down. In that case we can just let the whole host terminate.
parameters_handler.detach();
process_replacing_handler.detach();
}
}
intptr_t PluginBridge::dispatch_wrapper(AEffect* plugin,
int opcode,
int index,
@@ -199,9 +206,9 @@ intptr_t PluginBridge::dispatch_wrapper(AEffect* plugin,
// the X11 window handle passed by the host
switch (opcode) {
case effEditIdle:
// Because of the way the Win32 APi works we have to process events
// Because of the way the Win32 API works we have to process events
// on the same thread the window was created, and that thread is the
// `dispatch_handler` thread
// thread that's handling dispatcher calls
editor.handle_events();
return plugin->dispatcher(plugin, opcode, index, value, data,
@@ -261,12 +268,6 @@ intptr_t PluginBridge::dispatch_wrapper(AEffect* plugin,
}
}
void PluginBridge::wait() {
dispatch_handler.join();
parameters_handler.join();
process_replacing_handler.join();
}
class HostCallbackDataConverter : DefaultDataConverter {
public:
HostCallbackDataConverter(AEffect* plugin,
+6 -6
View File
@@ -55,9 +55,13 @@ class PluginBridge {
PluginBridge(std::string plugin_dll_path, std::string socket_endpoint_path);
/**
* Block the main thread until the plugin shuts down.
* Handle events on the main thread until the plugin quits. This can't be
* done on another thread since some plugins (e.g. Melda) expect certain
* (but for some reason not all) events to be passed from the same thread it
* was initiated from. This is then also the same thread that should handle
* Win32 GUI events.
*/
void wait();
void handle_dispatch();
intptr_t host_callback(AEffect*, int, int, intptr_t, void*, float);
@@ -115,10 +119,6 @@ class PluginBridge {
*/
boost::asio::local::stream_protocol::socket vst_host_aeffect;
/**
* The thread that handles dispatch events from the host.
*/
std::thread dispatch_handler;
/**
* The thread that responds to `getParameter` and `setParameter` requests.
*/
+2 -2
View File
@@ -35,8 +35,8 @@ int main(int argc, char* argv[]) {
try {
PluginBridge bridge(plugin_dll_path, socket_endpoint_path);
// Block the main thread until the plugin shuts down
bridge.wait();
// Blocks the main thread until the plugin shuts down
bridge.handle_dispatch();
} catch (const std::runtime_error& error) {
std::cerr << "Error while initializing Wine VST host:" << std::endl;
std::cerr << error.what() << std::endl;