wasm_wait (wasm v0.1.0)

View Source

memory.atomic.wait and memory.atomic.notify. Read this when a threaded guest is parked and you want to know who is meant to wake it.

A waiting agent parks until another writes the address it is watching and notifies it. On other runtimes this is a futex; here it is an Erlang process blocking in receive, which is the one part of the threads proposal the BEAM makes easier rather than harder.

The race, and why the mailbox settles it

A futex has a famous hazard. The waiter must check the value and then sleep, and a notifier that writes and signals between those two steps signals nobody: the waiter sleeps forever holding a value it already knows is stale. Real implementations close it with a lock around the queue, or with a kernel that performs the compare and the sleep as one operation.

Here the waiter registers before it re-reads the value. A notify arriving after that lands in the waiter's mailbox, and receive finds it whether it arrived before or after the call. There is nothing to lose, because a mailbox is not a signal that can be missed; it is a queue.

Each wait carries a fresh reference, so a notify that arrives after a waiter gave up cannot be mistaken for an answer to that waiter's next wait. The mailbox is swept on the way out either way, so a stale message cannot accumulate.

What is not modelled

Nothing here reorders memory. Every access goes through atomics, which is sequentially consistent, so atomic.fence has nothing to do and the relaxed memory model the proposal permits is not exploited. That is a choice worth naming: an implementation that reordered would be faster and would also make the ordering bugs in guest programs unreproducible.

Summary

Functions

Wake up to Count agents waiting on Addr, answering how many.

Park until notified, the value changes, or the timeout expires.

Functions

notify(MemId, Addr, Count)

-spec notify(term(), non_neg_integer(), non_neg_integer()) -> non_neg_integer().

Wake up to Count agents waiting on Addr, answering how many.

wait(MemId, Addr, Read, TimeoutNs)

-spec wait(term(), non_neg_integer(), fun(() -> integer()), integer()) -> 0 | 1 | 2.

Park until notified, the value changes, or the timeout expires.

Answers 0 if woken, 1 if the value at the address was not the expected one, and 2 if it timed out. A negative timeout means no timeout at all.