pub struct ResumeDriver;Expand description
Drives CompiledProcess::resume() calls (scheduler.md §5): start
(SC-059), resume_for (SC-060/SC-061), and fork/join orchestration
(handle_fork/on_child_done, Resolved design decision D1). See this
module’s doc comment for scope and the SC-061 fix resume_for embodies.
Implementations§
Source§impl ResumeDriver
impl ResumeDriver
Sourcepub fn resume_for(
&self,
table: &ProcessTable,
proc: ProcessId,
arg: ResumeArg,
state: SimHandle,
ops: &dyn SchedulerOps,
) -> Result<Suspend, ResumeError>
pub fn resume_for( &self, table: &ProcessTable, proc: ProcessId, arg: ResumeArg, state: SimHandle, ops: &dyn SchedulerOps, ) -> Result<Suspend, ResumeError>
SC-061: “the scheduler must never call resume() concurrently on the same ProcessId; one process activation is the atomicity unit.” See this module’s doc comment for the fix this method embodies.
Sourcepub fn start(
&self,
table: &ProcessTable,
proc: ProcessId,
state: SimHandle,
ops: &dyn SchedulerOps,
) -> Result<Suspend, ResumeError>
pub fn start( &self, table: &ProcessTable, proc: ProcessId, state: SimHandle, ops: &dyn SchedulerOps, ) -> Result<Suspend, ResumeError>
SC-059: “the scheduler must call resume(Start) exactly once to begin
each registered process.” The once-only guarantee is
ProcessDescriptor::started’s AtomicBool CAS: a losing
compare_exchange (already true) is rejected with
Err(ResumeError::AlreadyStarted(proc)) before compiled’s lock is
even acquired, so a second start call never reaches resume() at
all — never a panic, matching resume_for’s typed-error style for the
same reason (misuse rejection, not exhaustive-match fallback, but the
same no-silent-no-op posture).
Sourcepub fn handle_fork(
&self,
table: &mut ProcessTable,
parent: ProcessId,
kind: JoinKind,
spawns: &[SpawnSpec],
mint_child: &mut dyn FnMut(&SpawnSpec) -> Box<dyn CompiledProcess>,
) -> Vec<ProcessId> ⓘ
pub fn handle_fork( &self, table: &mut ProcessTable, parent: ProcessId, kind: JoinKind, spawns: &[SpawnSpec], mint_child: &mut dyn FnMut(&SpawnSpec) -> Box<dyn CompiledProcess>, ) -> Vec<ProcessId> ⓘ
Fork/join per Resolved design decision D1 (docs/CONTRACTS.md), using
D1a’s v1 sched-internal shadow bookkeeping on ProcessDescriptor
(fork_join_kind/fork_remaining/fork_any_signaled, plain fields —
not process::ForkFrame, which sched does not own/construct this
wave). Registers one child per SpawnSpec via ProcessTable::register
(mint_child stands in for “codegen emits each branch as its own
process-table kernel”), writes each new child’s own
ProcessDescriptor::fork_parent = Some(parent) (LRM 9.3.2 — this is
handle_fork’s one and only writer of fork_parent), and sets the
parent’s fork_children/fork_join_kind/fork_remaining/
fork_any_signaled per kind (All => children.len(), Any => 1.min(children.len()), None => 0 — None leaves fork_remaining
at 0, the caller-visible “parent proceeds now, no on_child_done
needed” signal). table: &mut ProcessTable (not the shared
&ProcessTable resume_for/start take) is correct here: this
wave never calls handle_fork concurrently with anything else (see
this module’s doc comment).
Sourcepub fn on_child_done(
&self,
table: &mut ProcessTable,
child: ProcessId,
) -> Result<Option<ResumeArg>, ResumeError>
pub fn on_child_done( &self, table: &mut ProcessTable, child: ProcessId, ) -> Result<Option<ResumeArg>, ResumeError>
D1: reports one fork child’s completion to its parent, returning the
parent’s own next resume() argument exactly when the join condition
is satisfied — None otherwise (parent not resumed yet, or the
parent’s join was already satisfied and this is a later, detached
child under JoinKind::Any). Looks up child’s parent via the
child’s own ProcessDescriptor::fork_parent (an O(1) read set by
handle_fork above), never a linear scan over every parent’s
fork_children.
Task 9 (B-sched wave, SC-125) additions: before the ordinary
fork_join_kind (All/Any/None) computation below, this method
now also checks child’s parent for an active wait_order
(ProcessDescriptor::wait_order, installed by Engine:: apply_wait_order) or wait_fork (wait_fork_remaining, installed
by Engine::apply_wait_fork) wait — both genuinely independent of
fork_join_kind in practice (a real wait fork/wait_order is
always preceded by a fork ... join_none, which leaves
fork_join_kind permanently at Some(JoinKind::None), itself
always a no-op arm below — see handle_fork’s own doc comment).
Return type changed from Option<ResumeArg> to
Result<Option<ResumeArg>, ResumeError> to carry
ResumeError::WaitOrderViolated — every pre-existing call site
(this file’s own tests, sched::control::Engine::apply_suspend) is
updated accordingly; the ordinary All/Any/None paths still
only ever produce Ok(..), never Err.