@@ -25,10 +25,11 @@ terms of the MIT license. A copy of the license can be found in the file
2525// Android,OpenBSD : use pthread locals (MI_TLS_MODEL_PTHREADS). todo: maybe on Android MI_TLS_MODEL_LOCAL is better?
2626// --------------------------------------------------------------------------
2727
28- // static inline void* mi_prim_tls_slot(size_t slot) mi_attr_noexcept; // directly read an entry from the thread local storage (or thread control block)
29- // static inline void mi_prim_tls_slot_set(size_t slot, void* value) mi_attr_noexcept;
28+ // static inline void** mi_prim_thread_pointer(void); // get a pointer to the thread local storage
29+ // static inline void* mi_prim_tls_slot(size_t slot); // directly read an entry from the thread local storage block
30+ // static inline void mi_prim_tls_slot_set(size_t slot, void* value);
3031
31- static inline mi_threadid_t _mi_prim_thread_id (void ) mi_attr_noexcept ; // get a unique id for a thread
32+ static inline mi_threadid_t _mi_prim_thread_id (void ); // get a unique id for a thread
3233static inline mi_theap_t * _mi_theap_default (void ); // the default thread local theap
3334static inline mi_theap_t * _mi_theap_cached (void ); // last used thread local theap using the _heap_ api
3435static inline bool _mi_thread_is_initialized (void ); // a thread is initialized if it has a default theap
@@ -50,123 +51,7 @@ static inline mi_theap_t* _mi_page_associated_theap_peek(mi_page_t* page); //
5051
5152
5253//-------------------------------------------------------------------
53- // Access to TLS (thread local storage) slots.
54- //-------------------------------------------------------------------
55-
56- // On some libc + platform combinations we can directly access a thread-local storage (TLS) slot.
57- // The TLS layout depends on both the OS and libc implementation so we use specific tests for each main platform.
58- // If you test on another platform and it works please send a PR :-)
59- // see also https://akkadia.org/drepper/tls.pdf for more info on the TLS register.
60- //
61- // Note: we would like to prefer `__builtin_thread_pointer()` nowadays instead of using assembly,
62- // but unfortunately we can not detect support reliably (see issue #883)
63- #if (defined(_WIN32 )) || \
64- (defined(__GNUC__ ) && ( \
65- (defined(__GLIBC__ ) && (defined(__x86_64__ ) || defined(__i386__ ) || (defined(__arm__ ) && __ARM_ARCH >= 7 ) || defined(__aarch64__ ) || defined(__riscv ))) \
66- || (defined(__APPLE__ ) && (defined(__x86_64__ ) || defined(__aarch64__ ) || defined(__POWERPC__ ))) \
67- || (defined(__BIONIC__ ) && (defined(__x86_64__ ) || defined(__i386__ ) || (defined(__arm__ ) && __ARM_ARCH >= 7 ) || defined(__aarch64__ ))) \
68- || (defined(__FreeBSD__ ) && (defined(__x86_64__ ) || defined(__i386__ ) || defined(__aarch64__ ))) \
69- || (defined(__OpenBSD__ ) && (defined(__x86_64__ ) || defined(__i386__ ) || defined(__aarch64__ ))) \
70- ))
71-
72- static inline void * mi_prim_tls_slot (size_t slot ) mi_attr_noexcept {
73- void * res ;
74- const size_t ofs = (slot * sizeof (void * ));
75- #if defined(_WIN32 )
76- #if (_M_X64 || _M_AMD64 ) && !defined(_M_ARM64EC )
77- res = (void * )__readgsqword ((unsigned long )ofs ); // direct load at offset from gs
78- #elif _M_IX86 && !defined(_M_ARM64EC )
79- res = (void * )__readfsdword ((unsigned long )ofs ); // direct load at offset from fs
80- #else
81- res = ((void * * )NtCurrentTeb ())[slot ]; MI_UNUSED (ofs );
82- #endif
83- #elif defined(__i386__ )
84- __asm__("movl %%gs:%1, %0" : "=r" (res ) : "m" (* ((void * * )ofs )) : ); // x86 32-bit always uses GS
85- #elif defined(__APPLE__ ) && defined(__x86_64__ )
86- __asm__("movq %%gs:%1, %0" : "=r" (res ) : "m" (* ((void * * )ofs )) : ); // x86_64 macOSX uses GS
87- #elif defined(__x86_64__ ) && (MI_INTPTR_SIZE == 4 )
88- __asm__("movl %%fs:%1, %0" : "=r" (res ) : "m" (* ((void * * )ofs )) : ); // x32 ABI
89- #elif defined(__x86_64__ )
90- __asm__("movq %%fs:%1, %0" : "=r" (res ) : "m" (* ((void * * )ofs )) : ); // x86_64 Linux, BSD uses FS
91- #elif defined(__arm__ )
92- void * * tcb ; MI_UNUSED (ofs );
93- __asm__ volatile ("mrc p15, 0, %0, c13, c0, 3\nbic %0, %0, #3" : "=r" (tcb ));
94- res = tcb [slot ];
95- #elif defined(__aarch64__ )
96- void * * tcb ; MI_UNUSED (ofs );
97- #if defined(__APPLE__ ) // M1, issue #343
98- __asm__ volatile ("mrs %0, tpidrro_el0\nbic %0, %0, #7" : "=r" (tcb ));
99- #else
100- __asm__ volatile ("mrs %0, tpidr_el0" : "=r" (tcb ));
101- #endif
102- res = tcb [slot ];
103- #elif defined(__riscv )
104- void * * tcb ; MI_UNUSED (ofs );
105- __asm__ volatile ("mv %0, tp" : "=r" (tcb ));
106- res = tcb [slot ];
107- #elif defined(__APPLE__ ) && defined(__POWERPC__ ) // ppc, issue #781
108- MI_UNUSED (ofs );
109- res = pthread_getspecific (slot );
110- #else
111- #define MI_HAS_TLS_SLOT 0
112- MI_UNUSED (ofs );
113- res = NULL ;
114- #endif
115- return res ;
116- }
117-
118- #ifndef MI_HAS_TLS_SLOT
119- #define MI_HAS_TLS_SLOT 1
120- #endif
121-
122- // setting a tls slot is only used with TLS_MODEL_FIXED (which is not used by default on any platform)
123- static inline void mi_prim_tls_slot_set (size_t slot , void * value ) mi_attr_noexcept {
124- const size_t ofs = (slot * sizeof (void * ));
125- #if defined(_WIN32 )
126- ((void * * )NtCurrentTeb ())[slot ] = value ; MI_UNUSED (ofs );
127- #elif defined(__i386__ )
128- __asm__("movl %1,%%gs:%0" : "=m" (* ((void * * )ofs )) : "rn" (value ) : ); // 32-bit always uses GS
129- #elif defined(__APPLE__ ) && defined(__x86_64__ )
130- __asm__("movq %1,%%gs:%0" : "=m" (* ((void * * )ofs )) : "rn" (value ) : ); // x86_64 macOS uses GS
131- #elif defined(__x86_64__ ) && (MI_INTPTR_SIZE == 4 )
132- __asm__("movl %1,%%fs:%0" : "=m" (* ((void * * )ofs )) : "rn" (value ) : ); // x32 ABI
133- #elif defined(__x86_64__ )
134- __asm__("movq %1,%%fs:%0" : "=m" (* ((void * * )ofs )) : "rn" (value ) : ); // x86_64 Linux, BSD uses FS
135- #elif defined(__arm__ )
136- void * * tcb ; MI_UNUSED (ofs );
137- __asm__ volatile ("mrc p15, 0, %0, c13, c0, 3\nbic %0, %0, #3" : "=r" (tcb ));
138- tcb [slot ] = value ;
139- #elif defined(__aarch64__ )
140- void * * tcb ; MI_UNUSED (ofs );
141- #if defined(__APPLE__ ) // M1, issue #343
142- __asm__ volatile ("mrs %0, tpidrro_el0\nbic %0, %0, #7" : "=r" (tcb ));
143- #else
144- __asm__ volatile ("mrs %0, tpidr_el0" : "=r" (tcb ));
145- #endif
146- tcb [slot ] = value ;
147- #elif defined(__riscv )
148- void * * tcb ; MI_UNUSED (ofs );
149- __asm__ volatile ("mv %0, tp" : "=r" (tcb ));
150- tcb [slot ] = value ;
151- #elif defined(__APPLE__ ) && defined(__POWERPC__ ) // ppc, issue #781
152- MI_UNUSED (ofs );
153- pthread_setspecific (slot , value );
154- #else
155- MI_UNUSED (ofs ); MI_UNUSED (value );
156- #endif
157- }
158-
159- #endif
160-
161-
162- //-------------------------------------------------------------------
163- // Get a fast unique thread id.
164- //
165- // Getting the thread id should be performant as it is called in the
166- // fast path of `_mi_free` and we specialize for various platforms as
167- // inlined definitions. Regular code should call `init.c:_mi_thread_id()`.
168- // We only require _mi_prim_thread_id() to return a unique id
169- // for each thread (unequal to zero) with the bottom 2 bits clear.
54+ // Access to the thread pointer
17055//-------------------------------------------------------------------
17156
17257// Do we have __builtin_thread_pointer? This would be the preferred way to get a unique thread id
@@ -187,69 +72,122 @@ static inline void mi_prim_tls_slot_set(size_t slot, void* value) mi_attr_noexce
18772 #endif
18873#endif
18974
190- static inline mi_threadid_t __mi_prim_thread_id (void ) mi_attr_noexcept ;
191-
192- static inline mi_threadid_t _mi_prim_thread_id (void ) mi_attr_noexcept {
193- const mi_threadid_t tid = __mi_prim_thread_id ();
194- mi_assert_internal (tid > 1 );
195- mi_assert_internal ((tid & MI_PAGE_FLAG_MASK ) == 0 ); // bottom 2 bits are clear?
196- return tid ;
197- }
198-
199- // Get a unique id for the current thread.
200- #if defined(MI_PRIM_THREAD_ID )
201-
202- static inline mi_threadid_t __mi_prim_thread_id (void ) mi_attr_noexcept {
203- return MI_PRIM_THREAD_ID (); // used for example by CPython for a free threaded build (see python/cpython#115488)
75+ #if defined(MI_PRIM_THREAD_POINTER ) // potential user override
76+ static inline void * * mi_prim_thread_pointer (void ) {
77+ return MI_PRIM_THREAD_POINTER ();
20478}
205-
20679#elif defined(_WIN32 )
207-
208- static inline mi_threadid_t __mi_prim_thread_id (void ) mi_attr_noexcept {
209- // Windows: works on Intel and ARM in both 32- and 64-bit
210- return (uintptr_t )NtCurrentTeb ();
80+ static inline void * * mi_prim_thread_pointer (void ) {
81+ return (void * * )NtCurrentTeb ();
21182}
212-
21383#elif MI_USE_BUILTIN_THREAD_POINTER
214-
215- static inline mi_threadid_t __mi_prim_thread_id (void ) mi_attr_noexcept {
216- // Works on most Unix based platforms with recent compilers
217- return (uintptr_t )__builtin_thread_pointer ();
84+ static inline void * * mi_prim_thread_pointer (void ) {
85+ return __builtin_thread_pointer ();
21886}
87+ #elif defined(__GNUC__ )
88+ #if defined(__aarch64__ )
89+ static inline void * * mi_prim_thread_pointer (void ) {
90+ void * * tcb ;
91+ #if defined(__APPLE__ ) // M1, issue rgb(62, 76, 62)
92+ __asm__ volatile ("mrs %0, tpidrro_el0\nbic %0, %0, #7" : "=r" (tcb ));
93+ #else
94+ __asm__ volatile ("mrs %0, tpidr_el0" : "=r" (tcb ));
95+ #endif
96+ return tcb ;
97+ }
98+ #elif defined(__riscv )
99+ static inline void * * mi_prim_thread_pointer (void ) {
100+ void * * tcb ;
101+ __asm__ volatile ("mv %0, tp" : "=r" (tcb ));
102+ return tcb ;
103+ }
104+ #elif defined(__arm__ )
105+ static inline void * * mi_prim_thread_pointer (void ) {
106+ void * * tcb ;
107+ __asm__ volatile ("mrc p15, 0, %0, c13, c0, 3\nbic %0, %0, #3" : "=r" (tcb ));
108+ return tcb ;
109+ }
110+ #elif defined(__i386__ )
111+ static inline void * * mi_prim_thread_pointer (void ) {
112+ void * * tcb ;
113+ __asm__("movl %%gs:0, %0" : "=r" (tcb ) : : ); // x86 32-bit always uses GS
114+ return tcb ;
115+ }
116+ #elif defined(__x86_64__ )
117+ static inline void * * mi_prim_thread_pointer (void ) {
118+ void * * tcb ;
119+ #if defined(__APPLE__ ) && defined(__x86_64__ )
120+ __asm__("movq %%gs:0, %0" : "=r" (tcb ) : : ); // x86_64 macOSX uses GS
121+ #elif (MI_INTPTR_SIZE == 4 )
122+ __asm__("movl %%fs:0, %0" : "=r" (tcb ) : : ); // x32 ABI
123+ #else
124+ __asm__("movq %%fs:0, %0" : "=r" (tcb ) : : ); // x86_64 Linux, BSD uses FS
125+ #endif
126+ return tcb ;
127+ }
128+ #else
129+ #define MI_NO_THREAD_POINTER (1)
130+ #endif
131+ #elif MI_USE_PTHREADS && defined(__APPLE__ )
132+ static inline void * * mi_prim_thread_pointer (void ) {
133+ return (void * * )pthread_self ();
134+ }
135+ #else
136+ #define MI_NO_THREAD_POINTER (1)
137+ #endif
219138
220- #elif MI_HAS_TLS_SLOT
221-
222- static inline mi_threadid_t __mi_prim_thread_id (void ) mi_attr_noexcept {
223- #if defined(__BIONIC__ )
224- // issue #384, #495: on the Bionic libc (Android), slot 1 is the thread id
225- // see: https://github.com/aosp-mirror/platform_bionic/blob/c44b1d0676ded732df4b3b21c5f798eacae93228/libc/platform/bionic/tls_defines.h#L86
226- return (uintptr_t )mi_prim_tls_slot (1 );
139+ #if !MI_NO_THREAD_POINTER
140+ #define MI_HAS_TLS_SLOT (1)
141+ static inline void * mi_prim_tls_slot (size_t slot ) {
142+ #if defined(_WIN32 )
143+ #if (_M_X64 || _M_AMD64 ) && !defined(_M_ARM64EC )
144+ return (void * )__readgsqword ((unsigned long )(slot * sizeof (void * ))); // direct load at offset from gs
145+ #elif _M_IX86 && !defined(_M_ARM64EC )
146+ return (void * )__readfsdword ((unsigned long )(slot * sizeof (void * ))); // direct load at offset from fs
147+ #else
148+ return mi_prim_thread_pointer ()[slot ];
149+ #endif
227150 #else
228- // in all our other targets, slot 0 is the thread id
229- // glibc: https://sourceware.org/git/?p=glibc.git;a=blob_plain;f=sysdeps/x86_64/nptl/tls.h
230- // apple: https://github.com/apple/darwin-xnu/blob/main/libsyscall/os/tsd.h#L36
231- return (uintptr_t )mi_prim_tls_slot (0 );
151+ return mi_prim_thread_pointer ()[slot ];
232152 #endif
233153}
234154
235- #elif defined(MI_USE_PTHREADS ) && defined(__APPLE__ )
236-
237- // on macOS, pthread_t is pointer
238- static inline mi_threadid_t __mi_prim_thread_id (void ) mi_attr_noexcept {
239- return (uintptr_t )((void * )pthread_self ());
155+ static inline void mi_prim_tls_slot_set (size_t slot , void * value ) {
156+ mi_prim_thread_pointer ()[slot ] = value ;
240157}
158+ #endif
241159
242- #else
243-
244- extern mi_decl_hidden mi_decl_thread void * __mi_thread_id_helper ;
160+ /* ----------------------------------------------------------------------------------------
161+ Get a unique thread-id for a thread
162+ ---------------------------------------------------------------------------------------- */
245163
164+ // Get a unique id for the current thread.
165+ #if defined(MI_PRIM_THREAD_ID )
166+ static inline mi_threadid_t __mi_prim_thread_id (void ) {
167+ return MI_PRIM_THREAD_ID (); // used for example by CPython for a free threaded build (see python/cpython#115488)
168+ }
169+ #elif !MI_NO_THREAD_POINTER
170+ static inline mi_threadid_t __mi_prim_thread_id (void ) {
171+ #if defined(__BIONIC__ )
172+ return (mi_threadid_t )mi_prim_tls_slot (1 );
173+ #else
174+ return (mi_threadid_t )mi_prim_thread_pointer ();
175+ #endif
176+ }
177+ #else
246178// otherwise use portable C, taking the address of a thread local variable (this is still very fast on most platforms).
247- static inline mi_threadid_t __mi_prim_thread_id (void ) mi_attr_noexcept {
179+ extern mi_decl_hidden mi_decl_thread void * __mi_thread_id_helper ;
180+ static inline mi_threadid_t __mi_prim_thread_id (void ) {
248181 return (uintptr_t )& __mi_thread_id_helper ;
249182}
250-
251183#endif
252184
185+ static inline mi_threadid_t _mi_prim_thread_id (void ) {
186+ const mi_threadid_t tid = __mi_prim_thread_id ();
187+ mi_assert_internal (tid > MI_THREADID_DETACHED );
188+ mi_assert_internal ((tid & MI_PAGE_FLAG_MASK ) == 0 ); // bottom 2 bits are clear?
189+ return tid ;
190+ }
253191
254192
255193/* ----------------------------------------------------------------------------------------
0 commit comments