Complete rewrite with improved architecture & correctness: - src/runtime.rs: Simplified task scheduling with proper state transitions - src/scheduler.rs: Decoupled from runtime, pure task queue logic - src/io.rs, src/mutex.rs: Refactored for clarity & performance - New actor model framework (src/actor.rs, src/context.rs) - Channel primitives (src/channel.rs) & process IDs (src/pid.rs) - Preemption framework (src/preempt.rs) for fair timeslicing - Expanded benchmarks & tests (multi_scheduler, primes, runtime)
90 lines
2.5 KiB
Rust
90 lines
2.5 KiB
Rust
//! mmap-based growable stack with a guard page below.
|
|
//!
|
|
//! Layout (low → high address):
|
|
//! [ guard page (PROT_NONE) | stack region ]
|
|
//! ^ top() — initial stack pointer
|
|
//!
|
|
//! Stacks grow downward. Overflow lands in the guard page → SIGSEGV.
|
|
|
|
use std::io;
|
|
|
|
pub struct Stack {
|
|
/// Bottom of the entire mmap'd region (start of guard page).
|
|
base: *mut u8,
|
|
/// Total mmap'd size: guard_size + stack_size.
|
|
total_size: usize,
|
|
/// Usable stack size (excluding guard page).
|
|
stack_size: usize,
|
|
}
|
|
|
|
// Stack owns its memory; safe to send across threads.
|
|
unsafe impl Send for Stack {}
|
|
|
|
impl Stack {
|
|
/// Allocate a new stack. `stack_size` is the usable region; one page is
|
|
/// added below as a guard page. Both are rounded up to the page size.
|
|
pub fn new(stack_size: usize) -> io::Result<Self> {
|
|
let page = page_size();
|
|
let stack_size = round_up(stack_size, page);
|
|
let guard_size = page;
|
|
let total_size = guard_size + stack_size;
|
|
|
|
let base = unsafe {
|
|
libc::mmap(
|
|
std::ptr::null_mut(),
|
|
total_size,
|
|
libc::PROT_READ | libc::PROT_WRITE,
|
|
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
|
|
-1,
|
|
0,
|
|
)
|
|
};
|
|
if base == libc::MAP_FAILED {
|
|
return Err(io::Error::last_os_error());
|
|
}
|
|
let base = base as *mut u8;
|
|
|
|
let ret = unsafe {
|
|
libc::mprotect(base as *mut libc::c_void, guard_size, libc::PROT_NONE)
|
|
};
|
|
if ret != 0 {
|
|
let err = io::Error::last_os_error();
|
|
unsafe { libc::munmap(base as *mut libc::c_void, total_size) };
|
|
return Err(err);
|
|
}
|
|
|
|
Ok(Self { base, total_size, stack_size })
|
|
}
|
|
|
|
/// 16-byte-aligned top of the usable region.
|
|
pub fn top(&self) -> *mut u8 {
|
|
let raw_top = self.base as usize + self.total_size;
|
|
(raw_top & !15) as *mut u8
|
|
}
|
|
|
|
/// Pointer to the bottom of the usable region (just above the guard page).
|
|
pub fn usable_base(&self) -> *mut u8 {
|
|
unsafe { self.base.add(page_size()) }
|
|
}
|
|
|
|
pub fn stack_size(&self) -> usize {
|
|
self.stack_size
|
|
}
|
|
}
|
|
|
|
impl Drop for Stack {
|
|
fn drop(&mut self) {
|
|
unsafe {
|
|
libc::munmap(self.base as *mut libc::c_void, self.total_size);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn page_size() -> usize {
|
|
unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }
|
|
}
|
|
|
|
fn round_up(n: usize, align: usize) -> usize {
|
|
(n + align - 1) & !(align - 1)
|
|
}
|