//! Actual frozen WaitSet + three-member Queue/CompletionBank/Table owners. //! CPU/register/source/clock progression is MODELED_ONLY; no assembly claim. #![allow(dead_code)] include!("services-prefix.rs"); use os_k1060_thread::{State, ThreadId}; use turkos_os_k1080_wait_main::wait_core as wait; use turkos_os_k1080_wait_main::bridge::{WaitAuthority, WaitGuestBridge}; unsafe impl os_k1060_context::WaitContextServices for model::Device { fn physical_wait_landing( &self, b: &Self::Binding, image: &os_k1060_context::Image, nonce: u64, ) -> Result { let h = self.inner.hardware.borrow(); let cpu = self.cpu.borrow(); let r = os_k1060_context::Backend::record(self, b)?; if self.root.get() != model::saved::ROOT || nonce == 0 || cpu.nonce != nonce || !h.sp.is_multiple_of(16) || h.sp < r.layout.usable_bottom() || h.sp > r.layout.usable_top() || cpu.registers != Some(model::saved::Backend::expected(*image)) { return Err(os_k1060_context::Error::Capture); } Ok(wait::Execution { cpu: h.cpu, irq_masked: h.daif & 128 != 0, in_irq: h.in_irq, current: Some(b.id), }) } fn take_sleep_wait( &mut self, b: &Self::Binding, owned: &mut Option, ) -> Result<(), os_k1060_context::Failure> { let before = |error| os_k1060_context::Failure { error, phase: os_k1060_context::FailurePhase::BeforeSwitch, }; if self.cpu.borrow().wait_fail_take || owned.is_some() || !self .inner .sleep_wait .as_ref() .is_some_and(|w| w.thread() == b.id) { return Err(before(os_k1060_context::Error::Wake)); } *owned = self.inner.sleep_wait.take(); self.cpu.borrow_mut().wait_takes += 1; Ok(()) } fn resolve_sleep_wait( &mut self, b: &Self::Binding, owned: &mut Option, ) -> Result<(), os_k1060_context::Failure> { let before = |error| os_k1060_context::Failure { error, phase: os_k1060_context::FailurePhase::BeforeSwitch, }; if self.cpu.borrow().wait_fail_resolve || !owned.as_ref().is_some_and(|w| w.thread() == b.id) { return Err(before(os_k1060_context::Error::Wake)); } match self.inner.table.borrow_mut().wake(owned.take().unwrap()) { Ok(id) => assert_eq!(id, b.id), Err((_, w)) => { *owned = Some(w); return Err(before(os_k1060_context::Error::Wake)); } } self.cpu.borrow_mut().wait_resolves += 1; match self.cpu.borrow().wait_drift { 1 => self.inner.hardware.borrow_mut().cpu = 1, 2 => self.inner.hardware.borrow_mut().daif = 0, 3 => self.inner.hardware.borrow_mut().current = None, 4 => { self.inner.hardware.borrow_mut().cpu = 1; core::mem::forget(self.inner.table.borrow_mut()); } _ => {} } Ok(()) } } #[derive(Default)] struct Ledger { pins: Cell, releases: Cell, release_fail: Cell, release_drift: Cell, dropped: Cell, } struct SourcePin { source: wait::Source, issuer: Rc, released: bool, } impl Drop for SourcePin { fn drop(&mut self) { if !self.released { self.issuer.dropped.set(self.issuer.dropped.get() + 1); } } } struct Port { hardware: Rc>, observation: Rc>, ledger: Rc, } unsafe impl wait::Producer for Port { fn execution(&self) -> wait::Execution { let h = self.hardware.borrow(); wait::Execution { cpu: h.cpu, irq_masked: h.daif & 128 != 0, in_irq: h.in_irq, current: h.current, } } fn observe(&self) -> Result { Ok(self.observation.get()) } } unsafe impl WaitAuthority for Port { type Pin = SourcePin; fn retain_source(&mut self, s: wait::Source) -> Result { if s != self.observation.get().source { return Err(wait::Error::Source); } self.ledger.pins.set(self.ledger.pins.get() + 1); Ok(SourcePin { source: s, issuer: self.ledger.clone(), released: false, }) } fn validate_source(&self, p: &SourcePin, s: wait::Source) -> Result<(), wait::Error> { if p.source != s || !Rc::ptr_eq(&p.issuer, &self.ledger) || self.observation.get().source != s { Err(wait::Error::Source) } else { Ok(()) } } fn release_source(&mut self, mut p: SourcePin) -> Result<(), (wait::Error, SourcePin)> { if self.ledger.release_fail.get() { return Err((wait::Error::Backend, p)); } assert!(Rc::ptr_eq(&p.issuer, &self.ledger)); self.ledger.pins.set(self.ledger.pins.get() - 1); self.ledger.releases.set(self.ledger.releases.get() + 1); p.released = true; if self.ledger.release_drift.get() { self.hardware.borrow_mut().cpu = 1; } Ok(()) } } type Bridge = WaitGuestBridge; struct System { waits: wait::WaitSet, ingress: wait::Ingress, ids: [ThreadId; 3], handles: [os_k1060_queue::Handle; 3], hardware: Rc>, cpu: Rc>, observation: Rc>, ledger: Rc, } fn system() -> System { let (mut q, h, hardware, cpu) = queue(); assert_eq!(step(&mut q, false), h[0]); let handles: [_; 3] = h.try_into().ok().unwrap(); let ids = handles.map(|h| q.queue().record(h).unwrap().thread); let observation = Rc::new(Cell::new(wait::Observation { source: wait::Source { channel: 0x108001, epoch: 1, owner: 0x1080, }, sequence: 0, ready: false, now: 100, })); let ledger = Rc::new(Ledger::default()); let port = || Port { hardware: hardware.clone(), observation: observation.clone(), ledger: ledger.clone(), }; let ingress = wait::Ingress::new(port()).ok().unwrap(); let bridge = Bridge::new(q, handles, port()).ok().unwrap(); let waits = wait::WaitSet::new(bridge).ok().unwrap(); System { waits, ingress, ids, handles, hardware, cpu, observation, ledger, } } fn arm(s: &mut System, source: usize, target: usize, deadline: Option) -> wait::WaitToken { let c = s .waits .with_backend_observation(|b| b.with_queue_observation(capture)); s.waits .arm(&s.ingress, s.ids[source], s.ids[target], c, deadline) .ok() .unwrap() } fn state(s: &System, i: usize) -> State { s.waits.with_backend_observation(|b| { b.with_queue_observation(|q| { q.queue().with_backend_observation(|b| { b.bank.handoff().bank().with_backend_observation(|d| { d.inner.table.borrow().record(s.ids[i]).unwrap().state }) }) }) }) } fn physical_landing(s: &mut System) { let target = s .waits .records() .iter() .find(|r| r.phase == wait::Phase::Departed) .unwrap() .target .unwrap(); let (image, nonce) = s.waits.with_backend_observation(|b| { b.with_queue_observation(|q| { q.queue().with_retained_observation(|p| { q.queue().with_backend_observation(|b| { let t = p.unwrap().handoff.as_ref().unwrap(); (b.bank.handoff().target_image(t).unwrap(), t.nonce()) }) }) }) }); // MODELED_ONLY raw continuation boundary: every set/queue/bank loan ended. s.hardware.borrow_mut().sp = image.sp() - 64; s.hardware.borrow_mut().current = Some(target); s.cpu.borrow_mut().nonce = nonce; s.cpu.borrow_mut().registers = Some(model::saved::Backend::expected(image)); } fn arrive(s: &mut System, t: wait::WaitTransfer) -> wait::WaitToken { physical_landing(s); s.waits.landed(t).ok().unwrap() } fn sleep(s: &mut System, source: usize, target: usize, deadline: Option) -> wait::WaitToken { let t = arm(s, source, target, deadline); let wait::Departure::Switch(t) = s .waits .depart(t) .unwrap_or_else(|(e, _)| panic!("departure: {e:?}")) else { panic!("expected real sleep handoff") }; assert_eq!(state(s, source), State::Sleeping); arrive(s, t) } fn signal(s: &mut System, now: u64) { let mut o = s.observation.get(); o.sequence += 1; o.now = now; s.observation.set(o); s.hardware.borrow_mut().in_irq = true; let hardware = s.hardware.clone(); assert!( unsafe { turkos_os_k1080_wait_main::ingress::wait_guest_irq_poll(&mut s.ingress, || { let h = hardware.borrow(); wait::Execution { cpu: h.cpu, irq_masked: h.daif & 128 != 0, in_irq: h.in_irq, current: h.current, } }) } .unwrap() ); s.hardware.borrow_mut().in_irq = false; } #[test] fn genuine_sleep_has_pending_prepared_before_table_change_and_exact_wait_after_landing() { let mut s = system(); let t = arm(&mut s, 0, 1, None); assert_eq!(state(&s, 0), State::Running); s.waits.with_backend_observation(|b| { b.with_queue_observation(|q| { assert!(q.queue().snapshot().retained_prepared); assert_eq!(ownership(q), (3, 12, 3)); }) }); let wait::Departure::Switch(t) = s .waits .depart(t) .unwrap_or_else(|(e, _)| panic!("departure: {e:?}")) else { panic!() }; assert_eq!(state(&s, 0), State::Sleeping); assert_eq!(s.waits.service(&mut s.ingress), Err(wait::Error::Pending)); let t = arrive(&mut s, t); assert_eq!(s.cpu.borrow().wait_takes, 1); s.waits.with_backend_observation(|b| { b.with_queue_observation(|q| { q.queue().with_backend_observation(|b| { b.bank .handoff() .bank() .with_backend_observation(|d| assert!(d.inner.sleep_wait.is_none())) }) }) }); s.waits.cancel(&t).unwrap(); assert_eq!(state(&s, 0), State::Ready); assert_eq!( s.waits.retire(t).ok().unwrap().outcome, wait::Outcome::Cancelled ); assert_eq!(s.cpu.borrow().wait_resolves, 1); assert_eq!(s.ledger.pins.get(), 0); } #[test] fn early_signal_aborts_actual_three_member_prepared_without_sleep() { let mut s = system(); let t = arm(&mut s, 0, 1, Some(101)); signal(&mut s, 101); let wait::Departure::Ready(t) = s .waits .depart(t) .unwrap_or_else(|(e, _)| panic!("departure: {e:?}")) else { panic!() }; assert_eq!(state(&s, 0), State::Running); assert_eq!(s.cpu.borrow().wait_takes, 0); assert_eq!( s.waits.retire(t).ok().unwrap().outcome, wait::Outcome::Signal ); s.waits.with_backend_observation(|b| { b.with_queue_observation(|q| assert!(!q.queue().snapshot().retained_prepared)) }); } #[test] fn two_exact_sleep_waits_same_tick_signal_win_once_and_publish_fifo_once() { let mut s = system(); let a = sleep(&mut s, 0, 1, Some(105)); let b = sleep(&mut s, 1, 2, Some(105)); assert_eq!( (state(&s, 0), state(&s, 1), state(&s, 2)), (State::Sleeping, State::Sleeping, State::Running) ); assert_eq!(s.cpu.borrow().wait_takes, 2); signal(&mut s, 105); assert_eq!(s.waits.service(&mut s.ingress), Ok(2)); assert_eq!(s.waits.service(&mut s.ingress), Ok(0)); assert_eq!(s.waits.winners(), 2); assert_eq!(s.cpu.borrow().wait_resolves, 2); s.waits.with_backend_observation(|b| { b.with_queue_observation(|q| { assert_eq!( q.queue().ready_order(), [Some(s.handles[0]), Some(s.handles[1]), None] ) }) }); for t in [a, b] { assert_eq!( s.waits.retire(t).ok().unwrap().outcome, wait::Outcome::Signal ); } assert_eq!((s.ledger.pins.get(), s.ledger.releases.get()), (0, 2)); s.waits .with_backend_observation(|b| assert_eq!(b.retained_claims(), 0)); assert_eq!(s.ledger.dropped.get(), 0); } #[test] fn cancellation_keeps_other_sleep_episode_and_deadline_wakes_only_that_wait() { let mut s = system(); let a = sleep(&mut s, 0, 1, Some(105)); let b = sleep(&mut s, 1, 2, Some(109)); s.waits.cancel(&a).unwrap(); assert_eq!(state(&s, 1), State::Sleeping); s.waits.retire(a).ok().unwrap(); let mut o = s.observation.get(); o.now = 109; s.observation.set(o); assert_eq!(s.waits.service(&mut s.ingress), Ok(1)); assert_eq!( s.waits.retire(b).ok().unwrap().outcome, wait::Outcome::Timeout ); assert_eq!(s.cpu.borrow().wait_resolves, 2); } #[test] fn old_queued_event_cannot_wake_reused_same_source_generation() { let mut s = system(); let a = arm(&mut s, 0, 1, None); signal(&mut s, 101); let wait::Departure::Ready(a) = s.waits.depart(a).ok().unwrap() else { panic!() }; let old = s.waits.retire(a).ok().unwrap().generation; let b = sleep(&mut s, 0, 1, None); assert!(b.generation() > old); assert_eq!(s.waits.service(&mut s.ingress), Ok(0)); assert_eq!(state(&s, 0), State::Sleeping); s.waits.cancel(&b).unwrap(); s.waits.retire(b).ok().unwrap(); } #[test] fn separate_irq_ingress_operates_while_every_task_owner_is_exclusively_borrowed() { let mut s = system(); let a = sleep(&mut s, 0, 1, None); let waits = RefCell::new(s.waits); let table = waits.borrow().with_backend_observation(|b| { b.with_queue_observation(|q| { q.queue().with_backend_observation(|b| { b.bank.handoff().bank().with_backend_observation(|d| { &d.inner.table as *const RefCell> }) }) }) }); let held_table = unsafe { &*table }.borrow_mut(); let held_waits = waits.borrow_mut(); let mut o = s.observation.get(); o.sequence += 1; s.observation.set(o); s.hardware.borrow_mut().in_irq = true; let hw = s.hardware.clone(); assert!( unsafe { turkos_os_k1080_wait_main::ingress::wait_guest_irq_poll(&mut s.ingress, || { let h = hw.borrow(); wait::Execution { cpu: h.cpu, irq_masked: h.daif & 128 != 0, in_irq: h.in_irq, current: h.current, } }) } .unwrap() ); assert_eq!(s.cpu.borrow().wait_resolves, 0); drop(held_waits); drop(held_table); s.waits = waits.into_inner(); s.hardware.borrow_mut().in_irq = false; assert_eq!(s.waits.service(&mut s.ingress), Ok(1)); s.waits.retire(a).ok().unwrap(); } #[test] fn raw_irq_gate_precedes_pointer_loan_for_wrong_cpu_unmasked_and_non_irq() { for kind in 0..3 { let e = wait::Execution { cpu: if kind == 0 { 1 } else { 0 }, irq_masked: kind != 1, in_irq: kind != 2, current: None, }; let r = unsafe { turkos_os_k1080_wait_main::ingress::wait_guest_irq_poll::( core::ptr::null_mut(), || e, ) }; assert_eq!( r, Err(if kind == 0 { wait::Error::Cpu } else { wait::Error::Context }) ); } } #[test] fn context_and_queue_gates_precede_actual_table_access() { let (mut b, h, hardware, _) = backend(); let m = b.issue(h[0], 0).unwrap(); let table = b.bank.handoff().bank().with_backend_observation(|d| { &d.inner.table as *const RefCell> }); let _exclusive = unsafe { &*table }.borrow_mut(); for kind in 0..3 { { let mut hw = hardware.borrow_mut(); hw.cpu = if kind == 0 { 1 } else { 0 }; hw.daif = if kind == 1 { 0 } else { 0x3c0 }; hw.in_irq = kind == 2; } let mut owned = None; assert!(b.bank.wait_guest_custody(h[0], &mut owned, false).is_err()); assert!( os_k1060_queue::WaitQueueServices::wait_custody(&mut b, &m, &mut owned, false).is_err() ); assert!(owned.is_none()); } } #[test] fn mismatched_capture_is_refused_before_actual_preparation_and_source_pin_released() { let mut s = system(); let mut c = s .waits .with_backend_observation(|b| b.with_queue_observation(capture)); c.episode += 1; assert!( s.waits .arm(&s.ingress, s.ids[0], s.ids[1], c, None) .is_err() ); assert_eq!((s.ledger.pins.get(), s.ledger.releases.get()), (0, 1)); assert_eq!(state(&s, 0), State::Running); s.waits.with_backend_observation(|b| { b.with_queue_observation(|q| assert!(!q.queue().snapshot().retained_prepared)) }); } #[test] fn actual_before_departure_keeps_prepared_for_retry_and_after_failure_quarantines_all_owners() { for after in [false, true] { let mut s = system(); let t = arm(&mut s, 0, 1, None); s.cpu.borrow_mut().depart_fail = Some(if after { os_k1060_context::FailurePhase::AfterSwitch } else { os_k1060_context::FailurePhase::BeforeSwitch }); let (e, t) = s.waits.depart(t).err().unwrap(); assert_eq!(s.ledger.pins.get(), 1); s.waits.with_backend_observation(|b| { b.with_queue_observation(|q| assert_eq!(ownership(q), (3, 12, 3))) }); if after { assert_eq!(e, wait::Error::Quarantined); assert_eq!(s.waits.records()[t.slot()].phase, wait::Phase::Quarantined); assert_eq!(state(&s, 0), State::Sleeping); s.waits.with_backend_observation(|b| { b.with_queue_observation(|q| { q.queue().with_backend_observation(|b| { b.bank .handoff() .bank() .with_backend_observation(|d| assert!(d.inner.sleep_wait.is_some())) }) }) }); } else { assert_eq!(e, wait::Error::Backend); assert_eq!(state(&s, 0), State::Running); s.cpu.borrow_mut().depart_fail = None; let wait::Departure::Switch(t) = s.waits.depart(t).ok().unwrap() else { panic!() }; let t = arrive(&mut s, t); s.waits.cancel(&t).unwrap(); s.waits.retire(t).ok().unwrap(); } } } #[test] fn custody_refusal_after_real_landing_keeps_actual_wait_and_all_three_bindings() { let mut s = system(); let t = arm(&mut s, 0, 1, None); let wait::Departure::Switch(t) = s.waits.depart(t).ok().unwrap() else { panic!() }; s.cpu.borrow_mut().wait_fail_take = true; let target = s.ids[1]; let (image, nonce) = s.waits.with_backend_observation(|b| { b.with_queue_observation(|q| { q.queue().with_retained_observation(|p| { q.queue().with_backend_observation(|b| { let t = p.unwrap().handoff.as_ref().unwrap(); (b.bank.handoff().target_image(t).unwrap(), t.nonce()) }) }) }) }); s.hardware.borrow_mut().current = Some(target); s.hardware.borrow_mut().sp = image.sp() - 64; s.cpu.borrow_mut().nonce = nonce; s.cpu.borrow_mut().registers = Some(model::saved::Backend::expected(image)); assert!(s.waits.landed(t).is_err()); assert_eq!(s.waits.records()[0].phase, wait::Phase::Quarantined); assert_eq!(s.ledger.pins.get(), 1); assert_eq!(state(&s, 0), State::Sleeping); s.waits.with_backend_observation(|b| { assert!(b.retained_failure()); b.with_queue_observation(|q| { assert_eq!(ownership(q), (3, 12, 3)); q.queue().with_backend_observation(|b| { b.bank .handoff() .bank() .with_backend_observation(|d| assert!(d.inner.sleep_wait.is_some())) }); }) }); } #[test] fn wake_refusal_retains_exact_prepared_wait_and_retry_publishes_once() { let mut s = system(); let t = sleep(&mut s, 0, 1, None); signal(&mut s, 101); s.cpu.borrow_mut().wait_fail_resolve = true; assert_eq!(s.waits.service(&mut s.ingress), Err(wait::Error::Backend)); assert_eq!(state(&s, 0), State::Sleeping); assert_eq!(s.waits.winners(), 0); assert_eq!(s.ledger.pins.get(), 1); s.cpu.borrow_mut().wait_fail_resolve = false; assert_eq!(s.waits.service(&mut s.ingress), Ok(1)); assert_eq!(s.cpu.borrow().wait_resolves, 1); s.waits.retire(t).ok().unwrap(); } #[test] fn successful_table_wake_with_execution_drift_quarantines_without_fifo_publication() { for drift in 1..=3 { let mut s = system(); let t = sleep(&mut s, 0, 1, None); s.cpu.borrow_mut().wait_drift = drift; signal(&mut s, 101); assert_eq!( s.waits.service(&mut s.ingress), Err(wait::Error::Quarantined) ); assert_eq!(state(&s, 0), State::Ready); assert_eq!(s.cpu.borrow().wait_resolves, 1); assert_eq!(s.waits.records()[t.slot()].phase, wait::Phase::Quarantined); assert_eq!(s.ledger.pins.get(), 1); s.waits.with_backend_observation(|b| { b.with_queue_observation(|q| { assert_eq!(q.queue().ready_order(), [Some(s.handles[2]), None, None]) }) }); assert!(s.waits.retire(t).is_err()); } } #[test] fn failed_source_release_retains_original_pin_and_claim_after_one_actual_wake() { let mut s = system(); let t = sleep(&mut s, 0, 1, None); s.waits.cancel(&t).unwrap(); s.ledger.release_fail.set(true); let (e, t) = s.waits.retire(t).err().unwrap(); assert_eq!(e, wait::Error::Backend); assert_eq!(s.waits.records()[t.slot()].phase, wait::Phase::Quarantined); assert_eq!( ( s.ledger.pins.get(), s.ledger.releases.get(), s.cpu.borrow().wait_resolves ), (1, 0, 1) ); s.waits .with_backend_observation(|b| assert_eq!(b.retained_claims(), 1)); assert_eq!(s.ledger.dropped.get(), 0); } #[test] fn source_epoch_change_refuses_before_wake_and_keeps_true_sleep_wait() { let mut s = system(); let t = sleep(&mut s, 0, 1, None); let mut o = s.observation.get(); o.source.epoch += 1; s.observation.set(o); assert_eq!(s.waits.cancel(&t), Err(wait::Error::Source)); assert_eq!(state(&s, 0), State::Sleeping); assert_eq!(s.cpu.borrow().wait_resolves, 0); assert_eq!(s.ledger.pins.get(), 1); } #[test] fn successful_source_release_drift_retains_logical_claim_and_queue_without_false_pin_claim() { let mut s = system(); let t = sleep(&mut s, 0, 1, None); s.waits.cancel(&t).unwrap(); s.ledger.release_drift.set(true); let (e, t) = s.waits.retire(t).err().unwrap(); assert_eq!(e, wait::Error::Quarantined); assert_eq!((s.ledger.pins.get(), s.ledger.releases.get()), (0, 1)); assert_eq!(s.waits.records()[t.slot()].phase, wait::Phase::Quarantined); s.waits.with_backend_observation(|b| { assert_eq!(b.retained_claims(), 1); assert!(b.retained_failure()); b.with_queue_observation(|q| assert_eq!(ownership(q), (3, 12, 3))); }); } #[test] fn constructor_duplicate_member_returns_exact_three_owner_queue_and_source_authority() { let (mut q, h, hardware, _) = queue(); step(&mut q, false); let observation = Rc::new(Cell::new(wait::Observation { source: wait::Source { channel: 1, epoch: 1, owner: 1, }, sequence: 0, ready: false, now: 0, })); let ledger = Rc::new(Ledger::default()); let port = Port { hardware, observation, ledger: ledger.clone(), }; let (e, q, p) = Bridge::new(q, [h[0], h[0], h[2]], port).err().unwrap(); assert_eq!(e, wait::Error::Duplicate); assert_eq!(ownership(&q), (3, 12, 3)); assert!(Rc::ptr_eq(&p.ledger, &ledger)); } #[test] fn requested_target_must_be_actual_fifo_head_before_preparation() { let mut s = system(); let c = s .waits .with_backend_observation(|b| b.with_queue_observation(capture)); let e = s .waits .arm(&s.ingress, s.ids[0], s.ids[2], c, None) .err() .unwrap(); assert_eq!(e.error, wait::Error::State); assert!(e.retained.is_none()); s.waits.with_backend_observation(|b| { b.with_queue_observation(|q| assert!(!q.queue().snapshot().retained_prepared)) }); assert_eq!((s.ledger.pins.get(), s.ledger.releases.get()), (0, 1)); assert_eq!(state(&s, 0), State::Running); } #[test] fn direct_bridge_gate_precedes_actual_table_observation_without_waitset_gate() { for kind in 0..3 { let s = system(); let bridge = s.waits.into_backend().ok().unwrap(); let table = bridge.with_queue_observation(|q| { q.queue().with_backend_observation(|b| { b.bank.handoff().bank().with_backend_observation(|d| { &d.inner.table as *const RefCell> }) }) }); let _exclusive = unsafe { &*table }.borrow_mut(); { let mut h = s.hardware.borrow_mut(); h.cpu = if kind == 0 { 1 } else { 0 }; h.daif = if kind == 1 { 0 } else { 0x3c0 }; h.in_irq = kind == 2; } let e = wait::Backend::observe(&bridge, s.observation.get().source) .err() .unwrap(); assert_eq!( e, if kind == 0 { wait::Error::Cpu } else { wait::Error::Context } ); } } #[test] fn postwake_execution_gate_precedes_owner_reborrow_after_real_retirement() { let mut s = system(); let t = sleep(&mut s, 0, 1, None); s.cpu.borrow_mut().wait_drift = 4; signal(&mut s, 101); assert_eq!( s.waits.service(&mut s.ingress), Err(wait::Error::Quarantined) ); assert_eq!(s.cpu.borrow().wait_resolves, 1); assert_eq!(s.waits.records()[t.slot()].phase, wait::Phase::Quarantined); s.waits.with_backend_observation(|b| { b.with_queue_observation(|q| { assert_eq!(q.queue().ready_order(), [Some(s.handles[2]), None, None]); assert_eq!(ownership(q), (3, 12, 3)); }) }); assert!(s.waits.retire(t).is_err()); } #[test] fn landing_current_requires_exact_departed_selection_target_before_owner_access() { let mut s = system(); let t = arm(&mut s, 0, 1, None); let wait::Departure::Switch(t) = s.waits.depart(t).ok().unwrap() else { panic!() }; assert!(s.cpu.borrow().logical_departed); s.hardware.borrow_mut().current = Some(s.ids[2]); s.waits .with_backend_observation(|b| assert_eq!(wait::Backend::execution(b).current, None)); let (e, t) = s.waits.landed(t).err().unwrap(); assert_eq!(e, wait::Error::State); assert_eq!(s.waits.records()[0].phase, wait::Phase::Departed); let t = arrive(&mut s, t); assert!(!s.cpu.borrow().logical_departed); s.waits.cancel(&t).unwrap(); s.waits.retire(t).ok().unwrap(); } #[test] fn old_root_stack_nonce_or_landing_frame_refuses_unchanged_exact_prepared_and_sleep_wait() { for field in 0..7 { let mut s = system(); let t = arm(&mut s, 0, 1, None); let wait::Departure::Switch(t) = s.waits.depart(t).ok().unwrap() else { panic!() }; physical_landing(&mut s); let root = s.waits.with_backend_observation(|b| { b.with_queue_observation(|q| { q.queue().with_backend_observation(|b| { b.bank .handoff() .bank() .with_backend_observation(|d| d.root.clone()) }) }) }); let old_sp = s.waits.with_backend_observation(|b| { b.with_queue_observation(|q| { q.queue().with_backend_observation(|b| { b.bank.handoff().bank().with_backend_observation(|d| { d.inner .table .borrow() .record(s.ids[0]) .unwrap() .layout .usable_top() }) }) }) }); match field { 0 => root.set(model::saved::ROOT + 4096), 1 => s.hardware.borrow_mut().sp = old_sp, 2 => s.cpu.borrow_mut().nonce += 1, 3 => s.cpu.borrow_mut().registers.as_mut().unwrap().pc += 4, 4 => s.cpu.borrow_mut().registers.as_mut().unwrap().sp += 16, 5 => s.cpu.borrow_mut().registers.as_mut().unwrap().q[7][1] ^= 1, _ => s.cpu.borrow_mut().registers.as_mut().unwrap().fpcr ^= 1, } assert_eq!( s.waits .with_backend_observation(wait::Backend::execution) .current, None ); let (e, t) = s.waits.landed(t).err().unwrap(); assert_eq!(e, wait::Error::State); assert_eq!(s.waits.records()[0].phase, wait::Phase::Departed); assert_eq!(state(&s, 0), State::Sleeping); assert_eq!(s.cpu.borrow().wait_takes, 0); assert_eq!(s.ledger.pins.get(), 1); s.waits.with_backend_observation(|b| { b.with_queue_observation(|q| { assert!(q.queue().snapshot().retained_prepared); assert_eq!(ownership(q), (3, 12, 3)); q.queue().with_backend_observation(|b| { b.bank.handoff().bank().with_backend_observation(|d| { assert!( d.inner .sleep_wait .as_ref() .is_some_and(|w| w.thread() == s.ids[0]) ) }) }); }) }); root.set(model::saved::ROOT); let t = arrive(&mut s, t); s.waits.cancel(&t).unwrap(); s.waits.retire(t).ok().unwrap(); } } // NEW tests appended to the byte-bound frozen22 integration fixture. // Hardware/SP/root/register/clock progression remains MODELED_ONLY. unsafe impl turkos_os_k1080_wait_main::bridge::K1080MainBackend for B { fn k1080_execution(&self) -> os_k1060_context::Execution { self.bank .handoff() .bank() .with_backend_observation(os_k1060_context::Backend::execution) } fn k1080_target_wire( &self, p: &Self::Prepared, ) -> Result<(os_k1060_context::Image, u64), wait::Error> { let before = ::execution(self); if before.cpu != 0 || !before.masked || before.in_irq || before.thread.is_some() { return Err(wait::Error::Context); } let t = p.handoff.as_ref().ok_or(wait::Error::State)?; if p.arrived || p.nonce == 0 || p.nonce != t.nonce() { return Err(wait::Error::State); } let image = self .bank .handoff() .target_image(t) .map_err(|_| wait::Error::Stale)?; self.bank.handoff().bank().with_backend_observation(|d| { let drift = d.cpu.borrow().main_wire_drift; if drift == 1 { d.inner.hardware.borrow_mut().cpu = 1; core::mem::forget(d.inner.table.borrow_mut()); } if drift == 3 { d.root.set(d.root.get() + 4096); core::mem::forget(d.inner.table.borrow_mut()); } }); Ok((image, t.nonce())) } fn k1080_bootstrap_wire( &self, p: &Self::ReturnPrepared, ) -> Result { let e = ::execution(self); if e.cpu != 0 || !e.masked || e.in_irq || e.thread.is_some() || p.nonce == 0 || p.observed || p.token.is_none() { return Err(wait::Error::Context); } let result = self .bank .with_return_observation(|r| { r.map(|r| { let mut f = os_k1060_context::Cooperative::EMPTY; f.sp = r.expected.sp; f.x19_x30 = r.expected.x19_x30; f.q = r.expected.q; f.fpcr = r.expected.fpcr; f.fpsr = r.expected.fpsr; f }) }) .ok_or(wait::Error::State); self.bank.handoff().bank().with_backend_observation(|d| { if d.cpu.borrow().main_wire_drift == 2 { d.inner.hardware.borrow_mut().cpu = 1; core::mem::forget(d.inner.table.borrow_mut()); } if d.cpu.borrow().main_wire_drift == 4 { d.root.set(d.root.get() + 4096); core::mem::forget(d.inner.table.borrow_mut()); } }); result } } fn main_capture(s: &System) -> os_k1060_context::Capture { s.waits .with_backend_observation(|b| b.with_queue_observation(capture)) } fn main_physical(s: &mut System, image: os_k1060_context::Image, nonce: u64) { s.waits.with_backend_observation(|bridge| { bridge.with_queue_observation(|q| { q.queue().with_retained_observation(|p| { q.queue().with_backend_observation(|b| { model::physical_step(b.bank.handoff(), p.unwrap().handoff.as_ref().unwrap()); }) }); }) }); let sp = s.hardware.borrow().sp; let candidates = s.waits.with_backend_observation(|bridge| { bridge.with_queue_observation(|q| { q.queue().with_backend_observation(|b| { b.bank.handoff().bank().with_backend_observation(|d| { s.ids .iter() .filter(|id| { let l = d.inner.table.borrow().record(**id).unwrap().layout; sp >= l.usable_bottom() && sp <= l.usable_top() }) .copied() .collect::>() }) }) }) }); assert_eq!(candidates.len(), 1); let target = candidates[0]; s.hardware.borrow_mut().current = Some(target); let ordinal = s.ids.iter().position(|id| *id == target).unwrap(); assert_eq!(state(s, ordinal), State::Ready); // Actual Table not activated yet. s.hardware.borrow_mut().sp = image.sp() - 64; s.cpu.borrow_mut().nonce = nonce; s.cpu.borrow_mut().registers = Some(model::saved::Backend::expected(image)); } fn main_cooperate(s: &mut System) -> os_k1060_queue::Handle { if s.hardware.borrow().current.is_some() { main_capture(s); } let token = s.waits.os_k1080_main_select().unwrap(); let (token, image, nonce) = s.waits.os_k1080_main_depart(token).ok().unwrap(); main_physical(s, image, nonce); assert!( s.waits .os_k1080_physical_execution() .unwrap() .current .is_some() ); s.waits.os_k1080_main_landed(token).ok().unwrap() } fn main_return(s: &mut System) { let capture = main_capture(s); let token = s.waits.os_k1080_main_return(capture).unwrap(); let (token, frame) = s.waits.os_k1080_main_return_depart(token).ok().unwrap(); assert_eq!(frame.sp, model::bootstrap().sp); s.waits .with_backend_observation(|b| b.with_queue_observation(returned)); s.waits.os_k1080_main_return_landed(token).ok().unwrap(); } #[test] fn main_owned_selection_rejects_old_physical_target_and_retries_same_token() { let mut s = system(); main_capture(&s); let token = s.waits.os_k1080_main_select().unwrap(); let (token, image, nonce) = s.waits.os_k1080_main_depart(token).ok().unwrap(); let inventory = s .waits .with_backend_observation(|b| b.with_queue_observation(ownership)); assert!(s.waits.os_k1080_physical_execution().is_err()); let token = match s.waits.os_k1080_main_landed(token) { Err(os_k1060_queue::HandoffSelectionError::Before(_, t)) => t, _ => panic!("old physical landing admitted"), }; assert_eq!( s.waits .with_backend_observation(|b| b.with_queue_observation(ownership)), inventory ); main_physical(&mut s, image, nonce); let target = s.hardware.borrow().current.unwrap(); assert_eq!( s.waits.os_k1080_physical_execution().unwrap().current, Some(target) ); let h = s.waits.os_k1080_main_landed(token).ok().unwrap(); assert_eq!( s.waits .with_backend_observation(|b| b.with_queue_observation(|q| q .queue() .record(h) .unwrap() .thread)), target ); assert_eq!(state(&s, 0), State::Ready); } #[test] fn main_stage_blocks_other_selection_without_discarding_exact_wait_prepared() { let mut s = system(); let token = arm(&mut s, 0, 1, None); let records = s.waits.records(); let pins = s.ledger.pins.get(); assert!(matches!( s.waits.os_k1080_main_select(), Err(wait::Error::Pending) )); assert_eq!(s.waits.records(), records); assert_eq!(s.ledger.pins.get(), pins); signal(&mut s, 101); let wait::Departure::Ready(token) = s.waits.depart(token).ok().unwrap() else { panic!() }; s.waits.retire(token).ok().unwrap(); assert_eq!(main_cooperate(&mut s), s.handles[1]); } #[test] fn main_pure_cpu_mask_irq_gates_precede_poisoned_real_table_loan() { for bad in 0..3 { let mut s = system(); s.waits.with_backend_observation(|b| { b.with_queue_observation(|q| { q.queue().with_backend_observation(|b| { b.bank.handoff().bank().with_backend_observation(|d| { core::mem::forget(d.inner.table.borrow_mut()) }); }) }) }); match bad { 0 => s.hardware.borrow_mut().cpu = 1, 1 => s.hardware.borrow_mut().daif = 0, _ => s.hardware.borrow_mut().in_irq = true, } assert!(s.waits.os_k1080_main_select().is_err()); assert!(s.waits.os_k1080_thread(0).is_err()); assert!(s.waits.os_k1080_landing_bounds().is_err()); assert_eq!(s.ledger.pins.get(), 0); } } #[test] fn main_two_owned_sleeps_allow_third_progress_and_ready_cooperation_after_one_cancel() { let mut s = system(); let a = sleep(&mut s, 0, 1, None); let b = sleep(&mut s, 1, 2, None); assert_eq!(s.cpu.borrow().wait_takes, 2); assert_eq!(s.ledger.pins.get(), 2); assert_eq!(state(&s, 0), State::Sleeping); assert_eq!(state(&s, 1), State::Sleeping); assert_eq!(state(&s, 2), State::Running); let mut progress = 0u64; for i in 1..=32 { progress = progress.checked_add(i * i).unwrap(); } assert_eq!(progress, 11440); s.waits.cancel(&b).unwrap(); assert_eq!(main_cooperate(&mut s), s.handles[1]); assert_eq!(state(&s, 0), State::Sleeping); assert_eq!(s.ledger.pins.get(), 2); s.waits.retire(b).ok().unwrap(); s.waits.cancel(&a).unwrap(); s.waits.retire(a).ok().unwrap(); assert_eq!(s.cpu.borrow().wait_resolves, 2); assert_eq!(s.ledger.pins.get(), 0); } #[test] fn main_bootstrap_return_refuses_real_terminal_pin_until_actual_retirement() { let mut s = system(); let token = arm(&mut s, 0, 1, None); signal(&mut s, 101); let wait::Departure::Ready(token) = s.waits.depart(token).ok().unwrap() else { panic!() }; let capture = main_capture(&s); let inventory = s .waits .with_backend_observation(|b| b.with_queue_observation(ownership)); assert!(matches!( s.waits.os_k1080_main_return(capture), Err(wait::Error::Pending) )); assert_eq!( s.waits .with_backend_observation(|b| b.with_queue_observation(ownership)), inventory ); assert_eq!(s.ledger.pins.get(), 1); s.waits.retire(token).ok().unwrap(); s.waits.service(&mut s.ingress).unwrap(); main_return(&mut s); assert_eq!(state(&s, 0), State::Dead); assert_eq!(s.hardware.borrow().current, None); assert_eq!(s.ledger.pins.get(), 0); } #[test] fn main_cleanup_retires_exact_real_members_and_all_twelve_modeled_stack_pages() { let mut s = system(); main_return(&mut s); for _ in 0..2 { main_cooperate(&mut s); main_return(&mut s); } assert!(s.waits.os_k1080_cleanup_ready().is_err()); for ordinal in 0..3 { match s.waits.os_k1080_main_retire(ordinal) { Ok(()) => {} Err((e, actual)) => panic!( "retire {ordinal}: {e:?}, member retained={}", actual.is_some() ), } } s.waits.os_k1080_cleanup_ready().unwrap(); assert_eq!( s.waits .with_backend_observation(|b| b.with_queue_observation(ownership)), (0, 0, 0) ); assert_eq!(s.ledger.dropped.get(), 0); } #[test] fn main_successful_wire_callback_drift_keeps_actual_lookup_before_poisoned_owner_read() { let mut s = system(); main_capture(&s); let token = s.waits.os_k1080_main_select().unwrap(); let nonce = token.nonce(); s.cpu.borrow_mut().main_wire_drift = 1; assert!(matches!( s.waits.os_k1080_main_depart(token), Err(os_k1060_queue::HandoffSelectionError::Quarantined(_)) )); assert_eq!(s.hardware.borrow().cpu, 1); assert!(s.waits.with_backend_observation(|b| b.retained_failure())); assert_eq!( s.waits .with_backend_observation(|b| b.os_k1080_retained_selection_nonce()), Some(nonce) ); assert_eq!(s.hardware.borrow().pins, 3); assert_eq!(s.hardware.borrow().stack_pages, 12); } #[test] fn main_successful_bootstrap_wire_drift_keeps_actual_after_lookup_before_poisoned_owner_read() { let mut s = system(); let capture = main_capture(&s); let token = s.waits.os_k1080_main_return(capture).unwrap(); s.cpu.borrow_mut().main_wire_drift = 2; let actual = match s.waits.os_k1080_main_return_depart(token) { Err(turkos_os_k1080_wait_main::bridge::K1080MainReturnFailure::After( wait::Error::Context, actual, )) => actual, _ => panic!("bootstrap drift admitted or falsely called before"), }; assert!(actual.nonce() > 0); assert_eq!(s.hardware.borrow().cpu, 1); assert!(s.waits.with_backend_observation(|b| b.retained_failure())); assert_eq!(s.hardware.borrow().pins, 3); assert_eq!(s.hardware.borrow().stack_pages, 12); } #[test] fn main_inert_old_lookup_refuses_reused_generation_without_resurrecting_consumed_token() { let mut s = system(); let token = arm(&mut s, 0, 1, None); let old = s.waits.os_k1080_inert_lookup(&token).unwrap(); signal(&mut s, 101); let wait::Departure::Ready(token) = s.waits.depart(token).ok().unwrap() else { panic!() }; let generation = token.generation(); s.waits.retire(token).ok().unwrap(); s.waits.service(&mut s.ingress).unwrap(); let token = arm(&mut s, 0, 1, None); assert!(token.generation() > generation); let records = s.waits.records(); let pins = s.ledger.pins.get(); assert_eq!( s.waits.os_k1080_check_old_lookup(&old), Err(wait::Error::Stale) ); assert_eq!(s.waits.records(), records); assert_eq!(s.ledger.pins.get(), pins); s.waits.cancel(&token).unwrap(); s.waits.retire(token).ok().unwrap(); } #[test] fn main_successful_target_root_drift_is_checked_even_when_authority_cpu_mask_current_match() { let mut s = system(); main_capture(&s); let token = s.waits.os_k1080_main_select().unwrap(); let nonce = token.nonce(); s.cpu.borrow_mut().main_wire_drift = 3; assert!(matches!( s.waits.os_k1080_main_depart(token), Err(os_k1060_queue::HandoffSelectionError::Quarantined(_)) )); assert_eq!(s.hardware.borrow().cpu, 0); assert_eq!(s.hardware.borrow().daif, 0x3c0); assert_eq!( s.waits .with_backend_observation(|b| b.os_k1080_retained_selection_nonce()), Some(nonce) ); assert_eq!(s.hardware.borrow().pins, 3); assert_eq!(s.hardware.borrow().stack_pages, 12); } #[test] fn main_successful_bootstrap_root_drift_keeps_after_lookup_even_when_authority_matches() { let mut s = system(); let capture = main_capture(&s); let token = s.waits.os_k1080_main_return(capture).unwrap(); let nonce = token.nonce(); s.cpu.borrow_mut().main_wire_drift = 4; let actual = match s.waits.os_k1080_main_return_depart(token) { Err(turkos_os_k1080_wait_main::bridge::K1080MainReturnFailure::After( wait::Error::Context, actual, )) => actual, _ => panic!("bootstrap root drift admitted"), }; assert_eq!(actual.nonce(), nonce); assert_eq!(s.hardware.borrow().cpu, 0); assert_eq!(s.hardware.borrow().daif, 0x3c0); assert!(s.waits.with_backend_observation(|b| b.retained_failure())); assert_eq!(s.hardware.borrow().pins, 3); assert_eq!(s.hardware.borrow().stack_pages, 12); }