Skip to content

Adjust how TLS initialization works#820

Merged
alexcrichton merged 2 commits into
WebAssembly:mainfrom
alexcrichton:refactor-tls
Jul 15, 2026
Merged

Adjust how TLS initialization works#820
alexcrichton merged 2 commits into
WebAssembly:mainfrom
alexcrichton:refactor-tls

Conversation

@alexcrichton

Copy link
Copy Markdown
Collaborator

In reviewing various issues and TLS initialization I was personally left pretty confused. There were more hooks into TLS than I had anticipated and I found them to interact in confusing ways. Notably __copy_tls initializes another thread's TLS pointer but uses the __wasm_init_tls intrinsic which sets the current thread's TLS pointer as well. This means that there was previously a dance that was done to save/restore this as necessary.

I additionally noticed that TLS initialization for WASIp3 is expected to be a bit more expensive than other platforms due to an intrinsic necessary to learn the current TID. This is something that I think would be worthwhile to take off the hot path.

Finally, I felt that the assembly as part of task initialization was doing a bit too much relative to what could be done in C.

Adding all these together, the changes here are:

  • For wasip3 coop threads, sync tasks use the "main thread" TLS setup in the start function. They no longer allocate their own block of TLS storage.
  • For wasip3 coop threads, async tasks now delegate to C to perform stack allocation. TLS is then stored at the top of the stack, and the stack top is returned to assembly to get configured.
  • The __copy_tls function is no longer used on wasip3 targets with coop threads. Task initialization after the changes above no longer used it, and spawned threads now initialize their TLS when they start.
  • The __init_tp function is now deferred as an internal detail of __pthread_self. This is effectively lazy initialization of __pthread_self(). The CRT startup objects thus no longer need this symbol for example.
  • When spawning a thread, assembly only initializes the stack pointer and lets C initialize TLS.
  • A workaround to consider __wasi_coop_thread_start used is removed since I believe it's not necessary as the symbol is referred to by function pointer to pass to an imported function.

Throughout this I've attempted to improve comments here and there. A workaround for #819 is needed temporarily, too. Much of #810 is addressed, but the stack for async tasks is still leaked which'll need fixing.

In reviewing various issues and TLS initialization I was personally left
pretty confused. There were more hooks into TLS than I had anticipated
and I found them to interact in confusing ways. Notably `__copy_tls`
initializes another thread's TLS pointer but uses the `__wasm_init_tls`
intrinsic which sets the current thread's TLS pointer as well. This
means that there was previously a dance that was done to save/restore
this as necessary.

I additionally noticed that TLS initialization for WASIp3 is expected to
be a bit more expensive than other platforms due to an intrinsic
necessary to learn the current TID. This is something that I think would
be worthwhile to take off the hot path.

Finally, I felt that the assembly as part of task initialization was
doing a bit too much relative to what could be done in C.

Adding all these together, the changes here are:

* For wasip3 coop threads, sync tasks use the "main thread" TLS setup in
  the `start` function. They no longer allocate their own block of TLS
  storage.
* For wasip3 coop threads, async tasks now delegate to C to perform
  stack allocation. TLS is then stored at the top of the stack, and the
  stack top is returned to assembly to get configured.
* The `__copy_tls` function is no longer used on wasip3 targets with
  coop threads. Task initialization after the changes above no longer
  used it, and spawned threads now initialize their TLS when they start.
* The `__init_tp` function is now deferred as an internal detail of
  `__pthread_self`. This is effectively lazy initialization of
  `__pthread_self()`. The CRT startup objects thus no longer need this
  symbol for example.
* When spawning a thread, assembly only initializes the stack pointer
  and lets C initialize TLS.
* A workaround to consider `__wasi_coop_thread_start` used is removed
  since I believe it's not necessary as the symbol is referred to by
  function pointer to pass to an imported function.

Throughout this I've attempted to improve comments here and there. A
workaround for WebAssembly#819 is needed temporarily, too. Much of WebAssembly#810 is
addressed, but the stack for async tasks is still leaked which'll need
fixing.
@alexcrichton

Copy link
Copy Markdown
Collaborator Author

r? @TartanLlama

Comment thread libc-top-half/musl/src/env/__init_tls.c Outdated
// TODO(wasip3): should make this constant configurable.
size_t stack_size = get_stack_bounds().size;
if (stack_size == 0)
stack_size = 131072;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we use __default_stacksize instead of the magic number?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I don't see that symbol anywhere in LLVM itself, and I wasn't actually sure that this was available. Does that work for you though?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It's in wasi-libc, declared here and defined here

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Oh wow and living in this file no less, thanks!

@alexcrichton
alexcrichton enabled auto-merge (squash) July 15, 2026 19:31
@alexcrichton
alexcrichton merged commit 7d831af into WebAssembly:main Jul 15, 2026
35 checks passed
@alexcrichton
alexcrichton deleted the refactor-tls branch July 15, 2026 19:38
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.

2 participants