use core::num::NonZeroUsize;
use crate::sanitizer::SanitizerFiber;
pub mod valgrind;
cfg_if::cfg_if! {
if #[cfg(all(feature = "default-stack", unix))] {
mod unix;
pub use self::unix::DefaultStack;
} else if #[cfg(all(feature = "default-stack", windows))] {
mod windows;
pub use self::windows::DefaultStack;
}
}
pub type StackPointer = NonZeroUsize;
pub const STACK_ALIGNMENT: usize = crate::arch::STACK_ALIGNMENT;
pub const MIN_STACK_SIZE: usize = 4096;
pub unsafe trait Stack {
fn base(&self) -> StackPointer;
fn limit(&self) -> StackPointer;
#[cfg(windows)]
fn teb_fields(&self) -> StackTebFields;
#[cfg(windows)]
fn update_teb_fields(&mut self, stack_limit: usize, guaranteed_stack_bytes: usize);
#[doc(hidden)]
#[inline]
fn sanitizer_fiber(&self) -> SanitizerFiber {
SanitizerFiber {
#[cfg(feature = "sanitizer")]
bottom: self.limit().get() as *const u8,
#[cfg(feature = "sanitizer")]
size: self.base().get() - self.limit().get(),
}
}
}
#[cfg(windows)]
#[derive(Clone, Copy, Debug)]
#[allow(non_snake_case)]
#[allow(missing_docs)]
pub struct StackTebFields {
pub StackBase: usize,
pub StackLimit: usize,
pub DeallocationStack: usize,
pub GuaranteedStackBytes: usize,
}
unsafe impl<'a, S: Stack> Stack for &'a mut S {
#[inline]
fn base(&self) -> StackPointer {
(**self).base()
}
#[inline]
fn limit(&self) -> StackPointer {
(**self).limit()
}
#[inline]
#[cfg(windows)]
fn teb_fields(&self) -> StackTebFields {
(**self).teb_fields()
}
#[inline]
#[cfg(windows)]
fn update_teb_fields(&mut self, stack_limit: usize, guaranteed_stack_bytes: usize) {
(**self).update_teb_fields(stack_limit, guaranteed_stack_bytes)
}
}
#[test]
fn assert_send_sync() {
fn send<T: Send>() {}
fn sync<T: Sync>() {}
send::<DefaultStack>();
sync::<DefaultStack>();
}