rtprecv: fix race condition on first buffer

When an incoming buffer is received, a deadlock can occur if:

1. 1st buffer is currently being handled by the src pad's task
   => holds semaphore.
2. 1st buffer reaches downstream AudioDecoder => Latency query.
3. src pad's task still holding semaphore while relaying Latency query.
4. `src_query()` calls `Pad::default()` which calls `iterate_internal_links()`.
5. `iterate_internal_links()` tries to acquire the `state` `Mutex` which is
   already locked  by `handle_push_jitterbuffer()`.

This commit temporarily releases the `state` `Mutex` until the semaphore is
acquired.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/2466>
This commit is contained in:
François Laignel 2025-08-13 18:45:38 +02:00 committed by GStreamer Marge Bot
parent e4e14cf5ca
commit 8ec5d0995f

View file

@ -1201,9 +1201,18 @@ impl RtpRecv {
// FIXME: Should block if too many packets are stored here because the source pad task
// is blocked
// Make sure not to deadlock, e.g.:
// 1. 1st buffer is currently being handled by the src pad's task => holds semaphore.
// 2. 1st buffer reaches downstream AudioDecoder => Latency query.
// 3. src pad's task still holding semaphore while relaying Latency query.
// 4. `src_query()` calls `Pad::default()` which calls `iterate_internal_links()`.
// 5. `iterate_internal_links()` tries to acquire the `state` `Mutex`.
// => deadlock.
drop(state);
let _src_pad_permit = rtpbin2::get_or_init_runtime()
.expect("initialized in change_state()")
.block_on(buffer.recv_src_pad.semaphore.acquire());
state = self.state.lock().unwrap();
let mut jb_store = buffer.recv_src_pad.jitter_buffer_store.lock().unwrap();