Skip to content

Check target definitions to see if more should have cfg(target_thread_local) enabled. #91659

Open
@thomcc

Description

@thomcc
Member

Out of curiosity, I ran a script to print out the list of targets where cfg(target_thread_local) (indicating support for #[thread_local]) is not true.

The results (and script) are available here: https://gist.github.com/thomcc/766d76e4da35ce1a73b93ccd548fd143

This looks somewhat wrong to me — I believe several of these should have support for static/linker thread local (or at least __thread/__declspec(thread) has worked there for me). Here are some items in that list which are... fairly suspicious to me.

  • All the x86_64 (and probably other arches) unix ELF targets, like the various BSDs.
  • i686-pc-windows-msvc, x86_64-pc-windows-gnu and i686-pc-windows-gnu
  • aarch64-apple-ios (probably), aarch64-apple-tvos (almost certainly)
  • ...

Playing around with1 clang, gcc, and msvc a bit indicates that (the ones I can easily test of these) should have it, and probably others.

My suspicion is:

  • Some of these are listed as not having thread locals by accident. It seems very easy to forget to change something like this when updating or adding a target
  • Some of these are listed as unsupported because technically we might support very old versions.

If the issue is about old versions, I guess a question would be what should the cfg do in situations where the support is version-dependent...

This sounds like a tricky thing to decide! Worth noting: support for TLS is what caused us to choose 10.7 as the minimum supported version for macOS: #11927, but I guess back then2 we might not have had a #[cfg(target_thread_local)]?.

But if nothing else, libstd probably has more concrete ideas about what it supports, and this causes it to be far more pessimistic in std::thread_local!.

And more concretely: I'm pretty sure if I used #[thread_local] in a malloc, I'd be pretty annoyed if it couldn't support, say, FreeBSD, since I know that at least GCC/Clang support __thread on that target.

Footnotes

  1. I think the correct thing to compare against would be _Thread_local/__thread/__declspec(thread) rather than C++'s thread_local — these don't have ctor/dtor support, and thus map more directly to Rust's #[thread_local]. That said, I don't really see a difference in what I've checked.

  2. I don't feel doing that much spelunking, seems likely that given the numeric gap between the macOS issue and the thread_local issue, that things probably worked very differently!

Activity

thomcc

thomcc commented on Dec 8, 2021

@thomcc
MemberAuthor

@rustbot modify labels: +A-thread-locals +F-thread_local

ChrisDenton

ChrisDenton commented on Dec 8, 2021

@ChrisDenton
Member

Hm, yeah. I'm pretty sure there's no reason for any Windows targets not to support it. Or at least it's very inconsistent that i686-uwp-windows-msvc enables target_thread_local but i686-pc-windows-msvc doesn't. But perhaps there was a historic reason for being cautious here.

Btw, the name of the spec configuration option confused me. I initially overlooked that is_elf_tls can be true on non-elf targets. Perhaps the name should match the feature name? Is renaming possible?

nagisa

nagisa commented on Dec 17, 2021

@nagisa
Member

Porting from the issue just above this comment…

We have a test ui/thread-local/tls.rs which only ignores emscripten targets and uses #[thread_local] unconditionally. This suggests to me that any target we test in CI actually supports #[thread_local] in some shape or form.

added a commit that references this issue on Dec 19, 2021

Rollup merge of rust-lang#92042 - ChrisDenton:msvc-static-tls, r=nagisa

4dbe966
added
O-windowsOperating system: Windows
O-iosOperating system: iOS
O-freebsdOperating system: FreeBSD
O-dragonflyOperating system: DragonFly BSD
O-openbsdOperating system: OpenBSD
O-netbsdOperating system: NetBSD
on Mar 2, 2023
mati865

mati865 commented on Jul 23, 2023

@mati865
Member

Fixing *-windows-gnu requires some skills and time.
Simply adding only has_thread_local: true to the spec will cause binaries to segfault (caught by multiple Rust ui tests) because LLVM uses native TLS and GCC uses emuTLS.
Using has_thread_local: true, force_emulated_tls: true (as it should be) looks better but symbols are not improperly exported. Linking of stage1 libstd will fail with:

  = note: D:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: cannot export _ZN3std11collections4hash3map11RandomState3new4KEYS7__getit5__KEY17h8ff9f85561241dd2E: symbol not found
          D:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: cannot export _ZN3std4sync4mpmc5waker17current_thread_id5DUMMY7__getit5__KEY17h6f5deddc9b6dd8b5E: symbol not found
          D:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: cannot export _ZN3std4sync4mpmc7context7Context4with7CONTEXT7__getit5__KEY17h187f3f20404853d8E: symbol not found
          collect2.exe: error: ld returned 1 exit status

Contents of CGU (codegen-units = 1):

$ nm build/x86_64-pc-windows-gnu/stage1-std/x86_64-pc-windows-gnu/release/deps/std-154d45023a8fc9de.std.2e86e8a7446b6664-cgu.0.rcgu.o | grep __getit
0000000000006e10 R __emutls_t._ZN3std11collections4hash3map11RandomState3new4KEYS7__getit5__KEY17h8ff9f85561241dd2E
0000000000006df8 r __emutls_t._ZN3std2io5stdio14OUTPUT_CAPTURE7__getit5__KEY17hd19b7ce05ba9364eE
0000000000006dd8 R __emutls_t._ZN3std4sync4mpmc5waker17current_thread_id5DUMMY7__getit5__KEY17h6f5deddc9b6dd8b5E
0000000000006de0 R __emutls_t._ZN3std4sync4mpmc7context7Context4with7CONTEXT7__getit5__KEY17h187f3f20404853d8E
00000000000000e0 d __emutls_v._ZN3std10sys_common11thread_info11THREAD_INFO7__getit3VAL17h17909a63c4d176f1E
0000000000000100 d __emutls_v._ZN3std10sys_common11thread_info11THREAD_INFO7__getit5STATE17he8008f109cc934c5E.0
00000000000001a0 D __emutls_v._ZN3std11collections4hash3map11RandomState3new4KEYS7__getit5__KEY17h8ff9f85561241dd2E
0000000000000180 d __emutls_v._ZN3std2io5stdio14OUTPUT_CAPTURE7__getit5__KEY17hd19b7ce05ba9364eE
0000000000000140 D __emutls_v._ZN3std4sync4mpmc5waker17current_thread_id5DUMMY7__getit5__KEY17h6f5deddc9b6dd8b5E
0000000000000160 D __emutls_v._ZN3std4sync4mpmc7context7Context4with7CONTEXT7__getit5__KEY17h187f3f20404853d8E
0000000000000120 d __emutls_v._ZN3std4sync7remutex25current_thread_unique_ptr1X7__getit3VAL17hcfb11cc3f4c31de3E
00000000000000a0 d __emutls_v._ZN3std9panicking11panic_count17LOCAL_PANIC_COUNT7__getit3VAL17hc5769e16fdfac207E.0
00000000000000c0 d __emutls_v._ZN3std9panicking11panic_count17LOCAL_PANIC_COUNT7__getit3VAL17hc5769e16fdfac207E.1
0000000000000078 D __imp__ZN3std11collections4hash3map11RandomState3new4KEYS7__getit5__KEY17h8ff9f85561241dd2E
0000000000000068 D __imp__ZN3std4sync4mpmc5waker17current_thread_id5DUMMY7__getit5__KEY17h6f5deddc9b6dd8b5E
0000000000000070 D __imp__ZN3std4sync4mpmc7context7Context4with7CONTEXT7__getit5__KEY17h187f3f20404853d8E
000000000005e380 t _ZN3std10sys_common11thread_info11THREAD_INFO7__getit7destroy17hd4ee32f75d09ec2fE
0000000000000320 T _ZN3std11collections4hash3map11RandomState3new4KEYS7__getit33__KEY$u7b$$u7b$tls.shim$u7d$$u7d$17h5d7e7145e387a1f5E
                 U _ZN3std11collections4hash3map11RandomState3new4KEYS7__getit5__KEY17h8ff9f85561241dd2E
0000000000000340 T _ZN3std4sync4mpmc5waker17current_thread_id5DUMMY7__getit33__KEY$u7b$$u7b$tls.shim$u7d$$u7d$17h489562b46704f878E
                 U _ZN3std4sync4mpmc5waker17current_thread_id5DUMMY7__getit5__KEY17h6f5deddc9b6dd8b5E
0000000000000360 T _ZN3std4sync4mpmc7context7Context4with7CONTEXT7__getit33__KEY$u7b$$u7b$tls.shim$u7d$$u7d$17h3bc68e75fd1d924dE
                 U _ZN3std4sync4mpmc7context7Context4with7CONTEXT7__getit5__KEY17h187f3f20404853d8E

For this to work Rust would have to not try to export symbols without __emutls decoration and instead export only those with it. Analogical change would have be made for symbols importing and of course dllexport/dllimport has to be taken into account as well.

madsmtm

madsmtm commented on Aug 21, 2024

@madsmtm
Contributor

Thread locals were enabled for all Apple targets in #104385.

@rustbot label -O-ios

ChrisDenton

ChrisDenton commented on Aug 22, 2024

@ChrisDenton
Member

This is enabled for all windows-msvc and windows-gnullvm targets, I believe it's just windows-gnu that's left as far as Windows is concerned.

added
O-windows-gnuToolchain: GNU, Operating system: Windows
and removed
O-windowsOperating system: Windows
on Aug 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-thread-localsArea: Thread local storage (TLS)F-thread_local`#![feature(thread_local)]`O-dragonflyOperating system: DragonFly BSDO-freebsdOperating system: FreeBSDO-netbsdOperating system: NetBSDO-openbsdOperating system: OpenBSDO-windows-gnuToolchain: GNU, Operating system: Windows

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @nagisa@thomcc@mati865@ChrisDenton@madsmtm

        Issue actions

          Check target definitions to see if more should have `cfg(target_thread_local)` enabled. · Issue #91659 · rust-lang/rust