Skip to content
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

[thread-spawn] Allow more function types to be spawned #15

Merged
merged 2 commits into from
Oct 9, 2023

Conversation

abrown
Copy link
Collaborator

@abrown abrown commented Sep 18, 2023

As discussed here, limiting which function types can be spawned is... well, limiting. Previously, only allowing a single i32 parameter meant that toolchains would have to create a closure, likely in shared memory, in order to pass more information to the spawned thread. This would make sense when the implementation uses pthread_create, e.g., but could be limiting in other cases.

Though that discussion never pinpointed any specific languages where this might be a problem, the limit was a bit artificial. I propose we start with a proposal that is as general as possible and whittle down from there. This change allows the spawned function to take any Wasm parameters with the understanding that this moves the complexity from the toolchain to the engine (at least when using pthreads).

We still retain the limitation that the spawned function must not return a value because there is no place to return it to: (a) the thread may start executing long after control flow has progressed from the spawn point and (b) it doesn't seem advisable to me yet to add promises/futures/etc.

@abrown
Copy link
Collaborator Author

abrown commented Sep 18, 2023

cc: @rossberg, I think the right spec notation is likely p_1^n or something like that but hopefully p* is close enough for now.

As discussed [here], limiting which function types can be spawned is...
well, limiting. Previously, only allowing a single `i32` parameter meant
that toolchains would have to create a closure, likely in shared memory,
in order to pass more information to the spawned thread. This would make
sense when the implementation uses `pthread_create`, e.g., but could be
limiting in other cases.

[here]: #3 (comment)

Though that discussion never pinpointed any specific languages where
this might be a problem, the limit was a bit artificial. I propose we
start with a proposal that is as general as possible and whittle down
from there. This change allows the spawned function to take any Wasm
parameters with the understanding that this moves the complexity from
the toolchain to the engine (at least when using pthreads).

We still retain the limitation that the spawned function must not return
a value because there is no place to return it to: (a) the thread may
start executing long after control flow has progressed from the spawn
point and (b) it doesn't seem advisable to me yet to add
promises/futures/etc.
@rossberg
Copy link
Member

I'd probably write v*, since that's the meta variables for values, but it doesn't really matter at this level. (Otherwise it's fine, you don't need any index or superscript, unless there are multiple variables or you care about the length of the sequence.)

| Validation | Valid with type `[i32, i32] -> []`; also, the function referred to must have type `[i32] -> []` and be `shared` |
| Execution | With function index `f` and stack values `n` and `c`, enqueue `n` "parallel" invocations of `f` passing `c`; immediately return |
| Validation | Valid with type `[i32, t*] -> []` when the function referred to has type `[t*] -> []` and is `shared` |
| Execution | With function index `f` and stack values [`n`, `p*`], enqueue `n` "parallel" invocations of `f` passing `p*`; immediately return |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: v* instead of p*

if we have thread.id, then thread.spawn might need to take a separate i32 arg for the ID (note: allowing thread.spawn to create multiple threads would interfere with this somewhat unless we had some mapping convention for the ID).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed that more discussion is needed about the multiple threads; I've been thinking about it and have a couple of ideas.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's what I was thinking last week (should have just written it out!): if we end up going with "thread.spawn creates multiple threads," thread.id could return two values, (1) the i32 arg passed initially and (2) an i32 for its ID within the group. It seemed to me those two values could be efficiently combined (e.g., addition, multiplication, shifting) to get at the thread-local memory for a specific thread, however the toolchain/thread framework might choose to do so.

proposals/thread-spawn/Overview.md Outdated Show resolved Hide resolved
proposals/thread-spawn/Overview.md Outdated Show resolved Hide resolved
execution has already progressed past the `thread.spawn` instruction.
2. _simplicity_: implementation-wise, if engines map `thread.spawn` to OS threads, they may be able
to do less wrapping and unwrapping if `f` expects a single parameter (as do OS threads).
- _no return values_: by preventing return values, this design can avoid adding a "thread" handle
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some design discussion here

maybe we want thread.spawn to be fallible, in which case we need a return value to signal this

some Web platform people may desire a terminate instruction that the spawner can call on a spawned thread, in which case we'd need thread.spawn to return some kind of rudimentary thread handle

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another approach here would be for the toolchain to take responsibility for how this gets communicated to the thread and have the thread end itself; cancelling threads can be a tricky business. There's also the thread.exit idea that might apply here; see "what about exiting a thread?".

proposals/thread-spawn/Overview.md Outdated Show resolved Hide resolved
@abrown abrown merged commit d059a3d into main Oct 9, 2023
@abrown abrown deleted the loosen-function-restrictions branch October 9, 2023 18:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants