From 6c48caecab7f023100c7b09b7079176bf7d18d9e Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 22 May 2026 05:15:12 +0000 Subject: [PATCH] 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. --- src/preempt.rs | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/preempt.rs b/src/preempt.rs index 6adb9dd..a99cc70 100644 --- a/src/preempt.rs +++ b/src/preempt.rs @@ -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 {