Browse Source

Make `set_panic_hook` into a safe fn

pull/162/head
Fenrir 10 months ago
parent
commit
a67c8c0bf6
  1. 43
      ctru-rs/src/applets/error.rs
  2. 2
      ctru-rs/src/services/gfx.rs

43
ctru-rs/src/applets/error.rs

@ -91,31 +91,50 @@ impl PopUp {
/// Sets a custom panic hook that uses the error applet to display panic messages. You can also choose to have /// Sets a custom panic hook that uses the error applet to display panic messages. You can also choose to have
/// messages printed over stderr along with the pop-up display. /// messages printed over stderr along with the pop-up display.
/// ///
/// # Safety /// If the `Gfx` service is not initialized during a panic, the error applet will not be displayed and the panic
/// /// message will be printed over stderr.
/// The error applet requires that both the [`Apt`] and [`Gfx`] services are active whenever it launches. pub fn set_panic_hook(use_stderr: bool) {
/// By calling this function, you promise that you will keep those services alive until either the program ends or use crate::services::gfx::GFX_ACTIVE;
/// you unregister this hook with [`std::panic::take_hook`](https://doc.rust-lang.org/std/panic/fn.take_hook.html).
pub unsafe fn set_panic_hook(use_stderr: bool) { use std::io::Write;
use std::sync::TryLockError;
std::panic::set_hook(Box::new(move |panic_info| { std::panic::set_hook(Box::new(move |panic_info| {
let mut popup = PopUp::new(Kind::Top); let _apt = Apt::new();
let thread = std::thread::current(); let thread = std::thread::current();
let name = thread.name().unwrap_or("<unnamed>"); let name = thread.name().unwrap_or("<unnamed>");
// If we get a `WouldBlock` error, we know that the `Gfx` service has been initialized.
// Otherwise fallback to printing over stderr.
match GFX_ACTIVE.try_lock() {
Err(TryLockError::WouldBlock) => {
if use_stderr {
print_to_stderr(name, panic_info);
}
let payload = format!("thread '{name}' {panic_info}"); let payload = format!("thread '{name}' {panic_info}");
popup.set_text(&payload); let mut popup = PopUp::new(Kind::Top);
if use_stderr { popup.set_text(&payload);
eprintln!("{payload}");
}
unsafe { unsafe {
popup.launch_unchecked(); popup.launch_unchecked();
} }
})) }
_ => {
print_to_stderr(name, panic_info);
}
}
}));
fn print_to_stderr(name: &str, panic_info: &std::panic::PanicInfo) {
let mut stderr = std::io::stderr().lock();
let _ = writeln!(stderr, "thread '{name}' {panic_info}");
}
} }
impl std::fmt::Display for Error { impl std::fmt::Display for Error {

2
ctru-rs/src/services/gfx.rs

@ -239,7 +239,7 @@ pub struct Gfx {
_service_handler: ServiceReference, _service_handler: ServiceReference,
} }
static GFX_ACTIVE: Mutex<()> = Mutex::new(()); pub(crate) static GFX_ACTIVE: Mutex<()> = Mutex::new(());
impl Gfx { impl Gfx {
/// Initialize a new default service handle. /// Initialize a new default service handle.

Loading…
Cancel
Save