Expand description
Phase 104.E.3 — cross-priority handoff queue.
Bridges that span priority boundaries (sub callback at
priority A, pub callback at priority B) need a bounded
handoff queue between the two so the high-priority sub
doesn’t block on the lower-priority pub’s transport drain.
The existing pattern is Arc<Mutex<heapless::Vec<M, N>>> +
a timer-driven pub; this module wraps it in a small
Handoff<M, N> type so bridge code stays terse.
Optional sugar — the manual pattern remains supported. The spec (Phase 104.E.3) explicitly lists this as “optional” convenience to avoid forcing every bridge to use the same shape.
use nros_node::executor::handoff::Handoff;
use std::sync::Arc;
// Shared bounded queue, N = 32, message type M.
let q: Arc<Handoff<MyMsg, 32>> = Arc::new(Handoff::new());
// High-priority ingress: push into the queue inside the
// sub callback. `push` is non-blocking — overflow returns
// `Err(msg)` so the high-pri side never stalls.
let q_pub = Arc::clone(&q);
executor.register_subscription::<MyMsg, _>(topic, move |msg: &MyMsg| {
let _ = q_pub.push(msg.clone()); // drop on overflow
})?;
// Low-priority egress: timer drains the queue + publishes.
let q_sub = Arc::clone(&q);
let pub_out = ...;
executor.register_timer(period, move || {
while let Some(msg) = q_sub.pop() {
let _ = pub_out.publish(&msg);
}
})?;Cross-priority safety: every push / pop takes the
internal mutex for the duration of one queue slot
operation (O(1)). On PiCAS-aware dispatchers (Phase 110.F)
the mutex inherits the holder’s effective priority, so
the low-pri drain doesn’t priority-invert the high-pri
push.
std-gated for now — the alloc-only path needs a
lock-free SPSC queue (heapless::spsc requires a .split()
call that doesn’t compose with Arc-sharing across
callbacks). Tracked under follow-up if no_std bridges
become a use case.
Structs§
- Handoff
- Bounded FIFO between two callbacks running on different
SchedContexts. Generic over message typeM(must beSendfor cross-thread executors) and capacityN.