From b9a926c1254b44d450f00eb161139fdd6f6bbbd1 Mon Sep 17 00:00:00 2001 From: Kyle Simpson Date: Thu, 11 Mar 2021 22:58:30 +0000 Subject: [PATCH] Break reference cycle in voice storage example (#44) Changes a stored `Arc` pointer to the call (used to queue up further tracks in response to events) into a `Weak`, as the event handler's strong pointer would keep the Call and Driver objects alive. This would have caused an unintentional resource leak of threads/tasks. This was found by some internal profiling in search of #42. --- examples/serenity/voice_storage/src/main.rs | 22 +++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/examples/serenity/voice_storage/src/main.rs b/examples/serenity/voice_storage/src/main.rs index b8ee25b..8973c0d 100644 --- a/examples/serenity/voice_storage/src/main.rs +++ b/examples/serenity/voice_storage/src/main.rs @@ -9,7 +9,7 @@ //! git = "https://github.com/serenity-rs/serenity.git" //! features = ["cache", "framework", "standard_framework", "voice"] //! ``` -use std::{collections::HashMap, convert::TryInto, env, sync::Arc}; +use std::{collections::HashMap, convert::TryInto, env, sync::{Arc, Weak}}; use serenity::{ async_trait, @@ -206,7 +206,7 @@ async fn join(ctx: &Context, msg: &Message) -> CommandResult { let (handler_lock, success_reader) = manager.join(guild_id, connect_to).await; - let call_lock_for_evt = handler_lock.clone(); + let call_lock_for_evt = Arc::downgrade(&handler_lock); if let Ok(_reader) = success_reader { let mut handler = handler_lock.lock().await; @@ -237,21 +237,23 @@ async fn join(ctx: &Context, msg: &Message) -> CommandResult { } struct LoopPlaySound { - call_lock: Arc>, + call_lock: Weak>, sources: Arc>>, } #[async_trait] impl VoiceEventHandler for LoopPlaySound { async fn act(&self, _ctx: &EventContext<'_>) -> Option { - let src = { - let sources = self.sources.lock().await; - sources.get("loop").expect("Handle placed into cache at startup.").into() - }; + if let Some(call_lock) = self.call_lock.upgrade() { + let src = { + let sources = self.sources.lock().await; + sources.get("loop").expect("Handle placed into cache at startup.").into() + }; - let mut handler = self.call_lock.lock().await; - let sound = handler.play_source(src); - let _ = sound.set_volume(0.5); + let mut handler = call_lock.lock().await; + let sound = handler.play_source(src); + let _ = sound.set_volume(0.5); + } None }