From f2597ca0b9e290518fca2303001133c60be92b3e Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Sat, 14 Mar 2020 18:08:23 +0100 Subject: [PATCH] Prevent race conditions from simultaneous dispatch calls --- README.md | 2 -- src/plugin/host-bridge.cpp | 16 ++++++++++++++-- src/plugin/host-bridge.h | 11 +++++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 98807e6a..9e687625 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,6 @@ There are a few things that should be done before making this public, including: - Implement missing features: - GUIs. Right now I'm just ignoring all of the opcodes related to GUIs so that the plugins don't crash when you open their GUI. - - The initial host callback fails in Bitwig if the plugin is bridged, but it - works if it's directly loaded into Bitwig. - Check whether sidechaining and ~~MPE~~ work since they're unofficial additions to the VST 2.4 spec. Should either work out of the box or with a minor adjustment. MPE works! diff --git a/src/plugin/host-bridge.cpp b/src/plugin/host-bridge.cpp index 3b8c573f..263d79c9 100644 --- a/src/plugin/host-bridge.cpp +++ b/src/plugin/host-bridge.cpp @@ -269,8 +269,20 @@ intptr_t HostBridge::dispatch(AEffect* /*plugin*/, } // TODO: Maybe reuse buffers here when dealing with chunk data - return send_event(host_vst_dispatch, converter, opcode, index, value, data, - option, std::pair(logger, true)); + + // Finish message Bitwig's plugin host sometimes calls the dispatch function + // for opcode 52 from an off thread. This shouldn't be happening, but it + // does. To prevent race conditions from multiple writes over the same + // socket at once we'll make sure that only one thread can send sockets at + // once. These locks are actually only needed around the `write_object()` + // part of `send_event()`. + dispatch_semaphore.lock(); + const auto return_value = + send_event(host_vst_dispatch, converter, opcode, index, value, data, + option, std::pair(logger, true)); + dispatch_semaphore.unlock(); + + return return_value; } void HostBridge::process_replacing(AEffect* /*plugin*/, diff --git a/src/plugin/host-bridge.h b/src/plugin/host-bridge.h index a4269b7a..852c5da6 100644 --- a/src/plugin/host-bridge.h +++ b/src/plugin/host-bridge.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "../common/logging.h" @@ -156,6 +157,16 @@ class HostBridge { */ std::thread host_callback_handler; + /** + * A binary semaphore for preventing the dispatch function from being called + * by two threads at once. This rarely happens and shouldn't event really be + * happening, but in Bitwig's plugin bridge sometimes calls the dispatch + * function with opcode 52 while it's still waiting for another dispatch + * call to return, which would cause two threads to write over the same + * socket at the same time. + */ + std::mutex dispatch_semaphore; + /** * The callback function passed by the host to the VST plugin instance. */