riot_wrappers/
panic.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#[panic_handler]
fn panic(info: &::core::panic::PanicInfo) -> ! {
    use crate::thread;

    let os_can_continue = !cfg!(feature = "panic_handler_crash")
        && crate::thread::InThread::new()
            // Panics with IRQs off are fatal because we can't safely re-enable them
            .map(|i| i.irq_is_enabled())
            // Panics in ISRs are always fatal because continuing in threads would signal to the
            // remaining system that the ISR terminated
            .unwrap_or(false);

    if !os_can_continue {
        // We can't abort on stable -- but even if we could: Set a breakpoint and wait for the
        // fault handler to reboot us of no debugger is attached? Spin endlessly? core_panic should
        // already answer all these questions.

        // Not attempting to print -- it would only get through on devices where stdio is provided
        // by a UART, and with these the debugger is usually also close enough that the risk of
        // smashing things by overflowing the ISR stack outweighs the benefits.

        unsafe {
            riot_sys::core_panic(
                riot_sys::core_panic_t_PANIC_GENERAL_ERROR,
                c"RUST PANIC".as_ptr() as _,
            )
        };
    } else {
        // I *guess* it's OK for a panic to simply make a thread into a zombie -- this does allow other
        // threads (including spawned Rust threads) to continue, but my layman's understanding of
        // panicking is that that's OK because whatever we were just mutating can simply never be used
        // by someone else ever again.

        let me = thread::get_pid();

        if cfg!(feature = "panic_handler_format") {
            use crate::stdio::println;

            println!(
                "Error in thread {:?} ({}):",
                me,
                me.get_name().unwrap_or("unnamed")
            );
            println!("{}", info);
        } else {
            let mut stdio = crate::stdio::Stdio {};
            use core::fmt::Write;
            let _ = stdio.write_str("Panic in thread ");
            let _ = stdio.write_str(me.get_name().unwrap_or("unnamed"));
            let _ = stdio.write_str("!\n");
        }

        // Not trying any unwinding -- this thread is just dead, won't be re-claimed, any mutexes it
        // holds are just held indefinitely rather than throwing poison errors.
        loop {
            thread::sleep();
        }
    }
}

// We could make this conditional also on panic="abort" and thus enable stable compilation when
// that flag is enabled -- but then again https://github.com/rust-lang/rust/issues/77443 is not
// stable yet so it's kind of moot (and I don't want to introduce yet another crate feature that'll
// largely be untested).
#[cfg(all(target_arch = "x86", not(panic = "abort")))]
#[lang = "eh_personality"]
fn rust_eh_personality() {
    loop {}
}