Skip to main content

Mailbox

Struct Mailbox 

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

A flow’s inbox, plus (when the owning flow is blocked on Receive / ReceiveMatch / Ask with nothing to read) the parked flow itself.

§Why the flow lives inside its own mailbox while waiting

Internally, a flow is reachable through its FlowId, which resolves (via the runtime’s flow directory) to this Mailbox. Bytecode does not address by Pid anymore (FlowCap): Send / Ask resolve a Cap to a FlowId first, then look up here. Host crate::Runtime::send still uses FlowId directly (trusted).

Storing the blocked Box<Flow> directly in MailboxInner::parked, behind the same mutex that guards the message queue, turns “deliver a message and wake the receiver if it was waiting” into a single critical section — which is what actually prevents the classic lost-wakeup race:

racing without a shared lock:
  receiver: queue.pop() -> None
  sender:   queue.push(msg); wake(receiver)   // receiver isn't parked yet!
  receiver: park()                            // ...and now sleeps forever

with both steps under one mutex (what this type does):
  receiver: lock; queue.pop() -> None; store self in `parked`; unlock
  sender:   lock; parked.take() -> Some(receiver); unlock; wake(receiver)

Because “check the queue” and “become parked” happen atomically with respect to “push and check for a parked receiver”, there is no window where a message can be pushed without either landing in the queue for a later Receive or immediately waking an already-parked one.

Wake only happens when a hop is accepted and matches the waiter. A flow that is already runnable (message queued, nobody parked) does not generate extra scheduler work — no wake storm on every Send.

§Selective wait (ReceiveMatch / Ask)

When parked with a selective (non-Any) filter, only a hop that satisfies the filter wakes the flow. Other hops are appended to the queue (subject to the bound) and the waiter stays parked (FIFO skip, never drop matching semantics).

§Bound

push may return MailboxFull when the policy is Reject and the logical capacity is already occupied and nobody matching is parked. A parked waiter that matches the hop still takes a handoff — that hop never occupies a queue slot.

Implementations§

Source§

impl Mailbox

Source

pub fn new() -> Self

Source

pub fn with_config(config: MailboxConfig) -> Self

Source

pub fn config(&self) -> MailboxConfig

Source

pub fn stats(&self) -> Result<MailboxStats, RuntimeError>

Snapshot of enqueue/dequeue/drop counters plus current occupancy (taken under the mailbox lock, so the depth and the counters describe the same instant).

Source

pub fn push( &self, value: Value, ) -> Result<Result<Delivery, MailboxFull>, RuntimeError>

Push value under the mailbox config.

  1. If a matching waiter is parked → Delivery::Handoff (does not consume a queue slot).
  2. Else enqueue / overflow according to OverflowPolicy.
  3. MailboxFull only for Reject when the queue is already at one of its logical bounds (see MailboxFullReason) — plus the one case no policy can absorb: a hop larger than the whole byte budget.

Mutex poison → RuntimeError (fail-closed).

Source

pub fn try_pop(&self) -> Result<Option<Value>, RuntimeError>

Non-blocking pop of the front hop (classic Receive).

Source

pub fn try_pop_match(&self, tag: u16) -> Result<Option<Value>, RuntimeError>

Non-blocking selective pop by application tag (ReceiveMatch).

Source

pub fn park( &self, flow: Box<Flow>, ) -> Result<Result<WaitEpoch, Box<Flow>>, RuntimeError>

Atomically re-check the queue and, if still empty, store flow as parked (classic Receive — any hop wakes).

Outer Result is infrastructure (mutex poison). Inner Result is the lost-wakeup race: Err(flow) means a message arrived between the worker’s try_pop and this call — resume immediately with the stashed pending message rather than parking forever.

Ok(Ok(epoch)) identifies the park that was installed. A caller arming a ReceiveTimeout deadline must carry that WaitEpoch to Mailbox::take_parked_at, or a late deadline will wake whatever wait happens to be current instead.

Source

pub fn park_match( &self, flow: Box<Flow>, tag: u16, ) -> Result<Result<WaitEpoch, Box<Flow>>, RuntimeError>

Like park, but only a hop with Message.tag == tag ends the wait. Non-matching hops already in the queue are left untouched (FIFO skip).

Source

pub fn take_parked_at( &self, epoch: WaitEpoch, ) -> Result<Option<Box<Flow>>, RuntimeError>

Take the parked flow back out only if epoch is still the current wait, used by the timer when a ReceiveTimeout deadline fires.

None means the deadline lost the race and must do nothing: either a hop already woke that wait, or the flow has since parked on a different Receive that this deadline does not own (see WaitEpoch).

The selective filter is reset only when the flow is actually taken. Clearing it on a stale call would downgrade a live ReceiveMatch / Ask waiter to “any hop wakes me”.

Trait Implementations§

Source§

impl Default for Mailbox

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<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> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
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, <T as TryFrom<U>>::Error>

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.