Re: Would an increase to PTHREAD_KEYS_MAX be an example of a FreeBSD ABI change? (lang/rust involved in why I ask)
Date: Thu, 14 May 2026 21:52:45 UTC
On 5/14/26 14:11, Konstantin Belousov wrote: > On Thu, May 14, 2026 at 11:30:10AM -0700, Mark Millard wrote: >> Would an increase to PTHREAD_KEYS_MAX be an example of a FreeBSD ABI change? >> >> >> Why I ask: an active failure for at least rust use on armv7 . . . >> >> The armv7 1.94.0 rust-bootstrap used to try to build 1.95.0 of lang/rust >> for armv7 gets the Thread Local Storage failure "Out of TLS keys". >> >> The same was true for the armv7 1.93.0 rust-bootstrap used to try to >> build the armv7 1.94.0: >> >> <https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=294545> >> (Robert Clausecker, not me.) >> >> >> OpenBSD increased PTHREAD_KEYS_MAX to 512 to avoid getting such "Out of >> TLS keys" failures, not necessarily for armv7 or for building rustc: >> >> <https://github.com/openbsd/src/commit/f90c65410264d8346b711e36bca7ee1f0dde5ca9> >> (2025-11-11) >> >> QUOTE from OpenBSD's commit: >> bump PTHREAD_KEYS_MAX to 512 >> the rust libstd emutls version is using one pthread_key per >> thread-variable. it means the maximum number of thread-variable at a >> time is PTHREAD_KEYS_MAX. >> >> with recent rustc 1.91.0, we start hiting the limit while compiling some >> programs (like sysutils/rustic). >> >> ok robert@ >> "Let's go 512 and hope someone eventually does proper TLS" deraadt@ >> END QUOTE >> >> I think they had 256 previous to the change, not just 128. >> >> (The "libstd emutls version" may not be always involved for rust's >> context? Also: the failure type is apparently not limited to building >> the rust compiler/toolchain. The overall issue is not FreeBSD OS specific.) >> >> >> Note: It appears that the official FreeBSD port-package building for >> armv7 stopped shortly before this started to be an issue. That is why >> fallout reports have not been accumulating for the "out of TLS keys" issue. >> >> >> If increasing PTHREAD_KEYS_MAX is an ABI change, an implication is that >> 14.*-RELEASE and 15.*-RELEASE could not be changed, possibly eliminating >> rust use on armv7 going forward. >> >> >> Note: >> It is my understanding that alternate Thread Local Storage models for >> rust require use of rust-nightly (unstable) builds instead of stable >> rust builds. > > Surely increasing the value would be ABI breaking change, but perhaps > this is the change that we can tolerate. > > OTOH, we do have compiler-supported TLS, so I am at least curious why > Rust doesn't use it. > > For the OTOH . . . https://github.com/rust-lang/rust/issues/29594 is about "Tracking issue for thread_local stabilization #29594" and goes back to 2015 with the most recent comment being on May 14, 2025. It is still not classified as stable. I do not claim to have gone through it all. QUOTE (of google AI results about the issues holding target_thread_local up for stabilization for rust): Key Aspects of the Stabilization Effort Platform Support: The major hurdle is that #[thread_local] translates directly to LLVM's thread_local attribute, which is not supported identically across all platforms. Destructors & Safety: Unlike the stable thread_local! macro, #[thread_local] does not implicitly support destructors on all platforms. Issues arise regarding when the memory is cleaned up. Alternative: The stable alternative is the thread_local! macro, which is safe and manages initialization and destruction, but has higher overhead. Current State As of 2026, the #[thread_local] attribute remains experimental, with efforts focused on defining safe abstractions that handle platform differences and initialization behavior consistently. END QUOTE Additional detail shows up in another google AI result: QUOTE When Rust Uses OS pthreads TLS Keys: Platform Constraints: On platforms lacking native #[thread_local] support (e.g., some embedded systems or specific older Unix versions), Rust falls back to pthread_key_create and pthread_setspecific to implement thread-local storage. Dynamic TLS Initialization: When using thread_local! macros, Rust might use OS-based TLS to manage the initialization of thread-local variables that are not known at compile-time, especially when they need a destructor called upon thread exit. Thread Exit Destructors: If a thread-local variable requires a destructor to run when the thread terminates, Rust often uses pthreads keys because they support associating a destructor function (pthread_key_create) with the TLS value. Internal Library Components: Some components within the standard library (std) use OS TLS to store thread-specific information (e.g., panicking state, thread handles). Caveats and Details Main Thread Limitations: On many Unix systems, when pthread-based TLS is used, destructors for thread-local storage are not run on the main thread when it exits. Performance: Using pthreads keys (pthread_setspecific) is generally slower than #[thread_local] (which uses ELF TLS) because it involves calling into the OS, often allocating memory on the first access. Async Signal Safety: Accessing thread_local! variables is not typically async-signal-safe because they can call into pthread functions which are not safe to use in signal handlers. END QUOTE Reads to me like an effort to find one, clean abstraction to span such a range. Not having found such, the variability and control of it leads to the "unstable" classification where use is only allowed via nightly builds instead of via stable builds. -- === Mark Millard marklmi at yahoo.com