use crate::{context, runqueue as queue}; use turkos_os_thread_wait::thread_wait as wait; use turkos_os_threads::threads::{State, ThreadId, Wait}; /// # Safety /// Owns an actual signal-source pin independent of Queue/Table/allocator. All /// observations read trusted source/CPU state. Release failure returns the pin. /// IRQ uses a distinct Producer owner and never calls this task authority. pub unsafe trait WaitAuthority: wait::Producer { type Pin; fn retain_source(&mut self, source: wait::Source) -> Result; fn validate_source(&self, pin: &Self::Pin, source: wait::Source) -> Result<(), wait::Error>; fn release_source(&mut self, pin: Self::Pin) -> Result<(), (wait::Error, Self::Pin)>; } pub struct WaitPins

{ pin: Option

, source: wait::Source, thread: ThreadId, target: ThreadId, member: usize, claim: u64, } pub struct WaitPrepared { selection: Option, sleep: Option, member: queue::Handle, target: queue::Handle, target_thread: ThreadId, closed: bool, } /// Owns all three real Queue/CompletionBank members for the lifetime of every /// wait, including terminal/quarantined waits. No member retirement is exposed. pub struct WaitGuestBridge< B: queue::QueueCompletionBackend + queue::WaitQueueServices, A: WaitAuthority, > { queue: queue::ReturnQueue, handles: [queue::Handle; 3], authority: A, claims: [Option; 3], sequence: u64, failed_selection: Option, faulted: bool, departed_target: Option, departed_handle: Option, } impl WaitGuestBridge { #[allow(clippy::result_large_err)] pub fn new( queue: queue::ReturnQueue, handles: [queue::Handle; 3], authority: A, ) -> Result, A)> { let this = Self { queue, handles, authority, claims: [None; 3], sequence: 0, failed_selection: None, faulted: false, departed_target: None, departed_handle: None, }; let checked = this.gate().and_then(|_| { for i in 0..3 { if this.handles[..i].contains(&this.handles[i]) { return Err(wait::Error::Duplicate); } this.queue .queue() .record(this.handles[i]) .map_err(|_| wait::Error::Stale)?; } Ok(()) }); match checked { Ok(()) => Ok(this), Err(e) => Err((e, this.queue, this.authority)), } } fn trusted_execution(&self) -> wait::Execution { let mut e = self.authority.execution(); // Pure trusted architecture gate before borrowing any owner. Wrong // contexts return their actual state for the frozen gate to reject. if wait::context(0, e, wait::Operation::Service).is_err() { return e; } if let Some(h) = self.departed_handle { e.current = None; if let Ok(physical) = self.queue.queue().wait_guest_physical_landing(h) && physical.current == self.departed_target { return physical; } } e } fn gate(&self) -> Result { let e = self.trusted_execution(); wait::context(0, e, wait::Operation::Service)?; if self.faulted || self.queue.quarantined() { return Err(wait::Error::Quarantined); } let actual = self .queue .queue() .with_backend_observation(|b| b.execution()); if (actual.cpu, actual.masked, actual.in_irq) != (e.cpu, e.irq_masked, e.in_irq) || (actual.thread != e.current && !(actual.thread.is_none() && e.current.is_some() && self.departed_target == e.current)) { return Err(wait::Error::Context); } Ok(e) } fn member(&self, id: ThreadId) -> Result { self.gate()?; self.handles .iter() .position(|h| self.queue.queue().record(*h).is_ok_and(|r| r.thread == id)) .ok_or(wait::Error::Stale) } pub fn with_queue_observation(&self, f: impl FnOnce(&queue::ReturnQueue) -> R) -> R { f(&self.queue) } pub fn retained_claims(&self) -> usize { self.claims.iter().flatten().count() } pub fn retained_failure(&self) -> bool { self.failed_selection.is_some() || self.faulted } fn failure(&mut self, e: queue::HandoffSelectionError, p: &mut WaitPrepared) -> wait::Failure { match e { queue::HandoffSelectionError::Before(_, token) => { p.selection = Some(token); wait::Failure { error: wait::Error::Backend, phase: wait::FailurePhase::Before, } } queue::HandoffSelectionError::Quarantined(_) => { self.faulted = true; wait::Failure { error: wait::Error::Quarantined, phase: wait::FailurePhase::After, } } } } fn custody(&mut self, p: &mut WaitPrepared, resolve: bool) -> Result<(), wait::Failure> { let before = |error| wait::Failure { error, phase: wait::FailurePhase::Before, }; self.gate().map_err(before)?; let q = self .queue .quiescent() .map_err(|_| before(wait::Error::Pending))?; match q.wait_guest_custody(p.member, &mut p.sleep, resolve) { Ok(()) => Ok(()), Err(f) => { let after = f.phase == context::FailurePhase::AfterSwitch; if after { self.faulted = true; } Err(wait::Failure { error: if after { wait::Error::Quarantined } else { wait::Error::Backend }, phase: if after { wait::FailurePhase::After } else { wait::FailurePhase::Before }, }) } } } } unsafe impl wait::Backend for WaitGuestBridge { type Pins = WaitPins; type Prepared = WaitPrepared; type Capture = context::Capture; fn execution(&self) -> wait::Execution { self.trusted_execution() } fn observe(&self, source: wait::Source) -> Result { self.gate()?; let o = self.authority.observe()?; if o.source != source { return Err(wait::Error::Source); } Ok(o) } fn retain( &mut self, thread: ThreadId, target: ThreadId, source: wait::Source, ) -> Result { self.gate()?; let member = self.member(thread)?; self.member(target)?; if self.claims[member].is_some() { return Err(wait::Error::Duplicate); } let claim = self.sequence.checked_add(1).ok_or(wait::Error::Exhausted)?; let pin = self.authority.retain_source(source)?; self.sequence = claim; self.claims[member] = Some(claim); Ok(WaitPins { pin: Some(pin), source, thread, target, member, claim, }) } fn validate( &self, p: &Self::Pins, thread: ThreadId, target: ThreadId, source: wait::Source, ) -> Result<(), wait::Error> { self.gate()?; if (p.thread, p.target, p.source) != (thread, target, source) || self.claims[p.member] != Some(p.claim) { return Err(wait::Error::Stale); } self.authority .validate_source(p.pin.as_ref().ok_or(wait::Error::State)?, source)?; for id in [thread, target] { let i = self.member(id)?; if self .queue .queue() .wait_guest_observe(self.handles[i]) .map_err(|_| wait::Error::State)? .thread .state == State::Dead { return Err(wait::Error::State); } } Ok(()) } fn stage( &mut self, p: &mut Self::Pins, capture: Self::Capture, ) -> Result { self.gate()?; let target = self.handles[self.member(p.target)?]; if self.queue.queue().ready_order()[0] != Some(target) { return Err(wait::Error::State); } let actual = self .queue .queue() .with_backend_observation(|b| { // Queue prepare uses this same actual capture authority, never the requested capture. b.wait_capture() }) .map_err(|_| wait::Error::Backend)?; if actual != capture { return Err(wait::Error::Context); } let token = self .queue .select(queue::Disposition::Sleeping) .map_err(|_| wait::Error::Backend)?; if self.queue.target(&token).ok() != Some(target) { self.failed_selection = Some(token); self.faulted = true; return Err(wait::Error::Quarantined); } Ok(WaitPrepared { selection: Some(token), sleep: None, member: self.handles[p.member], target, target_thread: p.target, closed: false, }) } fn abort(&mut self, p: &mut WaitPrepared) -> Result<(), wait::Failure> { self.gate().map_err(|error| wait::Failure { error, phase: wait::FailurePhase::Before, })?; let token = p.selection.take().ok_or(wait::Failure { error: wait::Error::State, phase: wait::FailurePhase::Before, })?; match self.queue.abort(token) { Ok(()) => { p.closed = true; Ok(()) } Err(e) => Err(self.failure(e, p)), } } fn depart(&mut self, p: &mut WaitPrepared) -> Result<(), wait::Failure> { self.gate().map_err(|error| wait::Failure { error, phase: wait::FailurePhase::Before, })?; let token = p.selection.take().ok_or(wait::Failure { error: wait::Error::State, phase: wait::FailurePhase::Before, })?; match self.queue.depart(token) { Ok(t) => { p.selection = Some(t); self.departed_target = Some(p.target_thread); self.departed_handle = Some(p.target); Ok(()) } Err(e) => Err(self.failure(e, p)), } } fn landed(&mut self, p: &mut WaitPrepared) -> Result<(), wait::Failure> { self.gate().map_err(|error| wait::Failure { error, phase: wait::FailurePhase::Before, })?; let token = p.selection.take().ok_or(wait::Failure { error: wait::Error::State, phase: wait::FailurePhase::Before, })?; match self.queue.landed(token) { Ok(h) if h == p.target => { self.departed_target = None; self.departed_handle = None; if let Err(mut f) = self.custody(p, false) { // The real handoff has completed; any later refusal cannot undo it. self.faulted = true; f.phase = wait::FailurePhase::After; return Err(f); } Ok(()) } Ok(_) => { self.faulted = true; Err(wait::Failure { error: wait::Error::State, phase: wait::FailurePhase::After, }) } Err(e) => Err(self.failure(e, p)), } } fn resolve( &mut self, pins: &mut Self::Pins, p: &mut WaitPrepared, _: wait::Outcome, ) -> Result<(), wait::Failure> { if p.closed || p.member != self.handles[pins.member] || p.selection.is_some() { return Err(wait::Failure { error: wait::Error::State, phase: wait::FailurePhase::Before, }); } self.custody(p, true)?; p.closed = true; Ok(()) } fn release( &mut self, mut owned: wait::Retained, ) -> Result<(), (wait::Error, wait::Retained)> { let execution = match self.gate() { Ok(e) => e, Err(e) => return Err((e, owned)), }; if owned .prepared .as_ref() .is_some_and(|p| !p.closed || p.selection.is_some() || p.sleep.is_some()) || self.claims[owned.pins.member] != Some(owned.pins.claim) { return Err((wait::Error::Pending, owned)); } let pin = owned.pins.pin.take().unwrap(); if let Err((e, pin)) = self.authority.release_source(pin) { owned.pins.pin = Some(pin); return Err((e, owned)); } // The source pin was actually retired. Quarantine preserves logical // claim and all Queue bindings; it makes no retained-pin claim. if self.authority.execution() != execution { self.faulted = true; return Err((wait::Error::Quarantined, owned)); } self.claims[owned.pins.member] = None; Ok(()) } }