1
0
Fork 0

Fix VST3 event loop leaking

This should have never used MaybeUninit in the first place.
This commit is contained in:
Robbert van der Helm 2022-08-22 12:31:09 +02:00
parent 5110e5b059
commit 26e0d17833
2 changed files with 21 additions and 17 deletions

View file

@ -3,7 +3,6 @@ use crossbeam::atomic::AtomicCell;
use crossbeam::channel::{self, SendTimeoutError};
use parking_lot::RwLock;
use std::collections::{HashMap, HashSet, VecDeque};
use std::mem::MaybeUninit;
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
use std::sync::Arc;
use std::time::Duration;
@ -53,11 +52,11 @@ pub(crate) struct WrapperInner<P: Vst3Plugin> {
/// through [`Self::do_maybe_async()`] instead. That method posts the task to the host's
/// `IRunLoop` instead of it's available.
///
/// This RwLock is only needed because it has to be initialized late. There is no reason to
/// mutably borrow the event loop, so reads will never be contested.
/// This AtomicRefCell+Option is only needed because it has to be initialized late. There is no
/// reason to mutably borrow the event loop, so reads will never be contested.
///
/// TODO: Is there a better type for Send+Sync late initializaiton?
pub event_loop: AtomicRefCell<MaybeUninit<OsEventLoop<Task, Self>>>,
pub event_loop: AtomicRefCell<Option<OsEventLoop<Task, Self>>>,
/// Whether the plugin is currently processing audio. In other words, the last state
/// `IAudioProcessor::setActive()` has been called with.
@ -281,7 +280,7 @@ impl<P: Vst3Plugin> WrapperInner<P> {
plug_view: RwLock::new(None),
event_loop: AtomicRefCell::new(MaybeUninit::uninit()),
event_loop: AtomicRefCell::new(None),
is_processing: AtomicBool::new(false),
// Some hosts, like the current version of Bitwig and Ardour at the time of writing,
@ -321,7 +320,7 @@ impl<P: Vst3Plugin> WrapperInner<P> {
// is separate from the internal COM-style reference count.
let wrapper: Arc<WrapperInner<P>> = wrapper.into();
*wrapper.event_loop.borrow_mut() =
MaybeUninit::new(OsEventLoop::new_and_spawn(Arc::downgrade(&wrapper)));
Some(OsEventLoop::new_and_spawn(Arc::downgrade(&wrapper)));
wrapper
}
@ -351,7 +350,7 @@ impl<P: Vst3Plugin> WrapperInner<P> {
#[must_use]
pub fn do_maybe_async(&self, task: Task) -> bool {
let event_loop = self.event_loop.borrow();
let event_loop = unsafe { event_loop.assume_init_ref() };
let event_loop = event_loop.as_ref().unwrap();
if event_loop.is_main_thread() {
unsafe { self.execute(task) };
true
@ -480,9 +479,14 @@ impl<P: Vst3Plugin> WrapperInner<P> {
}
// After the state has been updated, notify the host about the new parameter values
let task_posted = unsafe { self.event_loop.borrow().assume_init_ref() }.do_maybe_async(
Task::TriggerRestart(RestartFlags::kParamValuesChanged as i32),
);
let task_posted =
self.event_loop
.borrow()
.as_ref()
.unwrap()
.do_maybe_async(Task::TriggerRestart(
RestartFlags::kParamValuesChanged as i32,
));
nih_debug_assert!(task_posted, "The task queue is full, dropping task...");
}

View file

@ -508,13 +508,13 @@ impl<P: Vst3Plugin> Drop for RunLoopEventHandler<P> {
// handle those in the regular event loop so no work gets lost
let mut posting_failed = false;
while let Some(task) = self.tasks.pop() {
posting_failed |= !unsafe {
self.inner
.event_loop
.borrow()
.assume_init_ref()
.do_maybe_async(task)
};
posting_failed |= !self
.inner
.event_loop
.borrow()
.as_ref()
.unwrap()
.do_maybe_async(task);
}
if posting_failed {