WebAssembly / WebAssembly/threads

Revisiting the edge-case semantics of wake

Open
#108 16 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
WebAssembly
Stars
767
Forks
54
PR merge metrics
No merged PRs in 30d

Description

Currently

The current semantics of wake is as follows:

Wake consumes two operands, an i32 address, and an i32 wake count.

The wake count operand is interpreted as a signed value, and the following behaviour occurs based on this value:

wake count value Behavior
wake count < 0 Wake all waiters
wake count == 0 Wake no waiters
wake count > 0 Wake min(wake count, num waiters) waiters

Let num woken be the number of threads woken by this operation.

The result of the wake operation is num woken if num woken can be represented as an i32, and trap otherwise.

Proposal

I propose instead to interpret the wake count operand as an unsigned value, with the following behaviour

wake count value Behavior
--- Wake min(wake count, num waiters) waiters

The result of the wake operation is num woken, which is guaranteed to be representable as an i32.

Reasoning

From discussions in TPAC and elsewhere (https://github.com/WebAssembly/threads/issues/72), there were concerns about the behaviour of the operation when the number of waiting threads is greater than UINT32_MAX. There was also some concern about conformity to JS, but this seems to be a red herring as JS takes a float to represent its wake count, waking all threads if passed ∞, and otherwise clamping the value to max(ToInteger wake count, 0) with no concern for the UINT32_MAX edge-case (link).

Consider that if there really are more than UINT32_MAX waiting threads, neither implementation can wake all of them in one operation (must use a loop), the former because it would trigger a trap, and the latter because the number to wake is not representable.

Polls in previous CGs appear very inconclusive, and focussed on i32 vs i64 representation. I don't have a strong opinion on the representation issue, but I think adding a trap case to the semantics isn't the right approach, and interpreting the num waker argument as signed is slightly rogue.

This all seems to be perfectly theoretical anyway. At least on linux, superficial googling suggests that there are several internal limits that restrict maximum thread numbers to the order of millions, even on 64-bit systems, with a very hard limit of 2^29 due to their implementation of PIDs. Several linux syscalls assume that the number of waiters can be represented using i32. There's also a blogpost on experimentally pushing the envelope in Windows which doesn't get anywhere near 2^32.

This hopefully means that the semantic change won't break anything, as a negative wake count argument will now be interpreted as a ginormous positive one (at least 2^31).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the current wake semantics and proposal in this issue, then review WebAssembly/threads#72 and the linked ECMAScript Atomics.wake reference. Check the historical CG poll notes for prior decisions. Done requires an agreed semantic resolution and corresponding specification updates, but this issue names no implementation files or tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
wasm
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.