use crate::rt::{guard, ContextStack};
use crate::yield_::yield_now;
use libc::{sigaction, sighandler_t, SA_ONSTACK, SA_SIGINFO, SIGBUS, SIGSEGV};
use std::mem;
use std::mem::MaybeUninit;
use std::ptr::null_mut;
use std::sync::Once;
static mut SIG_ACTION: MaybeUninit<sigaction> = MaybeUninit::uninit();
unsafe extern "C" fn signal_handler(
signum: libc::c_int,
info: *mut libc::siginfo_t,
ctx: *mut libc::ucontext_t,
) {
let _ctx = &mut *ctx;
let addr = (*info).si_addr() as usize;
let stack_guard = guard::current();
if !stack_guard.contains(&addr) {
println!("{}", std::backtrace::Backtrace::force_capture());
sigaction(signum, SIG_ACTION.assume_init_ref(), null_mut());
return;
}
eprintln!(
"\ncoroutine in thread '{}' has overflowed its stack\n",
std::thread::current().name().unwrap_or("<unknown>")
);
ContextStack::current().top().err = Some(Box::new(crate::Error::StackErr));
let mut sigset: libc::sigset_t = mem::zeroed();
libc::sigemptyset(&mut sigset);
libc::sigaddset(&mut sigset, signum);
libc::sigprocmask(libc::SIG_UNBLOCK, &sigset, null_mut());
yield_now();
std::process::abort();
}
#[cold]
unsafe fn init() {
let mut action: sigaction = mem::zeroed();
action.sa_flags = SA_SIGINFO | SA_ONSTACK;
action.sa_sigaction = signal_handler as sighandler_t;
for signal in [SIGSEGV, SIGBUS] {
sigaction(signal, &action, SIG_ACTION.as_mut_ptr());
}
}
pub fn init_once() {
static INIT_ONCE: Once = Once::new();
INIT_ONCE.call_once(|| unsafe {
init();
})
}