Skip to content

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

Closed

Description

@thomcc

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

  1. thomcc commented on Dec 8, 2021

    @thomcc
    MemberAuthor

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

  2. 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?

  3. 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.

  4. added a commit that references this issue on Dec 19, 2021
  5. 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
  6. 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.

  7. madsmtm commented on Aug 21, 2024

    @madsmtm
    Member

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

    @rustbot label -O-ios

  8. 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.

  9. added
    O-windows-gnuToolchain: GNU, Operating system: Windows
    and removed
    O-windowsOperating system: Windows
    on Aug 22, 2024
  10. added 2 commits that reference this issue on Oct 1, 2026
    5574894
    2a07cd5
  11. added a commit that references this issue on Oct 2, 2026
    6ec9e21
  12. added a commit that references this issue on Oct 6, 2026
    9100b5c
  13. added a commit that references this issue on Oct 12, 2026
    6531484
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

      Issue actions