diff options
author | Sebastian Dröge <sebastian@centricular.com> | 2022-09-27 12:22:36 +0300 |
---|---|---|
committer | Sebastian Dröge <sebastian@centricular.com> | 2022-09-27 12:54:21 +0300 |
commit | b6ebad27614287ed122a9080f0c7955b056316b6 (patch) | |
tree | fd3e94fb68ba6140d6859102eddda45e642774a9 /utils | |
parent | adb4cb86918176c34f4942795305a017416f73c7 (diff) |
fallbackswitch: Fix lock order problem between state and stream lock
The order is first stream lock, then state lock. Everything else can
lead to deadlocks.
Diffstat (limited to 'utils')
-rw-r--r-- | utils/fallbackswitch/src/fallbackswitch/imp.rs | 55 |
1 files changed, 37 insertions, 18 deletions
diff --git a/utils/fallbackswitch/src/fallbackswitch/imp.rs b/utils/fallbackswitch/src/fallbackswitch/imp.rs index 8567ac2b1..a75aa32fb 100644 --- a/utils/fallbackswitch/src/fallbackswitch/imp.rs +++ b/utils/fallbackswitch/src/fallbackswitch/imp.rs @@ -759,12 +759,19 @@ impl FallbackSwitch { return Ok(gst::FlowSuccess::Ok); } + // Lock order: First stream lock then state lock! + let _stream_lock = MutexGuard::unlocked(&mut state, || self.src_pad.stream_lock()); + + is_active = self.active_sinkpad.lock().as_ref() == Some(pad); + if !is_active { + log!(CAT, obj: pad, "Dropping {:?} on inactive pad", buffer); + return Ok(gst::FlowSuccess::Ok); + } + let switched_pad = state.switched_pad; let discont_pending = state.discont_pending; state.switched_pad = false; state.discont_pending = false; - - let _stream_lock = self.src_pad.stream_lock(); drop(state); if switched_pad { @@ -855,7 +862,6 @@ impl FallbackSwitch { } let mut state = self.state.lock(); - let forward = self.active_sinkpad.lock().as_ref() == Some(pad); let mut pad_state = pad.imp().state.lock(); @@ -901,30 +907,43 @@ impl FallbackSwitch { _ => {} } - let fwd_sticky = if forward && state.switched_pad && event.is_serialized() { + drop(pad_state); + + let mut is_active = self.active_sinkpad.lock().as_ref() == Some(pad); + if !is_active { + log!(CAT, obj: pad, "Dropping {:?} on inactive pad", event); + return true; + } + + // Lock order: First stream lock then state lock! + let stream_lock_for_serialized = event + .is_serialized() + .then(|| MutexGuard::unlocked(&mut state, || self.src_pad.stream_lock())); + + is_active = self.active_sinkpad.lock().as_ref() == Some(pad); + if !is_active { + log!(CAT, obj: pad, "Dropping {:?} on inactive pad", event); + return true; + } + + let fwd_sticky = if state.switched_pad && stream_lock_for_serialized.is_some() { state.switched_pad = false; true } else { false }; - - drop(pad_state); - let _stream_lock = forward.then(|| self.src_pad.stream_lock()); drop(state); - if forward { - if fwd_sticky { - let _ = pad.push_event(gst::event::Reconfigure::new()); - pad.sticky_events_foreach(|event| { - self.src_pad.push_event(event.clone()); - std::ops::ControlFlow::Continue(gst::EventForeachAction::Keep) - }); + if fwd_sticky { + let _ = pad.push_event(gst::event::Reconfigure::new()); + pad.sticky_events_foreach(|event| { + self.src_pad.push_event(event.clone()); + std::ops::ControlFlow::Continue(gst::EventForeachAction::Keep) + }); - element.notify(PROP_ACTIVE_PAD); - } - self.src_pad.push_event(event); + element.notify(PROP_ACTIVE_PAD); } - true + self.src_pad.push_event(event) } fn sink_query( |