We provide a new API, Atomics.waitAsync, that an agent can use to wait on a shared memory location (to later be awoken by some agent calling Atomics.notify on that location) without waiting synchronously (ie, without blocking). Notably this API is useful in agents whose [[CanBlock]] attribute is false, such as the main thread of a web browser document, but the API is not restricted to such agents.
The API is promise-based. Very high performance is not a requirement, but good performance is desirable.
HostResolveInAgent is an implementation-defined abstract operation that takes three arguments, an agent signifier agentSignifier, a PromiseCapability RecordpromiseCapability, and a value resolution. The host's responsibility is to resolve promiseCapability in the agent signified by agentSignifier with resolution in finite time. The host may delay resolving promiseCapability in agentSignifier, e.g. for resource management reasons, but the promise must eventually be resolved.
1.2 GetWaiterList ( block, i )
A Waiter Record is a Record value used to denote a particular call to Atomics.wait or Atomics.waitAsync. It has fields as defined by Table 1.
If denoting a call to Atomics.waitAsync, the resulting promise, otherwise undefined.
[[Timeout]]
A non-negative Number
The timeout in milliseconds.
[[Result]]
"ok" or "timed-out"
The return value of the call.
A WaiterList is a semantic object that contains an ordered List of those agents that are waiting on a location (block, i) in shared memory; block is a Shared Data Block and i a byte offset into the memory of block. A WaiterList object also optionally contains a Synchronize event denoting the previous leaving of its critical section.Record value used to explain waiting and notification of agents via Atomics.wait, Atomics.waitAsync, and Atomics.notify. It has fields as defined by Table 2.
There can be multiple Waiter Records in a WaiterList with the same agent signifier.
The agent cluster has a store of WaiterList objectsRecords; the store is indexed by (block, i), where block is a Shared Data Block and i a byte offset into the memory of block. WaiterLists are agent-independent: a lookup in the store of WaiterLists by (block, i) will result in the same WaiterList object in any agent in the agent cluster.
Operations on a WaiterList—adding and removing waiting agents, traversing the list of agents, suspending and notifying agents on the list, setting and retrieving the Synchronize event—may only be performed by agents that have entered the WaiterList's critical section.
Note
Conceptually, agents that call either Atomics.wait or Atomics.waitAsync are appended to WaiterList. For calls to Atomics.waitAsync, the appended Waiter Record's [[PromiseCapability]] field contains the Promise returned by the call. For calls to Atomics.wait, the appended Waiter Record's [[PromiseCapability]] field is null.
Waiting agents are notified in FIFO order for fairness. There is a single FIFO queue shared by both synchronous and asynchronous waiters.
The abstract operation GetWaiterList takes two arguments, a Shared Data Blockblock and a nonnegative integeri. It performs the following steps:
The abstract operation AddWaiter takes two arguments, a WaiterListWL and an agent signifier Wa Waiter RecordwaiterRecord. It performs the following steps:
Assert: There is no Waiter Record in WL.[[Waiters]] whose [[PromiseCapability]] field is waiterRecord.[[PromiseCapability]] and [[AgentSignifier]] field is waiterRecord.[[AgentSignifier]].
Add W to the end of the list of waiters in WL.
Append waiterRecord as the last element of WL.[[Waiters]]
If waiterRecord.[[Timeout]] is finite, then in parallel,
The abstract operation RemoveWaiter takes two arguments, a WaiterListWL and an agent signifier Wa Waiter RecordwaiterRecord. It performs the following steps:
Assert: WwaiterRecord is on the list of waiters in WL.[[Waiters]].
Remove WwaiterRecord from the list of waiters inWL.[[Waiters]].
Change this function not to take a timeout argument. Timeouts are now handled in the caller. (Not intended as a normative change.)
1.8 Suspend ( WL, W, timeout )
The abstract operation Suspend takes threetwo arguments, a WaiterListWL,and an agent signifier W, and a nonnegative, non-NaN Number timeout. It performs the following steps:
Assert: W is on the list of waiters.There is a Waiter Record in WL.[[Waiters]] whose [[AgentSignifier]] field is W and whose [[PromiseCapability]] field is undefined.
Perform LeaveCriticalSection(WL) and suspend W for up to timeout milliseconds, performing the combined operation in such a way that a notification that arrives after the critical section is exited but before the suspension takes effect is not lost. W can notify either because the timeout expired or because it wasbe notified explicitly by another agent calling NotifyWaiter(WL, waiterRecord, ...), and not for any other reasons at all.
If W was notified explicitly by another agent calling NotifyWaiter(WL, W), return true.
Return false.
1.9 NotifyWaiter ( WL, WwaiterRecord )
The abstract operation NotifyWaiter takes two arguments,
a WaiterListWL and an agent signifier Wa Waiter RecordwaiterRecord. It performs the following steps:
NOTE: An agent must not access another agent's promise capability in any capacity beyond passing it to the host.
Note
The embedding may delay notifying Wthe agent whose signifier is waiterRecord.[[AgentSignifier]], e.g. for resource management reasons, but Wthat agent must eventually be notified in order to guarantee forward progress.
The abstract operation DoWait takes five arguments, mode which is one of (sync, async), and values typedArray, idnex, value, and timeout. It performs the following steps:
NOTE: There is no special handling of synchronous immediate timeouts. Asynchronous immediate timeouts have special handling in order to fail fast and avoid Promise machinery.