VST3 and Clap plugin instances may access their AudioThreadState's processor AtomicRefCell from different threads at the same time, the main thread and the audio thread. So it's very unlikely, but possible that this will randomly cause an already borrowed panic.
It's hard to replicate, but I can do so by creating a big bunch (~100) of plinth based plugins in Renoise, saving this as a song template. Loading such a song with many plinth instances will then sooner or later crash in IProcessorTrait::setProcessing:
|
let mut processor = self.audio_thread_state.processor.borrow_mut(); |
In my reproducible case, the processor's mut_borrow is held by the main thread's setActivate function.
Before that, I got random crashes once a week or so with heavy usage while developing & testing my plugin.
The problem is conceptionally quite clear though:
VST3's and CLAP's active/deactivate functions may only be called from the main thread. Those (re)create the processor. The VST3 setprocessing and CLAP's reset functions on the other hand, may be called from the audio thread only.
So even if a host follows the specs very closely (which isn't the usual case), it's unlikely, yet possible, that both setactive and setprocessing may get called at the same time.
Only way I see to fix that would be using a Mutex here, but maybe you've got a better idea here.
As Mutex on Rust uses a Futex or something comparable lightweight to check if the mutex is locked, the uncontended access should be, in theory, roughly as fast as it is now with the AtomicRefCell.
Using try_borow_mut with the AtomicRefCell could work here too, but it's going to be hard to handle the can't access case.
It's definitely super ugly to use a lock in audio time here - that feels wrong - but likely is just fine in practice here as it basically never locks in practice. And when it locks, it does so while processors get rebuilt.
BTW: Just have seen you've released your plugin. Congrats! it looks fabulous. I hope all is going well and as planed.
VST3 and Clap plugin instances may access their
AudioThreadState's processor AtomicRefCell from different threads at the same time, the main thread and the audio thread. So it's very unlikely, but possible that this will randomly cause analready borrowedpanic.It's hard to replicate, but I can do so by creating a big bunch (~100) of plinth based plugins in Renoise, saving this as a song template. Loading such a song with many plinth instances will then sooner or later crash in
IProcessorTrait::setProcessing:plugin-things/plinth-plugin/src/formats/vst3/component.rs
Line 260 in 2002514
In my reproducible case, the processor's
mut_borrowis held by the main thread'ssetActivatefunction.Before that, I got random crashes once a week or so with heavy usage while developing & testing my plugin.
The problem is conceptionally quite clear though:
VST3's and CLAP's
active/deactivatefunctions may only be called from the main thread. Those (re)create the processor. The VST3setprocessingand CLAP'sresetfunctions on the other hand, may be called from the audio thread only.So even if a host follows the specs very closely (which isn't the usual case), it's unlikely, yet possible, that both
setactiveandsetprocessingmay get called at the same time.Only way I see to fix that would be using a Mutex here, but maybe you've got a better idea here.
As Mutex on Rust uses a Futex or something comparable lightweight to check if the mutex is locked, the uncontended access should be, in theory, roughly as fast as it is now with the AtomicRefCell.
Using
try_borow_mutwith the AtomicRefCell could work here too, but it's going to be hard to handle thecan't accesscase.It's definitely super ugly to use a lock in audio time here - that feels wrong - but likely is just fine in practice here as it basically never locks in practice. And when it locks, it does so while processors get rebuilt.
BTW: Just have seen you've released your plugin. Congrats! it looks fabulous. I hope all is going well and as planed.