@@ -1232,21 +1232,45 @@ impl ThreadId {
1232
1232
}
1233
1233
}
1234
1234
_ => {
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
+ }
1238
1258
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;
1245
1264
} ;
1246
1265
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
+ }
1250
1274
}
1251
1275
}
1252
1276
}
0 commit comments