Skip to main content

ProcessTable

Struct ProcessTable 

Source
pub struct ProcessTable { /* private fields */ }
Expand description

Process storage, genuinely slotmap::SlotMap-backed (SC-063). ProcessId (u32) stays the crate-visible identity: v1 never frees/reuses a slot (fork children get fresh ids from the same monotonic sequence; nothing calls SlotMap::remove), so order_to_key[id as usize] is a stable, densely-assigned ProcessId -> ProcessKey side index — the same “assigned order equals registration order, for the lifetime of a run” invariant the previous Vec-backed slice already relied on, preserved exactly across this migration.

Implementations§

Source§

impl ProcessTable

Source

pub fn new() -> Self

Source

pub fn register(&mut self, compiled: Box<dyn CompiledProcess>) -> ProcessId

Registers a new process, assigning it the next ProcessId and registration_order (monotonic, never reused — v1 never frees a slot, matching Task 11’s documented assumption that ProcessId assignment order equals registration_order for the lifetime of a run). Signature unchanged by the slotmap migration — resume.rs (Task 12) keeps compiling with no edit of its own.

Source

pub fn count(&self) -> usize

How many ProcessIds were ever assigned: ids are dense, 0..count().

Source

pub fn get(&self, id: ProcessId) -> Option<&ProcessDescriptor>

Shared-reference lookup (Task 11’s review fix) — lets ResumeDriver reach a descriptor’s Mutex/AtomicBool fields through a shared &ProcessTable, never requiring &mut access to the whole table. Signature unchanged by the slotmap migration.

Source

pub fn get_mut(&mut self, id: ProcessId) -> Option<&mut ProcessDescriptor>

Mutable lookup — added by Task 12 (a minimal, same-track, additive extension to this Task-11-owned file; recorded in docs/CONTRACTS.md/this commit’s deviations, not a rewrite of anything Task 11 shipped). handle_fork/on_child_done mutate fork_children/fork_parent/fork_join_kind/fork_remaining/ fork_any_signaled directly — plain, non-Mutex fields per Task 11/D1a — which needs exclusive access to the whole table via &mut ProcessTable. This does not reopen SC-061: Task 12’s review fix note (resume.rs) already establishes this wave never calls handle_fork/on_child_done concurrently with resume_for/start (v1’s default SequentialController dispatches everything from one thread; only the SC-061 stress test deliberately drives resume_for from many, and never touches fork state).

Source

pub fn set_region_id(&mut self, id: ProcessId, region_id: u32)

Task 9 (A2-part2, CG-102). Sets id’s own region_id, called by SchedulerControl::register_process (sched/control.rs) right after register – a small, additive, same-track extension of this Task- 11-owned file (mirroring Task 12’s own get_mut precedent, recorded there identically), rather than widening register’s own signature: register’s direct callers (finals.rs, resume.rs, this file’s own unit tests, fork-child minting) have no notion of region_id at all and are unrelated to CG-102’s scheduler-dispatch scope, so leaving register’s arity untouched keeps this a minimal, targeted addition instead of churning every one of those call sites for a field they’d only ever pass 0 for anyway (ProcessDescriptor::new already defaults region_id to that same real v1 value).

Source

pub fn set_reactive(&mut self, id: ProcessId)

Marks id as a Reactive-region process (ProcessDescriptor::reactive).

Source

pub fn any_live_program_child(&self) -> bool

Whether any live fork child still belongs to a program thread (LRM 24.3).

Source

pub fn is_reactive(&self, id: ProcessId) -> bool

Whether id runs in the Reactive region. false for an unknown id.

Source

pub fn region_id(&self, id: ProcessId) -> u32

Task 9 (A2-part2, CG-102). region_id(&self, id: ProcessId) -> u32 – the plan’s own literal getter shape. Returns 0 (v1’s own real, correct single-conservative-partition value, not a sentinel) for an unknown id rather than panicking or returning Option: a caller reaching this (e.g. dispatch_ready_set) only ever holds ProcessIds this same Engine minted, so an unknown id here would already indicate a bug in the caller’s own bookkeeping, not a legitimate “no region_id set” state this getter needs to distinguish.

Source

pub fn remove(&mut self, id: ProcessId) -> Option<ProcessDescriptor>

Task 7 (B-sched wave, ledger SC-062): the SlotMap::remove wrapper this file’s own module doc comment already promised (“… stable… until eventually calls SlotMap::remove – a forward reference to work that was never done” – now done). Removes id’s descriptor and returns it; a later get/get_mut for the same id returns None.

Deviation from the plan’s literal text (recorded here and in docs/CONTRACTS.md): the plan additionally describes tombstoning id’s own order_to_key side-index slot. That is unnecessary and deliberately not done: slotmap::SlotMap::remove already bumps the removed slot’s internal generation, so the same ProcessKey value still sitting in order_to_key[id] no longer resolves via self.slots.get/get_mut – this is the entire reason Task 11 required a genuine SlotMap (SC-063) rather than a Vec in the first place. Adding a second, hand-maintained tombstone layer on top of that would only be able to drift out of sync with the SlotMap’s own source of truth; leaving order_to_key untouched keeps exactly one source of truth for liveness, and a stale/reused ProcessId still fails loudly via get’s existing Option return, exactly as the plan’s own acceptance requires.

Trait Implementations§

Source§

impl Default for ProcessTable

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V