use core::marker::PhantomData;
use core::mem::ManuallyDrop;
pub use crate::arch::TrapHandlerRegs;
use crate::sanitizer;
use crate::unwind::initial_func_abi;
#[cfg(doc)]
use crate::Coroutine; use crate::{arch, util};
use crate::{sanitizer::SanitizerFiber, stack::StackPointer};
#[derive(Clone, Copy)]
pub struct CoroutineTrapHandler<Return> {
pub(crate) stack_base: StackPointer,
pub(crate) stack_limit: StackPointer,
pub(crate) marker: PhantomData<fn(Return)>,
}
impl<Return> CoroutineTrapHandler<Return> {
pub fn stack_ptr_in_bounds(&self, stack_ptr: usize) -> bool {
stack_ptr >= self.stack_limit.get() && stack_ptr < self.stack_base.get()
}
pub unsafe fn setup_trap_handler<F>(&self, f: F) -> TrapHandlerRegs
where
F: FnOnce() -> Return,
F: 'static,
{
initial_func_abi! {
unsafe fn trap_handler<F: FnOnce() -> Return, Return>(
f: *mut F,
parent_link: *mut StackPointer
) -> ! {
#[cfg(windows)]
reset_guard_page();
let result = crate::unwind::catch_unwind_at_root(f.read());
unsafe {
(*SanitizerFiber::from_parent_link(parent_link)).start_switch();
}
let mut result = ManuallyDrop::new(result);
arch::switch_and_reset(util::encode_val(&mut result), parent_link);
}
}
unsafe {
sanitizer::unpoison_stack_range(self.stack_base, self.stack_limit);
}
arch::setup_trap_trampoline(self.stack_base, f, trap_handler::<F, Return>)
}
}
#[cfg(windows)]
fn reset_guard_page() {
extern "C" {
fn _resetstkoflw() -> i32;
}
if unsafe { _resetstkoflw() } == 0 {
panic!("failed to restore stack guard page");
}
}