From da6a13f04fb8ad26e80015959fb2134ee95927f1 Mon Sep 17 00:00:00 2001 From: Guanzhong Chen Date: Mon, 15 Jul 2019 17:35:19 -0700 Subject: [PATCH 1/4] Define thread local storage conventions --- Linking.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/Linking.md b/Linking.md index f0365cc..6e43481 100644 --- a/Linking.md +++ b/Linking.md @@ -528,3 +528,43 @@ 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, only the `local-exec` model of thread local storage is defined. + +To use thread local storage, the `bulk-memory` proposal must be enabled. + +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 module will contain: + +* 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`. This will be initialized to + `0` by default. When a thread is created (including the main thread), memory + will be allocated and this global will be initialized with the help of the + function `__wasm_init_tls`. +* a linker-synthesized global function called `__wasm_init_tls`. This function + takes a pointer argument containing the memory address to use as the thread + local storage block of the current thread. If there are no thread-local + variables, this function will do nothing. Otherwise, the memory block will be + initialized with the passive segment `.tdata` via the `memory.init` instruction. + Additionally, `__tls_base` will be set to the value of the pointer argument. + +To use thread-local storage properly, a thread should do the equivalent of the +following pseudo-code upon startup: + +``` +global.get __tls_size +if + global.get __tls_size + call malloc + call __wasm_init_tls +end +``` From 4a89730f14d9187ea0472d6b7fb9bc2c024cf8f8 Mon Sep 17 00:00:00 2001 From: Guanzhong Chen Date: Tue, 16 Jul 2019 10:32:11 -0700 Subject: [PATCH 2/4] Update Linking.md --- Linking.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Linking.md b/Linking.md index 6e43481..21ab203 100644 --- a/Linking.md +++ b/Linking.md @@ -561,10 +561,6 @@ To use thread-local storage properly, a thread should do the equivalent of the following pseudo-code upon startup: ``` -global.get __tls_size -if - global.get __tls_size - call malloc - call __wasm_init_tls -end +(if (global.get __tls_size) (then + (call __wasm_init_tls (call malloc (global.get __tls_size))))) ``` From d7ed645ae3675982dfe9002319b9377606fbcb2a Mon Sep 17 00:00:00 2001 From: Guanzhong Chen Date: Tue, 16 Jul 2019 11:20:41 -0700 Subject: [PATCH 3/4] Update Linking.md --- Linking.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Linking.md b/Linking.md index 21ab203..063596f 100644 --- a/Linking.md +++ b/Linking.md @@ -532,9 +532,12 @@ threads needs to support both of these proposals. Thread Local Storage -------------------- -Currently, only the `local-exec` model of thread local storage is defined. +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 +executable TLS model. -To use thread local storage, the `bulk-memory` proposal must be enabled. +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. From 71b5d9ea62e15d4f3ae966b21b1c3c8c91f097ec Mon Sep 17 00:00:00 2001 From: Guanzhong Chen Date: Tue, 16 Jul 2019 12:40:11 -0700 Subject: [PATCH 4/4] Update Linking.md --- Linking.md | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/Linking.md b/Linking.md index 063596f..db529cf 100644 --- a/Linking.md +++ b/Linking.md @@ -534,7 +534,7 @@ 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 -executable TLS model. +exec TLS model. Additionally, thread local storage depends on bulk memory instructions, and therefore support depends on the bulk memory proposal. @@ -543,27 +543,34 @@ 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 module will contain: +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`. This will be initialized to - `0` by default. When a thread is created (including the main thread), memory - will be allocated and this global will be initialized with the help of the - function `__wasm_init_tls`. -* a linker-synthesized global function called `__wasm_init_tls`. This function - takes a pointer argument containing the memory address to use as the thread - local storage block of the current thread. If there are no thread-local - variables, this function will do nothing. Otherwise, the memory block will be - initialized with the passive segment `.tdata` via the `memory.init` instruction. - Additionally, `__tls_base` will be set to the value of the pointer argument. - -To use thread-local storage properly, a thread should do the equivalent of the +* 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))))) -``` + (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.