gstreamer: Reduce code bloat in panic handling

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1191>
This commit is contained in:
Sebastian Dröge 2023-01-16 10:17:29 +02:00
parent 3a340d0a89
commit 3e2eb6e652
7 changed files with 100 additions and 81 deletions

View file

@ -135,24 +135,13 @@ impl AppSinkCallbacksBuilder {
}
}
fn post_panic_error_message(element: &AppSink, err: &dyn std::any::Any) {
skip_assert_initialized!();
if let Some(cause) = err.downcast_ref::<&str>() {
gst::element_error!(element, gst::LibraryError::Failed, ["Panicked: {}", cause]);
} else if let Some(cause) = err.downcast_ref::<String>() {
gst::element_error!(element, gst::LibraryError::Failed, ["Panicked: {}", cause]);
} else {
gst::element_error!(element, gst::LibraryError::Failed, ["Panicked"]);
}
}
unsafe extern "C" fn trampoline_eos(appsink: *mut ffi::GstAppSink, callbacks: gpointer) {
let callbacks = callbacks as *mut AppSinkCallbacks;
let element: Borrowed<AppSink> = from_glib_borrow(appsink);
if (*callbacks).panicked.load(Ordering::Relaxed) {
let element: Borrowed<AppSink> = from_glib_borrow(appsink);
gst::element_error!(element, gst::LibraryError::Failed, ["Panicked"]);
gst::subclass::post_panic_error_message(element.upcast_ref(), element.upcast_ref(), None);
return;
}
@ -162,7 +151,11 @@ unsafe extern "C" fn trampoline_eos(appsink: *mut ffi::GstAppSink, callbacks: gp
Ok(result) => result,
Err(err) => {
(*callbacks).panicked.store(true, Ordering::Relaxed);
post_panic_error_message(&element, &err);
gst::subclass::post_panic_error_message(
element.upcast_ref(),
element.upcast_ref(),
Some(err),
);
}
}
}
@ -177,7 +170,7 @@ unsafe extern "C" fn trampoline_new_preroll(
if (*callbacks).panicked.load(Ordering::Relaxed) {
let element: Borrowed<AppSink> = from_glib_borrow(appsink);
gst::element_error!(element, gst::LibraryError::Failed, ["Panicked"]);
gst::subclass::post_panic_error_message(element.upcast_ref(), element.upcast_ref(), None);
return gst::FlowReturn::Error.into_glib();
}
@ -187,7 +180,11 @@ unsafe extern "C" fn trampoline_new_preroll(
Ok(result) => result,
Err(err) => {
(*callbacks).panicked.store(true, Ordering::Relaxed);
post_panic_error_message(&element, &err);
gst::subclass::post_panic_error_message(
element.upcast_ref(),
element.upcast_ref(),
Some(err),
);
gst::FlowReturn::Error
}
@ -208,7 +205,7 @@ unsafe extern "C" fn trampoline_new_sample(
if (*callbacks).panicked.load(Ordering::Relaxed) {
let element: Borrowed<AppSink> = from_glib_borrow(appsink);
gst::element_error!(element, gst::LibraryError::Failed, ["Panicked"]);
gst::subclass::post_panic_error_message(element.upcast_ref(), element.upcast_ref(), None);
return gst::FlowReturn::Error.into_glib();
}
@ -218,7 +215,11 @@ unsafe extern "C" fn trampoline_new_sample(
Ok(result) => result,
Err(err) => {
(*callbacks).panicked.store(true, Ordering::Relaxed);
post_panic_error_message(&element, &err);
gst::subclass::post_panic_error_message(
element.upcast_ref(),
element.upcast_ref(),
Some(err),
);
gst::FlowReturn::Error
}
@ -239,7 +240,7 @@ unsafe extern "C" fn trampoline_new_event(
if (*callbacks).panicked.load(Ordering::Relaxed) {
let element: Borrowed<AppSink> = from_glib_borrow(appsink);
gst::element_error!(element, gst::LibraryError::Failed, ["Panicked"]);
gst::subclass::post_panic_error_message(element.upcast_ref(), element.upcast_ref(), None);
return false.into_glib();
}
@ -249,7 +250,11 @@ unsafe extern "C" fn trampoline_new_event(
Ok(result) => result,
Err(err) => {
(*callbacks).panicked.store(true, Ordering::Relaxed);
post_panic_error_message(&element, &err);
gst::subclass::post_panic_error_message(
element.upcast_ref(),
element.upcast_ref(),
Some(err),
);
false
}

View file

@ -115,17 +115,6 @@ impl AppSrcCallbacksBuilder {
}
}
fn post_panic_error_message(element: &AppSrc, err: &dyn std::any::Any) {
skip_assert_initialized!();
if let Some(cause) = err.downcast_ref::<&str>() {
gst::element_error!(element, gst::LibraryError::Failed, ["Panicked: {}", cause]);
} else if let Some(cause) = err.downcast_ref::<String>() {
gst::element_error!(element, gst::LibraryError::Failed, ["Panicked: {}", cause]);
} else {
gst::element_error!(element, gst::LibraryError::Failed, ["Panicked"]);
}
}
unsafe extern "C" fn trampoline_need_data(
appsrc: *mut ffi::GstAppSrc,
length: u32,
@ -136,7 +125,7 @@ unsafe extern "C" fn trampoline_need_data(
if (*callbacks).panicked.load(Ordering::Relaxed) {
let element: Borrowed<AppSrc> = from_glib_borrow(appsrc);
gst::element_error!(element, gst::LibraryError::Failed, ["Panicked"]);
gst::subclass::post_panic_error_message(element.upcast_ref(), element.upcast_ref(), None);
return;
}
@ -146,7 +135,11 @@ unsafe extern "C" fn trampoline_need_data(
Ok(result) => result,
Err(err) => {
(*callbacks).panicked.store(true, Ordering::Relaxed);
post_panic_error_message(&element, &err);
gst::subclass::post_panic_error_message(
element.upcast_ref(),
element.upcast_ref(),
Some(err),
);
}
}
}
@ -158,7 +151,7 @@ unsafe extern "C" fn trampoline_enough_data(appsrc: *mut ffi::GstAppSrc, callbac
if (*callbacks).panicked.load(Ordering::Relaxed) {
let element: Borrowed<AppSrc> = from_glib_borrow(appsrc);
gst::element_error!(element, gst::LibraryError::Failed, ["Panicked"]);
gst::subclass::post_panic_error_message(element.upcast_ref(), element.upcast_ref(), None);
return;
}
@ -168,7 +161,11 @@ unsafe extern "C" fn trampoline_enough_data(appsrc: *mut ffi::GstAppSrc, callbac
Ok(result) => result,
Err(err) => {
(*callbacks).panicked.store(true, Ordering::Relaxed);
post_panic_error_message(&element, &err);
gst::subclass::post_panic_error_message(
element.upcast_ref(),
element.upcast_ref(),
Some(err),
);
}
}
}
@ -184,7 +181,7 @@ unsafe extern "C" fn trampoline_seek_data(
if (*callbacks).panicked.load(Ordering::Relaxed) {
let element: Borrowed<AppSrc> = from_glib_borrow(appsrc);
gst::element_error!(element, gst::LibraryError::Failed, ["Panicked"]);
gst::subclass::post_panic_error_message(element.upcast_ref(), element.upcast_ref(), None);
return false.into_glib();
}
@ -194,7 +191,11 @@ unsafe extern "C" fn trampoline_seek_data(
Ok(result) => result,
Err(err) => {
(*callbacks).panicked.store(true, Ordering::Relaxed);
post_panic_error_message(&element, &err);
gst::subclass::post_panic_error_message(
element.upcast_ref(),
element.upcast_ref(),
Some(err),
);
false
}

View file

@ -667,26 +667,11 @@ impl<O: IsA<Pad>> PadExtManual for O {
None => panic::resume_unwind(err),
};
let maybe_couldnt_stop = if pad.pause_task().is_err() {
", could not stop task"
} else {
""
};
let cause = if let Some(cause) = err.downcast_ref::<&str>() {
cause
} else if let Some(cause) = err.downcast_ref::<String>() {
cause
} else {
"Panicked"
};
let _ = element.post_message(
crate::message::Error::builder(
crate::LibraryError::Failed,
&format!("Panicked: {}{}", cause, maybe_couldnt_stop),
)
.src(&*pad)
.build(),
);
if pad.pause_task().is_err() {
crate::error!(crate::CAT_RUST, "could not stop pad task on panic");
}
crate::subclass::post_panic_error_message(&element, pad.upcast_ref(), Some(err));
}
}

View file

@ -319,6 +319,7 @@ impl<T: ElementImpl> ElementImplExt for T {
}
}
#[inline(never)]
fn panicked(&self) -> &atomic::AtomicBool {
self.instance_data::<atomic::AtomicBool>(crate::Element::static_type())
.expect("instance not initialized correctly")

View file

@ -2,33 +2,61 @@
use thiserror::Error;
use crate::{ErrorMessage, FlowReturn};
use crate::{prelude::ElementExt, ErrorMessage, FlowReturn};
#[doc(hidden)]
#[inline(never)]
pub fn post_panic_error_message(
element: &crate::Element,
src: &crate::Object,
panic: Option<Box<dyn std::any::Any + Send + 'static>>,
) {
let cause = panic.as_ref().and_then(|err| {
err.downcast_ref::<&str>()
.copied()
.or_else(|| err.downcast_ref::<String>().map(|s| s.as_str()))
});
let msg = if let Some(cause) = cause {
crate::message::Error::builder(crate::LibraryError::Failed, &format!("Panicked: {}", cause))
.src(src)
.build()
} else {
crate::message::Error::builder(crate::LibraryError::Failed, "Panicked")
.src(src)
.build()
};
let _ = element.post_message(msg);
}
#[macro_export]
macro_rules! panic_to_error(
($imp:expr, $ret:expr, $code:block) => {{
use std::panic::{self, AssertUnwindSafe};
use std::sync::atomic::Ordering;
#[allow(clippy::unused_unit)]
{
if $imp.panicked().load(Ordering::Relaxed) {
$imp.post_error_message($crate::error_msg!($crate::LibraryError::Failed, ["Panicked"]));
let panicked = $imp.panicked();
let element = $crate::glib::subclass::types::ObjectSubclassExt::obj($imp);
let element = unsafe { $crate::glib::Cast::unsafe_cast_ref::<$crate::Element>(element.as_ref()) };
if panicked.load(std::sync::atomic::Ordering::Relaxed) {
$crate::subclass::post_panic_error_message(
element,
$crate::glib::Cast::upcast_ref::<$crate::Object>(element),
None,
);
$ret
} else {
let result = panic::catch_unwind(AssertUnwindSafe(|| $code));
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| $code));
match result {
Ok(result) => result,
Err(err) => {
$imp.panicked().store(true, Ordering::Relaxed);
if let Some(cause) = err.downcast_ref::<&str>() {
$imp.post_error_message($crate::error_msg!($crate::LibraryError::Failed, ["Panicked: {}", cause]));
} else if let Some(cause) = err.downcast_ref::<String>() {
$imp.post_error_message($crate::error_msg!($crate::LibraryError::Failed, ["Panicked: {}", cause]));
} else {
$imp.post_error_message($crate::error_msg!($crate::LibraryError::Failed, ["Panicked"]));
}
panicked.store(true, std::sync::atomic::Ordering::Relaxed);
$crate::subclass::post_panic_error_message(
element,
$crate::glib::Cast::upcast_ref::<$crate::Object>(element),
Some(err),
);
$ret
}
}

View file

@ -34,7 +34,7 @@ mod uri_handler;
pub use self::{
device_provider::DeviceProviderMetadata,
element::ElementMetadata,
error::FlowError,
error::{post_panic_error_message, FlowError},
plugin::{MAJOR_VERSION, MINOR_VERSION},
task_pool::TaskPoolFunction,
};

View file

@ -100,24 +100,23 @@ macro_rules! plugin_define(
#[allow(clippy::missing_safety_doc)]
unsafe extern "C" fn plugin_init_trampoline(plugin: *mut $crate::ffi::GstPlugin) -> $crate::glib::ffi::gboolean {
use std::panic::{self, AssertUnwindSafe};
let panic_result = std::panic::catch_unwind(
std::panic::AssertUnwindSafe(|| super::$plugin_init(&$crate::glib::translate::from_glib_borrow(plugin)))
);
let panic_result = panic::catch_unwind(AssertUnwindSafe(|| super::$plugin_init(&$crate::glib::translate::from_glib_borrow(plugin))));
match panic_result {
Ok(register_result) => match register_result {
Ok(_) => $crate::glib::ffi::GTRUE,
Err(err) => {
let cat = $crate::DebugCategory::get("GST_PLUGIN_LOADING").unwrap();
$crate::error!(cat, "Failed to register plugin: {}", err);
$crate::error!($crate::CAT_PLUGIN_LOADING, "Failed to register plugin: {}", err);
$crate::glib::ffi::GFALSE
}
}
Err(err) => {
let cat = $crate::DebugCategory::get("GST_PLUGIN_LOADING").unwrap();
if let Some(cause) = err.downcast_ref::<&str>() {
$crate::error!(cat, "Failed to initialize plugin due to panic: {}", cause);
} else if let Some(cause) = err.downcast_ref::<String>() {
$crate::error!(cat, "Failed to initialize plugin due to panic: {}", cause);
let cause = err.downcast_ref::<&str>().copied()
.or_else(|| err.downcast_ref::<String>().map(|s| s.as_str()));
if let Some(cause) = cause {
$crate::error!($crate::PLUGIN_LOADING, "Failed to initialize plugin due to panic: {}", cause);
} else {
$crate::error!(cat, "Failed to initialize plugin due to panic");
}