Module: Mesa
Branch: main
Commit: 9a3af6e1d8a88ff5c919d33966e97168fe780a86
URL:    
http://cgit.freedesktop.org/mesa/mesa/commit/?id=9a3af6e1d8a88ff5c919d33966e97168fe780a86

Author: Karol Herbst <kher...@redhat.com>
Date:   Thu Oct 26 18:50:37 2023 +0200

rusticl/queue: Only take a weak ref to the last Event

This resolves a memory leak when the application drops its last reference
to the queue, but never waits explicitly.

The problem was, that the queue was refed by QueueState::last and that ref
only gets dropped on a blocking wait. This is problematic as non user
Event objects also hold a ref on the Queue they are created on, therefore
causing a cyclic ref relation.

In order to resolve it, just use a weak reference. A failure of upgrading
the Weak ref is not an issue as in this case we'd only wait on an already
destroyed or processed event. The worker thread already makes sure
everything stays in sync.

Fixes: 5b3ff7e3f3d ("rusticl/queue: overhaul of the queue+event handling")
Signed-off-by: Karol Herbst <kher...@redhat.com>
Reviewed-by: @LingMan <18294-ling...@users.noreply.gitlab.freedesktop.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25926>

---

 src/gallium/frontends/rusticl/core/queue.rs | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/src/gallium/frontends/rusticl/core/queue.rs 
b/src/gallium/frontends/rusticl/core/queue.rs
index 364b4272487..4a4cb223949 100644
--- a/src/gallium/frontends/rusticl/core/queue.rs
+++ b/src/gallium/frontends/rusticl/core/queue.rs
@@ -13,12 +13,13 @@ use std::collections::HashSet;
 use std::sync::mpsc;
 use std::sync::Arc;
 use std::sync::Mutex;
+use std::sync::Weak;
 use std::thread;
 use std::thread::JoinHandle;
 
 struct QueueState {
     pending: Vec<Arc<Event>>,
-    last: Option<Arc<Event>>,
+    last: Weak<Event>,
     // `Sync` on `Sender` was stabilized in 1.72, until then, put it into our 
Mutex.
     // see 
https://github.com/rust-lang/rust/commit/5f56956b3c7edb9801585850d1f41b0aeb1888ff
     chan_in: mpsc::Sender<Vec<Arc<Event>>>,
@@ -62,7 +63,7 @@ impl Queue {
             props_v2: props_v2,
             state: Mutex::new(QueueState {
                 pending: Vec::new(),
-                last: None,
+                last: Weak::new(),
                 chan_in: tx_q,
             }),
             _thrd: thread::Builder::new()
@@ -134,7 +135,7 @@ impl Queue {
         // Update last if and only if we get new events, this prevents 
breaking application code
         // doing things like `clFlush(q); clFinish(q);`
         if let Some(last) = state.pending.last() {
-            state.last = Some(last.clone());
+            state.last = Arc::downgrade(last);
         }
 
         let events = state.pending.drain(0..).collect();
@@ -144,9 +145,10 @@ impl Queue {
             .send(events)
             .map_err(|_| CL_OUT_OF_HOST_MEMORY)?;
         if wait {
-            // Waiting on the last event is good enough here as the queue will 
process it in order,
-            // also take the value so we can release the event once we are done
-            state.last.take().map(|e| e.wait());
+            // Waiting on the last event is good enough here as the queue will 
process it in order
+            // It's not a problem if the weak ref is invalid as that means the 
work is already done
+            // and waiting isn't necessary anymore.
+            state.last.upgrade().map(|e| e.wait());
         }
         Ok(())
     }

Reply via email to