-
Notifications
You must be signed in to change notification settings - Fork 824
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add MemoryAtomicWait32, MemoryAtomicWait64 and MemoryAtomicNotify helper functions #3155
Labels
Milestone
Comments
This was referenced Aug 31, 2022
Merged
ptitSeb
added a commit
that referenced
this issue
Sep 6, 2022
ptitSeb
added a commit
that referenced
this issue
Sep 6, 2022
ptitSeb
added a commit
that referenced
this issue
Nov 22, 2022
ptitSeb
added a commit
that referenced
this issue
Nov 22, 2022
bors bot
added a commit
that referenced
this issue
Nov 29, 2022
3153: SharedMemory & Atomics r=ptitSeb a=ptitSeb # Description Enabled SharedMemory and the Atomics extension proposal - [x] Enable Atomic extension by default - [x] Fix "imports" tests #3154 - [x] Add function for memory.atomic.wait32, memory.atomic.wait64 and memory.atomic.notify opcodes #3155 - [x] Add support for the new wait/notify opcodes in Cranelift compiler #3156 - [x] Add support for the new wait/notify opcodes in LLVM compiler #3157 - [x] Add support for atomic access opcodes in AArch64/Singlepass compiler #3159 - [x] Add support for the new wait/notify opcodes in Singlepass compiler #3158 - [x] Fix Atomic issues on x86_64 Singlepass compiler not related to Wait/Notify opcodes #3161 - [x] Fix Atomic issues on Cranelift compiler not related to Wait/Notify opcodes #3162 - [x] Fix Atomic issues on LLVM compiler not related to Wait/Notify opcodes #3163 - [x] Fix the ticket #3167 on Cranelift For #3304 Co-authored-by: John Sharratt's Shared Account <[email protected]> Co-authored-by: ptitSeb <[email protected]> Co-authored-by: Syrus Akbary <[email protected]>
Merged |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Motivation
To help adding the memory.atomic.wait32, memory.atomic.wait64 and memory.atomic.notify opcode to all compilers, some helper function that will do all the traitment should be coded, similarly to how the GrowMemory and the other complex opcodes are handled
Proposed solution
Functions are defined in
lib/vm/src/libcalls.rs
Expected signature would be
for the memory.atomic.wait32. An alternative for imported_memory might also be needed.
The specs are here: https://github.com/WebAssembly/threads/blob/main/proposals/threads/Overview.md
The relevant part is:
Wait and Notify operators
The notify and wait operators are optimizations over busy-waiting for a value to change. The operators have sequentially consistent ordering.
Both notify and wait operators trap if the effective address of either operator is misaligned or out-of-bounds. Wait operators additionally trap if used on an unshared linear memory. The wait operators require an alignment of their memory access size. The notify operator requires an alignment of 32 bits.
For the web embedding, the agent can also be suspended or woken via the
Atomics.wait
andAtomics.notify
functions respectively. An agent will not be suspended for other reasons, unless all agents in that cluster are also suspended.An agent suspended via
Atomics.wait
can be woken by the WebAssemblymemory.atomic.notify
operator. Similarly, an agent suspended bymemory.atomic.wait32
ormemory.atomic.wait64
can be woken byAtomics.notify
.Wait
The wait operator take three operands: an address operand, an expected value, and a relative timeout in nanoseconds as an
i64
. The return value is0
,1
, or2
, returned as ani32
.If the linear memory is unshared, the wait operation traps. Otherwise, the wait operation begins by performing an atomic load from the given address. If the loaded value is not equal to the expected value, the operator returns 1 ("not-equal"). If the values are equal, the agent is suspended. If the agent is woken, the wait operator returns 0 ("ok"). If the timeout expires before another agent notifies this one, this operator returns 2 ("timed-out"). Note that when the agent is suspended, it will not be spuriously woken. The agent is only woken by
memory.atomic.notify
(orAtomics.notify
in the web embedding).When an agent is suspended, if the number of waiters (including this one) is equal to 232, then trap.
memory.atomic.wait32
: load i32 value, compare to expected (asi32
), and wait for notify at same addressmemory.atomic.wait64
: load i64 value, compare to expected (asi64
), and wait for notify at same addressFor the web embedding,
memory.atomic.wait32
is equivalent in behavior to executing the following:memory
be aWebAssembly.Memory
object for this module.buffer
bememory
(Get
(memory
,"buffer"
)).int32array
beInt32Array
(buffer
).result
beAtomics.wait
(int32array
,address
,expected
,timeout
/ 1e6), whereaddress
,expected
, andtimeout
are the operands to thewait
operator as described above.i32
value as described in the above table: ("ok" ->0
, "not-equal" ->1
, "timed-out" ->2
).memory.atomic.wait64
has no equivalent in ECMAScript as it is currently specified, as there is noInt64Array
type, and an ECMAScriptNumber
cannot represent all values of a 64-bit integer. That said, the behavior can be approximated as follows:memory
be aWebAssembly.Memory
object for this module.buffer
bememory
(Get
(memory
,"buffer"
)).int64array
beInt64Array
, whereInt64Array
is a typed-array constructor that allows 64-bit integer views with an element size of8
.result
beAtomics.wait
(int64array
,address
,expected
,timeout
/ 1e6), whereaddress
,expected
, andtimeout
are the operands to thewait
operator as described above. TheAtomics.wait
operation is modified:ValidateSharedIntegerTypedArray
will fail if the typed-array type is not anInt64Array
.value
is not converted to anInt32
, but kept in a 64-bit integer representation.indexedPosition
is (i
x 8) +offset
i32
value as described in the above table: ("ok" ->0
, "not-equal" ->1
, "timed-out" ->2
).Notify
The notify operator takes two operands: an address operand and a count as an unsigned
i32
. The operation will notify as many waiters as are waiting on the same effective address, up to the maximum as specified bycount
. The operator returns the number of waiters that were woken as an unsignedi32
. Note that if the notify operator is used with an unshared linear memory, the number of waiters will always be zero.memory.atomic.notify
: notifycount
threads waiting on the given address viamemory.atomic.wait32
ormemory.atomic.wait64
For the web embedding,
memory.atomic.notify
is equivalent in behavior to executing the following:- Let
- Let
- Let
- Let
- Return
Wait and Notify operators The notify and wait operators are optimizations over busy-waiting for a value to change. The operators have sequentially consistent ordering.memory
be aWebAssembly.Memory
object for this module.buffer
bememory
(Get
(memory
,"buffer"
)).int32array
beInt32Array
(buffer
).result
beAtomics.notify
(int32array
,address
,count
).result
converted to ani32
.Both notify and wait operators trap if the effective address of either operator is misaligned or out-of-bounds. Wait operators additionally trap if used on an unshared linear memory. The wait operators require an alignment of their memory access size. The notify operator requires an alignment of 32 bits.
For the web embedding, the agent can also be suspended or woken via the Atomics.wait and Atomics.notify functions respectively. An agent will not be suspended for other reasons, unless all agents in that cluster are also suspended.
An agent suspended via Atomics.wait can be woken by the WebAssembly memory.atomic.notify operator. Similarly, an agent suspended by memory.atomic.wait32 or memory.atomic.wait64 can be woken by Atomics.notify.
Wait
The wait operator take three operands: an address operand, an expected value, and a relative timeout in nanoseconds as an i64. The return value is 0, 1, or 2, returned as an i32.
timeout value Behavior
timeout < 0 Never expires
0 <= timeout <= maximum signed i64 value Expires after timeout nanoseconds
Return value Description
0 "ok", woken by another agent in the cluster
1 "not-equal", the loaded value did not match the expected value
2 "timed-out", not woken before timeout expired
If the linear memory is unshared, the wait operation traps. Otherwise, the wait operation begins by performing an atomic load from the given address. If the loaded value is not equal to the expected value, the operator returns 1 ("not-equal"). If the values are equal, the agent is suspended. If the agent is woken, the wait operator returns 0 ("ok"). If the timeout expires before another agent notifies this one, this operator returns 2 ("timed-out"). Note that when the agent is suspended, it will not be spuriously woken. The agent is only woken by memory.atomic.notify (or Atomics.notify in the web embedding).
When an agent is suspended, if the number of waiters (including this one) is equal to 232, then trap.
memory.atomic.wait32: load i32 value, compare to expected (as i32), and wait for notify at same address
memory.atomic.wait64: load i64 value, compare to expected (as i64), and wait for notify at same address
For the web embedding, memory.atomic.wait32 is equivalent in behavior to executing the following:
Let memory be a WebAssembly.Memory object for this module.
Let buffer be memory(Get(memory, "buffer")).
Let int32array be Int32Array(buffer).
Let result be Atomics.wait(int32array, address, expected, timeout / 1e6), where address, expected, and timeout are the operands to the wait operator as described above.
Return an i32 value as described in the above table: ("ok" -> 0, "not-equal" -> 1, "timed-out" -> 2).
memory.atomic.wait64 has no equivalent in ECMAScript as it is currently specified, as there is no Int64Array type, and an ECMAScript Number cannot represent all values of a 64-bit integer. That said, the behavior can be approximated as follows:
Let memory be a WebAssembly.Memory object for this module.
Let buffer be memory(Get(memory, "buffer")).
Let int64array be Int64Array, where Int64Array is a typed-array constructor that allows 64-bit integer views with an element size of 8.
Let result be Atomics.wait(int64array, address, expected, timeout / 1e6), where address, expected, and timeout are the operands to the wait operator as described above. The Atomics.wait operation is modified:
ValidateSharedIntegerTypedArray will fail if the typed-array type is not an Int64Array.
value is not converted to an Int32, but kept in a 64-bit integer representation.
indexedPosition is (i x 8) + offset
Return an i32 value as described in the above table: ("ok" -> 0, "not-equal" -> 1, "timed-out" -> 2).
Notify
The notify operator takes two operands: an address operand and a count as an unsigned i32. The operation will notify as many waiters as are waiting on the same effective address, up to the maximum as specified by count. The operator returns the number of waiters that were woken as an unsigned i32. Note that if the notify operator is used with an unshared linear memory, the number of waiters will always be zero.
memory.atomic.notify: notify count threads waiting on the given address via memory.atomic.wait32 or memory.atomic.wait64
For the web embedding, memory.atomic.notify is equivalent in behavior to executing the following:
Let memory be a WebAssembly.Memory object for this module.
Let buffer be memory(Get(memory, "buffer")).
Let int32array be Int32Array(buffer).
Let result be Atomics.notify(int32array, address, count).
Return result converted to an i32.
The text was updated successfully, but these errors were encountered: