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

Define thread local storage conventions #116

Merged
merged 4 commits into from
Jul 19, 2019
Merged
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
46 changes: 46 additions & 0 deletions Linking.md
Original file line number Diff line number Diff line change
Expand Up @@ -528,3 +528,49 @@ threads needs to support both of these proposals.

[passive_segments]: https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md#design
[datacount_section]: https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md#datacount-section

Thread Local Storage
--------------------

Currently, thread-local storage is only supported in the main WASM module
and cannot be accessed outside of it. This corresponds to the ELF local
exec TLS model.

Additionally, thread local storage depends on bulk memory instructions, and
therefore support depends on the bulk memory proposal.

All thread local variables will be merged into one passive segment called
`.tdata`. This section contains the starting values for all TLS variables.
The thread local block of every thread will be initialized with this segment.

In a threaded build, the linker will create:

* an immutable global variable of type `i32` called `__tls_size`.
Its value is the total size of the thread local block for the module,
i.e. the sum of the sizes of all thread local variables plus padding.
This value will be `0` if there are no thread-local variables.
* a mutable global `i32` called `__tls_base`, with a `i32.const 0` initializer.
* a global function called `__wasm_init_tls` with signature `(i32) -> ()`.

To initialize thread-local storage, a thread should do the equivalent of the
following pseudo-code upon startup:

(if (global.get __tls_size) (then
(call __wasm_init_tls (call malloc (global.get __tls_size)))))

`__wasm_init_tls` takes a pointer argument containing the memory block to use
as the thread local storage block of the current thread. It should do nothing if
there are no thread-local variables. Otherwise, the memory block will be
initialized with the passive segment `.tdata` via the `memory.init` instruction.
It will then set `__tls_base` to the address of the memory block passed to
`__wasm_init_tls`.

The relocations for thread local variables shall resolve into offsets relative to
the start of the TLS block. As such, adding the value of `__tls_base` yields the
actual address of the variable. For example, a variable called `tls_var` would
have its address computed as follows:

(i32.add (global.get __tls_base) (i32.const tls_var))

The variable can then be used as normal. Upon thread exit, the runtime should free
the memory allocated for the TLS block.