Skip to content

Commit

Permalink
Add garbage collector thread as sidecar of render thread
Browse files Browse the repository at this point in the history
  • Loading branch information
uklotzde committed Jul 19, 2023
1 parent 70382ce commit 092e556
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 4 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ dasp_sample = "0.11"
float_eq = "1.0"
hound = "3.5"
hrtf = "0.8"
llq = "0.1.1"
log = "0.4"
num-complex = "0.4"
realfft = "3.0"
Expand Down
2 changes: 1 addition & 1 deletion src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ impl AudioContextRegistration {
pub fn post_message<M: Any + Send + 'static>(&self, msg: M) {
let wrapped = crate::message::ControlMessage::NodeMessage {
id: self.id,
msg: Box::new(msg),
msg: llq::Node::new(Box::new(msg)),
};
let _ = self.context.send_control_msg(wrapped);
}
Expand Down
2 changes: 1 addition & 1 deletion src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,6 @@ pub(crate) enum ControlMessage {
/// Generic message to be handled by AudioProcessor
NodeMessage {
id: AudioNodeId,
msg: Box<dyn Any + Send + 'static>,
msg: llq::Node<Box<dyn Any + Send + 'static>>,
},
}
43 changes: 41 additions & 2 deletions src/render/thread.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
//! Communicates with the control thread and ships audio samples to the hardware

use std::any::Any;
use std::cell::Cell;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use std::time::Instant;
use std::time::{Duration, Instant};

use crossbeam_channel::{Receiver, Sender};
use dasp_sample::FromSample;
Expand Down Expand Up @@ -31,6 +32,7 @@ pub(crate) struct RenderThread {
buffer_offset: Option<(usize, AudioRenderQuantum)>,
load_value_sender: Option<Sender<AudioRenderCapacityLoad>>,
event_sender: Option<Sender<EventDispatch>>,
garbage_collector: llq::Producer<Box<dyn Any + Send + 'static>>,
}

// SAFETY:
Expand All @@ -53,6 +55,8 @@ impl RenderThread {
load_value_sender: Option<Sender<AudioRenderCapacityLoad>>,
event_sender: Option<Sender<EventDispatch>>,
) -> Self {
let (gc_producer, gc_consumer) = llq::Queue::new().split();
spawn_garbage_collector_thread(gc_consumer);
Self {
graph: None,
sample_rate,
Expand All @@ -62,6 +66,7 @@ impl RenderThread {
buffer_offset: None,
load_value_sender,
event_sender,
garbage_collector: gc_producer,
}
}

Expand Down Expand Up @@ -124,7 +129,7 @@ impl RenderThread {
}
NodeMessage { id, mut msg } => {
self.graph.as_mut().unwrap().route_message(id, msg.as_mut());
// FIXME: Drop the remains of the handled message outside of the render thread.
self.garbage_collector.push(msg);
}
}
}
Expand Down Expand Up @@ -296,6 +301,40 @@ impl RenderThread {

impl Drop for RenderThread {
fn drop(&mut self) {
self.garbage_collector
.push(llq::Node::new(Box::new(TerminateGarbageCollectorThread)));
log::info!("Audio render thread has been dropped");
}
}

// Controls the polling frequency of the garbage collector thread.
const GARBAGE_COLLECTOR_THREAD_TIMEOUT: Duration = Duration::from_millis(100);

// Poison pill that terminates the garbage collector thread.
#[derive(Debug)]
struct TerminateGarbageCollectorThread;

// Spawns a sidecar thread of the `RenderThread` for dropping resources.
fn spawn_garbage_collector_thread(consumer: llq::Consumer<Box<dyn Any + Send + 'static>>) {
let _join_handle = std::thread::spawn(move || run_garbage_collector_thread(consumer));
}

fn run_garbage_collector_thread(mut consumer: llq::Consumer<Box<dyn Any + Send + 'static>>) {
log::info!("Entering garbage collector thread");
loop {
if let Some(node) = consumer.pop() {
if node
.as_ref()
.downcast_ref::<TerminateGarbageCollectorThread>()
.is_some()
{
log::info!("Terminating garbage collector thread");
break;
}
// Implicitly drop the received node.
} else {
std::thread::sleep(GARBAGE_COLLECTOR_THREAD_TIMEOUT);
}
}
log::info!("Exiting garbage collector thread");
}

0 comments on commit 092e556

Please sign in to comment.