feat(stack,runtime): per-shape actor stacks — Stack::new(reserve, guard), Config knobs, pool rule (RFC 019 §1)
Stack takes an explicit (reserve, guard) shape, both page-rounded and
stored; usable_base derives from the stored guard. Guard default raised
4 KiB -> 64 KiB (DEFAULT_STACK_GUARD): probestack makes one page enough
for Rust frames, but an unprobed C frame can leap a page in one sub rsp
— the motivating SQLite segfault. Reserve default stays 64 KiB
(DEFAULT_STACK_RESERVE); ACTOR_STACK_SIZE retired.
Config::{stack_reserve, stack_guard} thread the runtime defaults into
RuntimeInner pre-rounded. All acquisition/recycling now goes through
acquire_stack/recycle_stack carrying the pool rule: only default-shaped
stacks are pooled (pooled ⇒ default-shaped by induction); custom shapes
mmap fresh and munmap at death. Pool lock still dropped before any mmap.
No public spawn API change (SpawnOpts is the next commit).
Tests: shape rounding + accessors, wide-guard faults at both ends
(subprocess), Config::stack_reserve permits >64 KiB recursion that
previously could only segfault.
This commit is contained in:
+4
-9
@@ -288,15 +288,10 @@ pub fn spawn(f: impl FnOnce() + Send + 'static) -> JoinHandle {
|
||||
/// rather than its true caller.
|
||||
pub fn spawn_under<A>(supervisor: Pid<A>, f: impl FnOnce() + Send + 'static) -> JoinHandle {
|
||||
let supervisor = supervisor.erase();
|
||||
// Stack + closure boxing happen before ANY runtime lock is taken: no
|
||||
// syscall and no allocation ever stalls another scheduler thread.
|
||||
let stack = with_runtime(|inner| inner.stack_pool.lock().pop())
|
||||
.unwrap_or_else(|| {
|
||||
match crate::stack::Stack::new(crate::runtime::ACTOR_STACK_SIZE) {
|
||||
Ok(stack) => stack,
|
||||
Err(e) => panic!("stack allocation failed: {e}"),
|
||||
}
|
||||
});
|
||||
// Stack + closure boxing happen before the slot locks are taken; the
|
||||
// pool lock inside acquire_stack is dropped before any mmap, so no
|
||||
// syscall ever stalls another scheduler thread.
|
||||
let stack = with_runtime(|inner| crate::runtime::acquire_stack(inner, None));
|
||||
let sp = init_actor_stack(stack.top(), crate::actor::trampoline);
|
||||
let closure: crate::runtime::Closure = Box::new(f);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user