{"id":13872612,"url":"https://github.com/WebAssembly/wasi-threads","last_synced_at":"2025-07-16T02:30:53.035Z","repository":{"id":49409515,"uuid":"494168711","full_name":"WebAssembly/wasi-threads","owner":"WebAssembly","description":null,"archived":false,"fork":false,"pushed_at":"2024-07-17T14:07:57.000Z","size":47,"stargazers_count":134,"open_issues_count":15,"forks_count":8,"subscribers_count":36,"default_branch":"main","last_synced_at":"2024-07-17T17:27:34.398Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"WebAssembly","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/WebAssembly.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-05-19T17:31:09.000Z","updated_at":"2024-07-17T14:08:01.000Z","dependencies_parsed_at":"2024-01-02T09:24:42.921Z","dependency_job_id":"4b55d929-9805-4d29-8e42-c6da5e6658cb","html_url":"https://github.com/WebAssembly/wasi-threads","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":"WebAssembly/wasi-proposal-template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebAssembly%2Fwasi-threads","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebAssembly%2Fwasi-threads/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebAssembly%2Fwasi-threads/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebAssembly%2Fwasi-threads/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/WebAssembly","download_url":"https://codeload.github.com/WebAssembly/wasi-threads/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":214112108,"owners_count":15685297,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-05T23:00:48.127Z","updated_at":"2024-08-05T23:02:21.261Z","avatar_url":"https://github.com/WebAssembly.png","language":"WebAssembly","readme":"# `wasi-threads`\n\nA proposed [WebAssembly System Interface](https://github.com/WebAssembly/WASI)\nAPI to add native thread support.\n\n\u003e __NOTE__: this proposal is considered a legacy proposal, retained for engines\n\u003e that can only support WASI v0.1 (`preview1`). After much debate, future work\n\u003e on threads will happen in the [shared-everything-threads] proposal which adds\n\u003e component model [built-ins] for thread spawning, among other things. The goal\n\u003e is that WASI v0.2 and following will use [shared-everything-threads] (once\n\u003e fully implemented) and this proposal can eventually be removed. In the\n\u003e meantime, users experimenting with this proposal can continue to get help with\n\u003e questions and bugs by opening issues on this repository and tagging various\n\u003e maintainers who plan to continue supporting WASI v0.1 (e.g., @loganek, @yamt,\n\u003e @wenyongh).\n\n[shared-everything-threads]: https://github.com/WebAssembly/shared-everything-threads\n[built-ins]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md#-threads\n\n### Current Phase\n\nPhase 1\n\n### Champions\n\n- [Alexandru Ene](https://github.com/AlexEne)\n\n### Phase 4 Advancement Criteria\n\n_TODO before entering Phase 2._\n\n## Table of Contents\n\n- [Introduction](#introduction)\n- [Goals](#goals)\n- [Non-goals](#non-goals)\n- [API walk-through](#api-walk-through)\n  - [Use case: support various languages](#use-case-support-various-languages)\n  - [Use case: support thread-local storage](#use-case-support-thread-local-storage)\n- [Detailed design discussion](#detailed-design-discussion)\n  - [Design choice: thread IDs](#design-choice-thread-ids)\n  - [Design choice: termination](#design-choice-termination)\n  - [Design choice: pthreads](#design-choice-pthreads)\n  - [Design choice: instance-per-thread](#design-choice-instance-per-thread)\n- [Considered alternatives](#considered-alternatives)\n  - [Alternative: WebAssembly threads](#alternative-webassembly-threads)\n  - [Alternative: wasi-parallel](#alternative-wasi-parallel)\n- [Stakeholder Interest \u0026 Feedback](#stakeholder-interest--feedback)\n- [References \u0026 acknowledgements](#references--acknowledgements)\n\n### Introduction\nThis proposal looks to provide a standard API for thread creation. This is a\nWASI-level proposal that augments the WebAssembly-level [threads proposal]. That\nWebAssembly-level proposal provides the primitives necessary for shared memory,\natomic operations, and wait/notify. This WASI-level proposal solely provides a\nmechanism for spawning threads. Any other thread-like operations (thread\njoining, locking, etc.) will use primitives from the WebAssembly-level proposal.\n\nSome background: browsers already have a mechanism for spawning threads \u0026mdash;\n[Web Workers] \u0026mdash; and the WebAssembly-level proposal avoided specifying how\nthread spawning should occur. This allows other uses of WebAssembly \u0026mdash;\ni.e., outside the browser \u0026mdash; to specify their own mechanism for spawning\nthreads.\n\n[threads proposal]: https://github.com/WebAssembly/threads\n[Web Workers]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers\n\n\n### Goals\n- __`pthreads` support__: the goal of this proposal is to add the missing\n  functions that are required to implement a subset of `pthreads` API. It does\n  not aim to be identical to the `pthreads` API, but one must be able to create\n  threads that operate on a shared Wasm memory while using the WebAssembly\n  atomic instructions to synchronize on memory access.\n\n- __library reuse__: standardizing this API would allow re-use of existing\n  libraries and remove friction when porting projects from native\n  execution contexts to WebAssembly and WASI environments (outside the\n  browsers).\n\n- __future-compatible__: a possible future direction for WebAssembly is towards\n  supporting multiple threads per instance. We aim to expose an API that would\n  be compatible with this future direction.\n\n- __browser polyfills__: for browsers, we aim to provide a way to polyfill this\n  API using Web Workers providing similar functionality to what exists in\n  browsers today.\n\n\n\n### Non-goals\n- __full POSIX compatibity__: this API will not be 100% compatible with all\n  functions and options described by POSIX threads standard.\n\n- __modify core WebAssembly__: the current proposal is limited to the WASI APIs\n  signatures and behavior and does not propose changes to the Wasm instruction\n  set.\n\n\n\n### API walk-through\n\nThe API consists of a single function. In pseudo-code:\n\n```C\nstatus wasi_thread_spawn(thread_start_arg* start_arg);\n```\n\nwhere the `status` is a unique non-negative integer thread ID (TID) of the new\nthread (see [Design choice: thread IDs](#design-choice-thread-ids)) or a\nnegative number representing an error if the host failed to spawn the thread.\nThe host implementing `wasi_thread_spawn` will call a predetermined function\nexport (`wasi_thread_start`) in a new WebAssembly instance. Any necessary\nlocking/signaling/thread-local storage will be implemented using existing\ninstructions available in WebAssembly. Ideally, users will never use\n`wasi_thread_spawn` directly but rather compile their threaded code from a\nlanguage that supports threads (see below).\n\n#### Use case: support various languages\n\nUsing this API, it should be possible to implement threads in languages like:\n- __C__, using the `pthreads` library (see the current work in [wasi-libc])\n- __Rust__, as a part of the `std` library (in the future, e.g., [here])\n\nThe API should be able to support even more languages, but supporting these\ninitially is a good starting point.\n\n[wasi-libc]: https://github.com/WebAssembly/wasi-libc\n[here]: https://github.com/rust-lang/rust/blob/7308c22c6a8d77e82187e290e1f7459870e48d12/library/std/src/sys/wasm/atomics/thread.rs\n\n#### Use case: support thread-local storage\n\nFor languages that implement thread-local storage (TLS), the start argument can\ncontain a language-specific structure with the address and (potentially) the\nlength of a TLS memory region. The host WebAssembly engine will treat this\nargument as an opaque pointer \u0026mdash; it should not introspect these\nlanguage-specific details. In C, e.g., the start function should be a static\ntrampoline-like wrapper (exported as `wasi_thread_start`) that reads the actual\nuser start function out of the start argument and calls this after doing some\nTLS bookkeeping (this is not much different than how C starts threads natively).\n\n\n\n### Detailed design discussion\n\nThreads are tricky to implement. This proposal relies on a specific convention\nin order to work correctly. When instantiating a module which is expected to run\nwith `wasi-threads`, the WASI host must first allocate shared memories to\nsatisfy the module's imports.\n\nUpon a call to `wasi_thread_spawn`, the WASI host must:\n\n1. instantiate the module again \u0026mdash; this child instance will be used for the\n   new thread\n2. in the child instance, import all of the same WebAssembly objects,\n   including the above mentioned shared memories, as the parent\n3. optionally, spawn a new host-level thread (other spawning mechanisms are\n   possible)\n4. calculate a positive, non-duplicate thread ID, `tid`, and return it to the\n   caller; any error in the previous steps is indicated by returning a negative\n   error code.\n5. in the new thread, call the child instance's exported entry function with the\n   thread ID and the start argument: `wasi_thread_start(tid, start_arg)`\n\nA WASI host that implements the above should be able to spawn threads for a\nvariety of languages.\n\n#### Design choice: thread IDs\n\nWhen `wasi_thread_spawn` successfully spawns a thread, it returns a thread ID\n(TID) \u0026mdash; 32-bit integer with several restrictions. TIDs are managed and\nprovided by the WASI host. To avoid leaking information, the host may choose to\nreturn arbitrary TIDs (as opposed to leaking OS TIDs).\n\nValid TIDs fall in the range $[1, 2^{29})$. Some considerations apply:\n- `0` is reserved for compatibility reasons with existing libraries (e.g.,\n  wasi-libc) and must not be returned by `wasi_thread_spawn`\n- the uppermost three bits of a valid TID must always be `0`. The most\n  significant bit is the sign bit and recall that `wasi_thread_spawn` uses\n  negative values to indicate errors. The remaining bits are reserved for\n  compatibility with existing language implementations.\n\n#### Design choice: termination\n\nA `wasi-threads` module initially executes a single thread \u0026mdash; the main\nthread. As `wasi_thread_spawn` is called, more threads begin to execute. Threads\nterminate in the following ways:\n\n- __upon return__ from `wasi_thread_start`, and other threads continue to\n  execute\n- __upon a trap__ in any thread; all threads are immediately terminated\n- __upon a `proc_exit` call__ in any thread; all threads are immediately\n  terminated.\n\n#### Design choice: pthreads\n\nOne of the goals of this API is to be able to support `pthreads` for C compiled\nto WebAssembly. Given a WASI host that implements `thread_spawn` as described\nabove, what responsibility would the C language have (i.e., `libc`) to properly\nimplement `pthreads`?\n\n`pthread_create` must not only call WASI's `wasi_thread_spawn` but is also\nresponsible for setting up the new thread's stack, TLS/TSD space, and updating\nthe `pthread_t` structure. This could be implemented by the following steps\n(ignoring error conditions):\n1. configure a `struct start_args` with the user's `void *(*start_func)(void *)`\n   and `void *start_arg` (as done natively) but also with `pthread_t *thread`\n2. call `malloc` (instead of `mmap`) to allocate TLS/TSD in the shared\n   WebAssembly memory\n3. define a static, exported `wasi_thread_start` function that takes as\n   parameters `int tid` and `void *start_args`\n4. in `pthread_create`, call `wasi_thread_spawn` with the configured\n   `start_args` and use `atomic.wait` to wait for the `start_args-\u003ethread-\u003etid`\n   value to change (note that for web polyfills this may not be necessary since\n   creation of web workers is not synchronous)\n5. now in the child thread: once the WASI host creates the new thread instance\n   and calls `wasi_thread_start`, then a) set `args-\u003ethread-\u003etid` to the\n   host-provided `tid`, b) set the `__wasilibc_pthread_self` global to point to\n   `args-\u003ethread` (this is used by `pthread_self`, e.g.), c) use `atomic.notify`\n   to inform the parent thread that the child now has a `tid`, d) start\n   executing the user's `start_func` with the user's `start_arg` \u0026mdash; at this\n   point the new instance is executing separately in its own thread\n6. back in the parent thread: once it has been notified that the child has\n   recorded its TID, it can safely return with the `pthread_t` structure\n   properly filled out.\n\n`pthread_join` has a similar `wait`/`notify` implementation, but in reverse: the\nparent thread can `wait` on the `thread-\u003ereturn` address to change and the child\nthread can `notify` it of this once the user's start function finishes (i.e., at\nthe end of the `wasi_thread_start` wrapper).\n\nThe remainder of the `pthreads` API can be split up into what can be implemented\nand what can safely be skipped until some later date.\n\n##### What can easily be implemented\n\n- `pthread_self` can use the `__wasilibc_pthread_self` global to return the\n  address to the current thread's `pthread_t` structure; this relies on each\n  thread mapping to a new instance (and thus a new set of globals) \u0026mdash see\n  discussion below on \"instance per thread.\"\n- `pthread_detach` can be implemented by using the flags already present in the\n  `pthread_t` structure.\n- `pthread_mutex_*`, `pthread_rwlock_*`, `pthread_cond_*`, `sem_*` can all be\n  implemented using existing operations in the WebAssembly [threads proposal].\n- thread-specific data (TSD), i.e., functions using `pthread_key_t`, can be\n  implemented using the memory region allocated for the thread in WebAssembly\n  shared memory.\n\n##### What can be skipped\n- `pthread_yield` is a [deprecated] `pthreads` function; `sched_yield` is the\n  right one to use. Since it is unclear how WASI's scheduling should interact\n  with the host's, this can be deferred until someone has a use case for it.\n- `pthread_cancel` allows a parent thread to cancel a child thread; in\n  particular, asynchronous cancellation is difficult (impossible?) to implement\n  without a WebAssembly mechanism to interrupt the child thread and it\n  complicates the entire implementation. It can be left for later.\n\n[deprecated]: https://man7.org/linux/man-pages/man3/pthread_yield.3.html\n\n##### What _has_ been implemented\n\n`wasi-libc` contains an implementation of `pthreads` using\n`wasi-threads`. Various WebAssembly engines support the proposal, including:\nWasmtime, WAMR, Wasmer, toywasm.\n\n#### Design choice: instance-per-thread\n\nA thread spawning mechanism for WebAssembly could be implemented in various\nways: the way chosen here, a cloned \"instance-per-thread,\" is one option. The\nother major option is to share the instance among many threads, as described in\nthe [Weakening WebAssembly] paper. Sharing an instance among many threads, as\ndescribed there, would require:\n - WebAssembly objects (memories, tables, globals, functions) to allow a\n   `shared` attribute\n - the WebAssembly specification to grow a `fork` instruction\n\n[Weakening WebAssembly]: https://www.researchgate.net/publication/336447205_Weakening_WebAssembly\n\nThe \"instance-per-thread\" approach was chosen here because a) it matches the\nthread instantiation model of the browser (also \"instance-per-thread\") and b)\nthe WebAssembly specification changes required for the other approach may take\nsome time to materialize. In the meantime, this proposal allows threaded\nWebAssembly to progress. If in the future the WebAssembly specification were to\nadd a \"many-threads-per-instance\" mechanism, the hope is that the API here\nshould not need to change significantly, though it is unclear how much the\nchanges might be.\n\nThe \"instance-per-thread\" approach chosen here does have its disadvantages:\n* higher memory consumption (each instance is cloned)\n* breaking behavior on non-standard functions such as `dlopen()` that require to\n  modify the function table\n* potential breaking behaviour of existing binaries once a new instruction gets\n  added. This is a low risk because `shared` attributes do not yet exist on\n  globals/tables/etc. having the `shared` attribute in a future WebAssembly spec\n  version is not a likely approach. Most likely, no attributes would be\n  interpreted as `local`/`private` as that would keep the existing behavior for\n  binaries.\n\n\n\n### Considered alternatives\n\n#### Alternative: WebAssembly threads\n\nInstead of exposing threads at the WASI level, thread spawning could be\nspecified in the WebAssembly specification. This is the approach described in\nthe [Weakening WebAssembly] paper. See the [Design choice:\ninstance-per-thread](#design-choice-instance-per-thread) discussion above for\nmore details.\n\n#### Alternative: wasi-parallel\n\n[wasi-parallel] is another WASI proposal which provides a parallel \"for\"\nconstruct, similar to what, e.g., [OpenMP](https://www.openmp.org/) provides.\n[wasi-parallel] spawns `N` threads at a time (though they may not all run\nconcurrently); this API spawns a single thread at a time.\n\n[wasi-parallel]: https://github.com/WebAssembly/wasi-parallel/blob/main/docs/Explainer.md\n\n\n\n### Stakeholder Interest \u0026 Feedback\n\nTODO before entering Phase 3.\n\n\u003c!-- [This should include a list of implementers who have expressed interest in\nimplementing the proposal] --\u003e\n\n\n### References \u0026 acknowledgements\n\nMany thanks for valuable feedback and advice from (alphabetical order):\n* [Amanieu d'Antras](https://github.com/Amanieu)\n* [Andrew Brown](https://github.com/abrown)\n* [Conrad Watt](https://github.com/conrad-watt)\n* [George Kulakowski](https://github.com/kulakowski-wasm)\n* [Nathaniel McCallum](https://github.com/npmccallum)\n* [Petr Penzin](https://github.com/penzn)\n* [Sam Clegg](https://github.com/sbc100)\n* [Wang Xin](https://github.com/xwang98)\n* [Wenyong Huang](https://github.com/wenyongh)\n* Xu Jun\n","funding_links":[],"categories":["WebAssembly"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FWebAssembly%2Fwasi-threads","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FWebAssembly%2Fwasi-threads","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FWebAssembly%2Fwasi-threads/lists"}