v-zhangxiaomeng5 opened a new pull request, #20803: URL: https://github.com/apache/nuttx/pull/20803
A GCC toolchain configured with --disable-tls, the common case for bare metal targets, compiles a thread_local or __thread variable into a call to __emutls_get_address(). The libgcc of such a toolchain is built with the single thread model, so its implementation keeps one copy of each variable for the whole program and every thread reads and writes that same copy. Add an implementation that gives one copy per thread. A pthread key holds the copy of a variable and frees it when the thread exits. A pthread key, however, belongs to one task group, while the __emutls_object that the compiler emits for a variable is a single global object shared by every task group of a flat build, so the key is reached through two levels: * obj->loc.offset holds a task local storage index, allocated once for the variable. * The task local storage holds the pthread key of the task group, created on first use. * The pthread key holds the copy of the variable of the calling thread. The build redirects the calls with the --wrap option of the linker instead of defining the same names, because the symbols of libgcc have external linkage and are part of the link of some configurations whatever the order of the archives is. With CONFIG_DEBUG_LINK_WHOLE_ARCHIVE the emutls.o of libgcc is pulled in unconditionally, and a second definition of __emutls_get_address() would then collide with it. The file is built only for a GNU toolchain that does not use the native thread local storage of NuttX, and only where both the task local storage and the pthread keys are available. Assisted-by: Claude Code:claude-opus-5-5 *Note: Please adhere to [Contributing Guidelines](https://github.com/apache/nuttx/blob/master/CONTRIBUTING.md).* ## Summary A GCC toolchain configured with --disable-tls compiles a thread_local or __thread variable into a call to __emutls_get_address(). The libgcc of such a toolchain is built with the single thread model, so it keeps one copy of each variable for the whole program and every thread reads and writes that same copy, which breaks the meaning of the keyword. This adds libs/libc/tls/tls_emutls.c, which gives one copy per thread. A pthread key holds the copy and frees it when the thread exits. Because a pthread key belongs to one task group while the __emutls_object the compiler emits is a single global object shared by every task group of a flat build, the key is reached through two levels: obj->loc.offset holds a task local storage index allocated once for the variable, and the task local storage holds the pthread key of the task group, created on first use. __emutls_register_common() is provided as well, with the same largest-wins merge as libgcc. ## Impact A thread_local variable now has one copy per thread on a toolchain without native TLS. Known limitation: each variable costs one task local storage slot and one pthread key per task group, so the count is bounded by those two symbols, and a failed task_tls_alloc() is fatal because the caller the compiler emits cannot report an error. ## Testing Built on Ubuntu 22.04.5 (x86_64) with Arm GNU Toolchain 13.2.Rel1 (--disable-tls, the case this targets) and arm-none-eabi-gcc 10.3.1 (--enable-tls), NuttX master and nuttx-apps master. lm3s6965-ek: libc.a contains tls_emutls.o exporting T __wrap___emutls_get_address and T __wrap___emutls_register_common, and both --wrap options appear in LDFLAGS and in build.ninja. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
