13
0

VST3: fix deadlock when loading a preset in some plugins

Some plugins call back to restartComponent() directly from
IEditController::setComponentState.

This lead to a deadlock since VST3Plugin::load_preset
takes a lock (since 7.2-85 b27467157b), and restartComponent
takes the same mutex again.
This commit is contained in:
Robin Gareus 2023-02-15 23:50:11 +01:00
parent 8f248bd0ba
commit 3c57085756
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
2 changed files with 11 additions and 4 deletions

View File

@ -185,6 +185,7 @@ public:
bool activate ();
bool deactivate ();
bool active () const { return _is_processing; }
bool is_loading_state () const { return _is_loading_state; }
/* State */
bool save_state (RAMStream& stream);
@ -271,6 +272,7 @@ private:
Vst3EventList _output_events;
/* state */
bool _is_loading_state;
bool _is_processing;
int32_t _block_size;

View File

@ -27,6 +27,7 @@
#include "pbd/failed_constructor.h"
#include "pbd/file_utils.h"
#include "pbd/tokenizer.h"
#include "pbd/unwind.h"
#ifdef PLATFORM_WINDOWS
#include "pbd/windows_special_dirs.h"
@ -168,7 +169,7 @@ VST3Plugin::default_value (uint32_t port)
void
VST3Plugin::set_parameter (uint32_t port, float val, sampleoffset_t when)
{
if (!_plug->active () || AudioEngine::instance()->in_process_thread()) {
if (!_plug->active () || _plug->is_loading_state () || AudioEngine::instance()->in_process_thread() ) {
/* directly use VST3PI::_input_param_changes */
_plug->set_parameter (port, val, when);
} else {
@ -1144,6 +1145,7 @@ VST3PI::VST3PI (boost::shared_ptr<ARDOUR::VST3PluginModule> m, std::string uniqu
#if SMTG_OS_LINUX
, _run_loop (0)
#endif
, _is_loading_state (false)
, _is_processing (false)
, _block_size (0)
, _port_id_bypass (UINT32_MAX)
@ -1471,7 +1473,7 @@ VST3PI::restartComponent (int32 flags)
if (flags & Vst::kReloadComponent) {
Glib::Threads::Mutex::Lock pl (_process_lock, Glib::Threads::NOT_LOCK);
if (!AudioEngine::instance()->in_process_thread()) {
if (!AudioEngine::instance()->in_process_thread() && !_is_loading_state) {
pl.acquire ();
} else {
assert (0); // a plugin should not call this while processing
@ -1489,7 +1491,7 @@ VST3PI::restartComponent (int32 flags)
}
if (flags & Vst::kParamValuesChanged) {
Glib::Threads::Mutex::Lock pl (_process_lock, Glib::Threads::NOT_LOCK);
if (!AudioEngine::instance()->in_process_thread()) {
if (!AudioEngine::instance()->in_process_thread() && !_is_loading_state) {
pl.acquire ();
}
update_shadow_data ();
@ -1504,7 +1506,7 @@ VST3PI::restartComponent (int32 flags)
* changes are automatically picked up.
*/
Glib::Threads::Mutex::Lock pl (_process_lock, Glib::Threads::NOT_LOCK);
if (!AudioEngine::instance()->in_process_thread()) {
if (!AudioEngine::instance()->in_process_thread() && !_is_loading_state) {
/* Some plugins (e.g BlendEQ) call this from the process,
* IPlugProcessor::ProcessBuffers. In that case taking the
* _process_lock would deadlock.
@ -2392,6 +2394,9 @@ VST3PI::load_state (RAMStream& stream)
if (!read_equal_ID (stream, Vst::getChunkID (Vst::kChunkList))) {
return false;
}
PBD::Unwinder<bool> uw (_is_loading_state, true);
int32 count;
stream.read_int32 (count);
for (int32 i = 0; i < count; ++i) {