Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions design/mvp/CanonicalABI.md
Original file line number Diff line number Diff line change
Expand Up @@ -4939,6 +4939,7 @@ def canon_thread_resume_later(i):
trap_if(not inst.may_leave)
other_thread = inst.threads.get(i)
trap_if(not other_thread.suspended())
assert(current_thread() is not other_thread)
other_thread.resume_later()
return []
```
Expand Down Expand Up @@ -5021,6 +5022,7 @@ def canon_thread_suspend_then_resume(cancellable, i):
trap_if(not thread.task.inst.may_leave)
other_thread = thread.task.inst.threads.get(i)
trap_if(not other_thread.suspended())
assert(current_thread() is not other_thread)
cancelled = thread.suspend_then_resume(cancellable, other_thread)
return [cancelled]
```
Expand Down Expand Up @@ -5052,6 +5054,7 @@ def canon_thread_yield_then_resume(cancellable, i):
trap_if(not thread.task.inst.may_leave)
other_thread = thread.task.inst.threads.get(i)
trap_if(not other_thread.suspended())
assert(current_thread() is not other_thread)
cancelled = thread.yield_then_resume(cancellable, other_thread)
return [cancelled]
```
Expand All @@ -5073,13 +5076,15 @@ validation specifies:
* `$suspend-then-promote` is given type `(func (param $i i32) (result i32))`

Calling `$suspend-then-promote` invokes the following function which loads a
thread at index `$i` from the current component instance's `threads` table and
thread at index `$i` from the current component instance's `threads` table,
trapping on out-of-bounds or if the index of the current thread is passed, and
then calls `Thread.suspend_then_resume` to resume the `other_thread` if it's
`ready` and, in any case, leave the [current thread] suspended.
```python
def canon_thread_suspend_then_promote(cancellable, i):
thread = current_thread()
trap_if(not thread.task.inst.may_leave)
trap_if(i == thread.index)
other_thread = thread.task.inst.threads.get(i)
cancelled = thread.suspend_then_promote(cancellable, other_thread)
return [cancelled]
Expand All @@ -5102,14 +5107,16 @@ validation specifies:
* `$yield-then-promote` is given type `(func (param $i i32) (result i32))`

