preempt: pub maybe_preempt for shared counter across event sources
v0.2 will add stack-frame entries as a second preemption event source. Both routes share ALLOC_COUNT so the timeslice check rate is the same whether the actor is alloc-heavy, frame-heavy, or mixed.
This commit is contained in:
@@ -1,8 +1,15 @@
|
||||
//! Allocator-driven preemption.
|
||||
//! Preemption hooks.
|
||||
//!
|
||||
//! A `GlobalAlloc` wrapper counts allocations. Every `ALLOC_INTERVAL`-th
|
||||
//! allocation it reads RDTSC and, if the actor's timeslice has expired,
|
||||
//! calls `switch_to_scheduler` to yield.
|
||||
//! Preemption is event-driven: every preemption event decrements a
|
||||
//! thread-local counter (`ALLOC_COUNT`). When the counter hits zero, we
|
||||
//! read RDTSC and, if the actor's timeslice has expired, call
|
||||
//! `switch_to_scheduler` to yield. Resetting the counter to `ALLOC_INTERVAL`
|
||||
//! amortises the RDTSC across many cheap events.
|
||||
//!
|
||||
//! Events today are heap allocations (via `PreemptingAllocator`). v0.2 will
|
||||
//! add stack-frame entries as a second event source — frames are stack
|
||||
//! allocations, the counter naming still fits — sharing this same counter
|
||||
//! so both routes behave consistently.
|
||||
//!
|
||||
//! All state is thread-local. The scheduler enables preemption on resume
|
||||
//! and disables it on the return path, so the scheduler can never preempt
|
||||
@@ -72,8 +79,12 @@ unsafe impl GlobalAlloc for PreemptingAllocator {
|
||||
}
|
||||
}
|
||||
|
||||
/// Shared preemption check. Called by every preemption event source — the
|
||||
/// heap allocator today, the stack-frame entry hook in v0.2. Decrements
|
||||
/// `ALLOC_COUNT`; every `ALLOC_INTERVAL` calls reads the timeslice clock
|
||||
/// and yields if expired.
|
||||
#[inline(always)]
|
||||
fn maybe_preempt() {
|
||||
pub fn maybe_preempt() {
|
||||
ALLOC_COUNT.with(|c| {
|
||||
let n = c.get();
|
||||
if n == 0 {
|
||||
|
||||
Reference in New Issue
Block a user