Add pico_tls library providing thread local variable support#2910
Open
kilograham wants to merge 1 commit intodevelopfrom
Open
Add pico_tls library providing thread local variable support#2910kilograham wants to merge 1 commit intodevelopfrom
kilograham wants to merge 1 commit intodevelopfrom
Conversation
* Works on GCC/llvm, newlib/picolibc, Arm/RISC-V
* Provides picolibc style functions for FreeRTOS (and perhaps others to use)
* Attempts to minimize runtime overhead when not used:
- note linker scripts are not competent enough to allow us to elide code
based on the emptiness of sections
- on Arm we have a signal of whether __aeabi_read_tp or __emutls_get_address
are called (we dont use this to change the link, we just do lazy
initializtion from these methods which removes most oof the code if there
are no thread local variables (since the methods aren't ever called and
we use gc-sections)
- on RISC-V theres not much we can do since TP reg is used
- support for resetting thread locals on core 1 re-init is optional
- thread local support can be dialed back if not needed (see below)
* Three types of TLS support are provided:
- per_thread (default) - proper per core (and potentially RTOS task) values for
__thread variables
- global - __thread is supported but only a single shared value is used
- none - programs using __thread may fail to link and runtime results are
undefined
* Note that tdata/tbss source data sections can be used if present
* Note that emutls source data sections can be used if present
* Code will still compile with older linker scripts missing the tls sections
* In either case two linear RAM sections .tls0 and .tls1 are used, and _init_tls
is used to copy the relevant source data from there
* Note .tdata/.tbss sit between .data/.bss so that they are copied/cleared
correctly by crt0. This was the case before, but I've recombined the
separate linker script fragments to make this more concrete
* The CMake build has code to detect emutls vs __aeabi_read_tp on Arm which
allows it to pass defines indicating support is only needed for one type.
Of course, other build systems or pico_clib_interfaces are free to define
these variables too, but they are not required for correct behavior (they
may just save space)
* Note that the code was basde somewhat on earlier separate PRs. Despite
being somewhat related to the c library being used, it is orthogonal
in the pico-sdk code since it really is a compiler decision. If a particular
pico_clib_interface wants to influence the behavior, it can do so via
#defines
PER_THREAD tls mode
- picolibc style tls funcs (_tls_size(), _init_tls()) work based on either
tdata/tbss or emutls source data for the latter the emutls_objects are
walked to figure out a linear size
- two sections .tls0 and .tls1 are added to RAM to hold tdata and tbss
for the two cores
- .tls1 is re-initialized (or rather re-initialization is marked but deferred
via per core runtime_init by default so values are reset on core 1 reset).
There is a define to turn this off to save a tiny amount of space if
not needed
- note that .tbss actually currently wasted space in RAM in this scenario
which is annoying but I think common to most runtimes
- note similarly .tdata need not be in RAM here either as it is not directly
- note w.r.t. to the last two points I don't want to rock the boar
in terms of other code that may use these sections (e.g. other RTOS)
- on RISC-V TP is initialed per core to .tls0 and .tls1
GLOBAL tls mode
- the __aeabi_read_tp() value returned always points at .tdata/.tbss
- RISC-V TP reg is initialized to .tdata./.tbss on core init
- emutls falls back to the c library
- the .tls0 and .tls1 sections are elided from the output via some sorcery
- _tls_size() returns 0 to prevent anyone else allocating space
NONE tls mode
- the .tls0 and .tls1 sections are elided from the output via some sorcery
- no other code is included, so you are left with whatever c library
support there is, but without crt having initialized it correctly. in
other words, it ain't gonna work right!
Co-authored-by: Keith Packard <keithp@keithp.com>
Co-authored-by: Al <alastairpatrick@gmail.com>
Contributor
Author
This was referenced Apr 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PER_THREAD tls mode
GLOBAL tls mode
NONE tls mode