preempt: explicit check!() macro for no-alloc loops
Stable Rust emits stack probes inline (subq/movq/jne loop) rather than calling __rust_probestack, so there's no transparent hook for stack- frame preemption. Override of __rust_probestack links cleanly but never runs. Falling back to an explicit check!() that users drop into hot compute loops. check!() decrements the same ALLOC_COUNT counter as the heap path, so both event sources fire timeslice checks at the same rate. Documents the prep-to-park invariant on maybe_preempt — library code that registers a wakeup and then parks must keep that window alloc-free and check-free, or a preemption-driven yield in the middle would lose the wakeup.
This commit is contained in:
22
src/lib.rs
22
src/lib.rs
@@ -42,3 +42,25 @@ pub use scheduler::{
|
||||
block_on_io, run, self_pid, sleep, spawn, spawn_under, yield_now, JoinError, JoinHandle,
|
||||
};
|
||||
pub use supervisor::Signal;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// check!() — explicit preemption point for tight no-alloc loops.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Voluntarily check whether this actor's timeslice has expired, yielding
|
||||
/// if so. Drop this into hot compute loops that don't allocate (heap or
|
||||
/// large stack frames) — without it, such loops monopolise the scheduler
|
||||
/// until they return.
|
||||
///
|
||||
/// Decrements the same per-actor event counter as the heap allocator's
|
||||
/// preemption hook, so the check rate is identical regardless of whether
|
||||
/// the actor is alloc-heavy, check-heavy, or mixed.
|
||||
///
|
||||
/// No-op outside an actor (the runtime's `PREEMPTION_ENABLED` flag is
|
||||
/// false there).
|
||||
#[macro_export]
|
||||
macro_rules! check {
|
||||
() => {
|
||||
$crate::preempt::maybe_preempt()
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user