@@ -1232,21 +1232,45 @@ impl ThreadId {
12321232 }
12331233 }
12341234 _ => {
1235- use crate :: sync:: { Mutex , PoisonError } ;
1236-
1237- static COUNTER : Mutex <u64 > = Mutex :: new( 0 ) ;
1235+ use crate :: cell:: SyncUnsafeCell ;
1236+ use crate :: hint:: spin_loop;
1237+ use crate :: sync:: atomic:: { Atomic , AtomicBool } ;
1238+ use crate :: thread:: yield_now;
1239+
1240+ // If we don't have a 64-bit atomic we use a small spinlock. We don't use Mutex
1241+ // here as we might be trying to get the current thread id in the global allocator,
1242+ // and on some platforms Mutex requires allocation.
1243+ static COUNTER_LOCKED : Atomic <bool > = AtomicBool :: new( false ) ;
1244+ static COUNTER : SyncUnsafeCell <u64 > = SyncUnsafeCell :: new( 0 ) ;
1245+
1246+ // Acquire lock.
1247+ let mut spin = 0 ;
1248+ while COUNTER_LOCKED . compare_exchange_weak( false , true , Ordering :: Acquire , Ordering :: Relaxed ) . is_err( ) {
1249+ if spin <= 3 {
1250+ for _ in 0 ..( 1 << spin) {
1251+ spin_loop( ) ;
1252+ }
1253+ } else {
1254+ yield_now( ) ;
1255+ }
1256+ spin += 1 ;
1257+ }
12381258
1239- let mut counter = COUNTER . lock( ) . unwrap_or_else( PoisonError :: into_inner) ;
1240- let Some ( id) = counter. checked_add( 1 ) else {
1241- // in case the panic handler ends up calling `ThreadId::new()`,
1242- // avoid reentrant lock acquire.
1243- drop( counter) ;
1244- exhausted( ) ;
1259+ let id;
1260+ // SAFETY: we have an exclusive lock on the counter.
1261+ unsafe {
1262+ id = ( * COUNTER . get( ) ) . saturating_add( 1 ) ;
1263+ ( * COUNTER . get( ) ) = id;
12451264 } ;
12461265
1247- * counter = id;
1248- drop( counter) ;
1249- ThreadId ( NonZero :: new( id) . unwrap( ) )
1266+ // Release the lock.
1267+ COUNTER_LOCKED . store( false , Ordering :: Release ) ;
1268+
1269+ if id == u64 :: MAX {
1270+ exhausted( )
1271+ } else {
1272+ ThreadId ( NonZero :: new( id) . unwrap( ) )
1273+ }
12501274 }
12511275 }
12521276 }
0 commit comments