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::{Mutex, Once};
static SIG_ACTION: Mutex<MaybeUninit<sigaction>> = Mutex::new(MaybeUninit::uninit());
unsafe extern "C" fn signal_handler(
signum: libc::c_int,
info: *mut libc::siginfo_t,
ctx: *mut libc::c_void, ) {
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());
let old_action = SIG_ACTION.lock().unwrap();
sigaction(signum, old_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;
let mut old_action = SIG_ACTION.lock().unwrap();
for signal in [SIGSEGV, SIGBUS] {
sigaction(signal, &action, old_action.assume_init_mut());
}
}
pub fn init_once() {
static INIT_ONCE: Once = Once::new();
INIT_ONCE.call_once(|| unsafe {
init();
})
}