Calling `$yield-then-promote` invokes the following function which loads a
thread at index `$i` from the current component instance's `threads` table and
thread at index `$i` from the current component instance's `threads` table,
trapping on out-of-bounds or if the index of the current thread is passed, and
then calls `Thread.yield_then_resume` to resume the `other_thread` if it's
`ready` and, in any case, leave the [current thread] ready to run at some
nondeterministic point in the future chosen by the embedder.
```python
def canon_thread_yield_then_promote(cancellable, i):
thread = current_thread()
trap_if(not thread.task.inst.may_leave)
trap_if(i == thread.index)
other_thread = thread.task.inst.threads.get(i)
cancelled = thread.yield_then_promote(cancellable, other_thread)
return [cancelled]
Expand Down
45 changes: 25 additions & 20 deletions design/mvp/Explainer.md
Original file line number Diff line number Diff line change
Expand Up @@ -2191,8 +2191,9 @@ For details, see [Thread Built-ins] in the concurrency explainer and
| Canonical ABI signature | `[t:i32] -> []` |

The `thread.resume-later` built-in changes the state of thread `t` from
"suspended" to "ready" (trapping if `t` is not in a "suspended" state) so that
the runtime can nondeterministically resume `t` at some point in the future.
"suspended" to "ready" (trapping if `t` is not in a "suspended" state, including
if `t` is the current thread) so that the runtime can nondeterministically
resume `t` at some point in the future.

For details, see [Thread Built-ins] in the concurrency explainer and
[`canon_thread_resume_later`] in the Canonical ABI explainer.
Expand Down Expand Up @@ -2239,9 +2240,10 @@ For details, see [Thread Built-ins] in the concurrency explainer and

The `thread.suspend-then-resume` built-in suspends the [current thread] and
immediately resumes execution of the thread `t`, trapping if `t` is not in a
"suspended" state. If `cancellable` is set, `thread.suspend-then-resume` returns
whether the current task was [cancelled] by the caller; otherwise,
`thread.suspend-then-resume` always returns `false`.
"suspended" state, which includes if `t` is the current thread. If `cancellable`
is set, `thread.suspend-then-resume` returns whether the current task was
[cancelled] by the caller; otherwise, `thread.suspend-then-resume` always
returns `false`.

For details, see [Thread Built-ins] in the concurrency explainer and
[`canon_thread_suspend_then_resume`] in the Canonical ABI explainer.
Expand All @@ -2254,11 +2256,12 @@ For details, see [Thread Built-ins] in the concurrency explainer and
| Canonical ABI signature | `[t:i32] -> [i32]` |

The `thread.yield-then-resume` built-in immediately resumes execution of the
thread `t` (trapping if `t` is not in a "suspended" state), leaving the [current
thread] in a "ready" state so that the runtime can nondeterministically resume
the current thread at some point in the future. If `cancellable` is set,
`thread.yield-then-resume` returns whether the current task was [cancelled] by
the caller; otherwise, `thread.yield-then-resume` always returns `false`.
thread `t` (trapping if `t` is not in a "suspended" state, which includes if `t`
is the current thread), leaving the [current thread] in a "ready" state so that
the runtime can nondeterministically resume the current thread at some point in
the future. If `cancellable` is set, `thread.yield-then-resume` returns whether
the current task was [cancelled] by the caller; otherwise,
`thread.yield-then-resume` always returns `false`.

For details, see [Thread Built-ins] in the concurrency explainer and
[`canon_thread_yield_then_resume`] in the Canonical ABI explainer.
Expand All @@ -2270,11 +2273,12 @@ For details, see [Thread Built-ins] in the concurrency explainer and
| Approximate WIT signature | `func<cancellable?>(t: thread) -> bool` |
| Canonical ABI signature | `[t:i32] -> [i32]` |

The `thread.suspend-then-promote` built-in immediately resumes execution of the
thread `t` if `t` is in a "ready" state, in any case leaving the current thread
in a "suspended" state. If `cancellable` is set, `thread.suspend-then-promote`
returns whether the current task was [cancelled] by the caller; otherwise,
`thread.suspend-then-promote` always returns `false`.
The `thread.suspend-then-promote` built-in traps if `t` is the current thread
and, otherwise, immediately resumes execution of the thread `t` if `t` is in a
"ready" state, in any case leaving the current thread in a "suspended" state. If
`cancellable` is set, `thread.suspend-then-promote` returns whether the current
task was [cancelled] by the caller; otherwise, `thread.suspend-then-promote`
always returns `false`.

For details, see [Thread Built-ins] in the concurrency explainer and
[`canon_thread_suspend_then_promote`] in the Canonical ABI explainer.
Expand All @@ -2286,11 +2290,12 @@ For details, see [Thread Built-ins] in the concurrency explainer and
| Approximate WIT signature | `func<cancellable?>(t: thread) -> bool` |
| Canonical ABI signature | `[t:i32] -> [i32]` |

The `thread.yield-then-promote` built-in immediately resumes execution of the
thread `t` if `t` is in a "ready" state, in any case leaving the current thread
in a "ready" state. If `cancellable` is set, `thread.yield-then-promote` returns
whether the current task was [cancelled] by the caller; otherwise,
`thread.yield-then-promote` always returns `false`.
The `thread.yield-then-promote` built-in traps if `t` is the current thread
and, otherwise, immediately resumes execution of the thread `t` if `t` is in a
"ready" state, in any case leaving the current thread in a "ready" state. If
`cancellable` is set, `thread.yield-then-promote` returns whether the current
task was [cancelled] by the caller; otherwise, `thread.yield-then-promote`
always returns `false`.

For details, see [Thread Built-ins] in the concurrency explainer and
[`canon_thread_yield_then_promote`] in the Canonical ABI explainer.
Expand Down
12 changes: 5 additions & 7 deletions design/mvp/canonical-abi/definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2363,13 +2363,6 @@ def canon_context_set(t, i, v):
thread.storage[i] = v
return []

### 🔀 `canon backpressure.set`

def canon_backpressure_set(flat_args):
assert(len(flat_args) == 1)
current_instance().backpressure = int(bool(flat_args[0]))
return []

### 🔀 `canon backpressure.{inc,dec}`

def canon_backpressure_inc():
Expand Down Expand Up @@ -2719,6 +2712,7 @@ def canon_thread_resume_later(i):
trap_if(not inst.may_leave)
other_thread = inst.threads.get(i)
trap_if(not other_thread.suspended())
assert(current_thread() is not other_thread)
other_thread.resume_later()
return []

Expand All @@ -2745,6 +2739,7 @@ def canon_thread_suspend_then_resume(cancellable, i):
trap_if(not thread.task.inst.may_leave)
other_thread = thread.task.inst.threads.get(i)
trap_if(not other_thread.suspended())
assert(current_thread() is not other_thread)
cancelled = thread.suspend_then_resume(cancellable, other_thread)
return [cancelled]

Expand All @@ -2755,6 +2750,7 @@ def canon_thread_yield_then_resume(cancellable, i):
trap_if(not thread.task.inst.may_leave)
other_thread = thread.task.inst.threads.get(i)
trap_if(not other_thread.suspended())
assert(current_thread() is not other_thread)
cancelled = thread.yield_then_resume(cancellable, other_thread)
return [cancelled]

Expand All @@ -2763,6 +2759,7 @@ def canon_thread_yield_then_resume(cancellable, i):
def canon_thread_suspend_then_promote(cancellable, i):
thread = current_thread()
trap_if(not thread.task.inst.may_leave)
trap_if(i == thread.index)
other_thread = thread.task.inst.threads.get(i)
cancelled = thread.suspend_then_promote(cancellable, other_thread)
return [cancelled]
Expand All @@ -2772,6 +2769,7 @@ def canon_thread_suspend_then_promote(cancellable, i):
def canon_thread_yield_then_promote(cancellable, i):
thread = current_thread()
trap_if(not thread.task.inst.may_leave)
trap_if(i == thread.index)
other_thread = thread.task.inst.threads.get(i)
cancelled = thread.yield_then_promote(cancellable, other_thread)
return [cancelled]
Expand Down
52 changes: 52 additions & 0 deletions test/async/self-switch-traps.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
;; Passing the index of the current thread to the four switch-to-another-thread
;; built-ins thread.{suspend,yield}-then-{resume,promote} traps
(component definition $Tester
(core module $Core
(import "" "thread.index" (func $thread-index (result i32)))
(import "" "thread.suspend-then-resume" (func $thread.suspend-then-resume (param i32) (result i32)))
(import "" "thread.yield-then-resume" (func $thread.yield-then-resume (param i32) (result i32)))
(import "" "thread.suspend-then-promote" (func $thread.suspend-then-promote (param i32) (result i32)))
(import "" "thread.yield-then-promote" (func $thread.yield-then-promote (param i32) (result i32)))
(func (export "trap-if-suspend-then-resume-self")
(drop (call $thread.suspend-then-resume (call $thread-index)))
unreachable
)
(func (export "trap-if-yield-then-resume-self")
(drop (call $thread.yield-then-resume (call $thread-index)))
unreachable
)
(func (export "trap-if-suspend-then-promote-self")
(drop (call $thread.suspend-then-promote (call $thread-index)))
unreachable
)
(func (export "trap-if-yield-then-promote-self")
(drop (call $thread.yield-then-promote (call $thread-index)))
unreachable
)
)
(canon thread.index (core func $thread.index))
(canon thread.suspend-then-resume (core func $thread.suspend-then-resume))
(canon thread.yield-then-resume (core func $thread.yield-then-resume))
(canon thread.suspend-then-promote (core func $thread.suspend-then-promote))
(canon thread.yield-then-promote (core func $thread.yield-then-promote))
(core instance $core (instantiate $Core (with "" (instance
(export "thread.index" (func $thread.index))
(export "thread.suspend-then-resume" (func $thread.suspend-then-resume))
(export "thread.yield-then-resume" (func $thread.yield-then-resume))
(export "thread.suspend-then-promote" (func $thread.suspend-then-promote))
(export "thread.yield-then-promote" (func $thread.yield-then-promote))
))))
(func (export "trap-if-suspend-then-resume-self") (canon lift (core func $core "trap-if-suspend-then-resume-self")))
(func (export "trap-if-yield-then-resume-self") (canon lift (core func $core "trap-if-yield-then-resume-self")))
(func (export "trap-if-suspend-then-promote-self") (canon lift (core func $core "trap-if-suspend-then-promote-self")))
(func (export "trap-if-yield-then-promote-self") (canon lift (core func $core "trap-if-yield-then-promote-self")))
)

(component instance $i $Tester)
(assert_trap (invoke "trap-if-suspend-then-resume-self") "cannot resume thread which is not suspended")
(component instance $i $Tester)
(assert_trap (invoke "trap-if-yield-then-resume-self") "cannot resume thread which is not suspended")
(component instance $i $Tester)
(assert_trap (invoke "trap-if-suspend-then-promote-self") "cannot resume thread which is not suspended") ;; TODO: will need to update error string
(component instance $i $Tester)
(assert_trap (invoke "trap-if-yield-then-promote-self") "cannot resume thread which is not suspended") ;; TODO: will need to update error string
Loading
Loading