@@ -1080,46 +1080,70 @@ pub struct ThreadId(NonZeroU64);
10801080impl ThreadId {
10811081 // Generate a new unique thread ID.
10821082 fn new ( ) -> ThreadId {
1083+ /// A permutation function that always maps 0 to 0.
1084+ ///
1085+ /// Ported from <https://www.gkbrk.com/wiki/avalanche-diagram/>.
1086+ /// This permutation is subject to change. **DO NOT** rely on it.
1087+ /// Always treat thread ids as opaque.
1088+ fn permute ( x : u64 ) -> u64 {
1089+ let mut a = x;
1090+ let mut b = 0 ;
1091+ let mut c = 0 ;
1092+ for _ in 0 ..4 {
1093+ b ^= a. wrapping_add ( c) . rotate_left ( 7 ) ;
1094+ c ^= b. wrapping_add ( a) . rotate_left ( 9 ) ;
1095+ a ^= c. wrapping_add ( b) . rotate_left ( 13 ) ;
1096+ }
1097+ a
1098+ }
1099+
10831100 #[ cold]
10841101 fn exhausted ( ) -> ! {
10851102 panic ! ( "failed to generate unique thread ID: bitspace exhausted" )
10861103 }
10871104
1088- cfg_if:: cfg_if! {
1089- if #[ cfg( target_has_atomic = "64" ) ] {
1090- use crate :: sync:: atomic:: { AtomicU64 , Ordering :: Relaxed } ;
1105+ fn generate ( ) -> u64 {
1106+ cfg_if:: cfg_if! {
1107+ if #[ cfg( target_has_atomic = "64" ) ] {
1108+ use crate :: sync:: atomic:: { AtomicU64 , Ordering :: Relaxed } ;
10911109
1092- static COUNTER : AtomicU64 = AtomicU64 :: new( 0 ) ;
1110+ static COUNTER : AtomicU64 = AtomicU64 :: new( 0 ) ;
10931111
1094- let mut last = COUNTER . load( Relaxed ) ;
1095- loop {
1096- let Some ( id) = last. checked_add( 1 ) else {
1097- exhausted( ) ;
1098- } ;
1112+ let mut last = COUNTER . load( Relaxed ) ;
1113+ loop {
1114+ let Some ( id) = last. checked_add( 1 ) else {
1115+ exhausted( ) ;
1116+ } ;
10991117
1100- match COUNTER . compare_exchange_weak( last, id, Relaxed , Relaxed ) {
1101- Ok ( _) => return ThreadId ( NonZeroU64 :: new( id) . unwrap( ) ) ,
1102- Err ( id) => last = id,
1118+ match COUNTER . compare_exchange_weak( last, id, Relaxed , Relaxed ) {
1119+ Ok ( _) => return id,
1120+ Err ( id) => last = id,
1121+ }
11031122 }
1104- }
1105- } else {
1106- use crate :: sync:: { Mutex , PoisonError } ;
1123+ } else {
1124+ use crate :: sync:: { Mutex , PoisonError } ;
11071125
1108- static COUNTER : Mutex <u64 > = Mutex :: new( 0 ) ;
1126+ static COUNTER : Mutex <u64 > = Mutex :: new( 0 ) ;
11091127
1110- let mut counter = COUNTER . lock( ) . unwrap_or_else( PoisonError :: into_inner) ;
1111- let Some ( id) = counter. checked_add( 1 ) else {
1112- // in case the panic handler ends up calling `ThreadId::new()`,
1113- // avoid reentrant lock acquire.
1114- drop( counter) ;
1115- exhausted( ) ;
1116- } ;
1128+ let mut counter = COUNTER . lock( ) . unwrap_or_else( PoisonError :: into_inner) ;
1129+ let Some ( id) = counter. checked_add( 1 ) else {
1130+ // in case the panic handler ends up calling `ThreadId::new()`,
1131+ // avoid reentrant lock acquire.
1132+ drop( counter) ;
1133+ exhausted( ) ;
1134+ } ;
11171135
1118- * counter = id;
1119- drop( counter) ;
1120- ThreadId ( NonZeroU64 :: new( id) . unwrap( ) )
1136+ * counter = id;
1137+ drop( counter) ;
1138+ id
1139+ }
11211140 }
11221141 }
1142+
1143+ // Permute ids to stop users from relying on the exact value of
1144+ // `ThreadId`. Since `generate` never returns zero the id will not
1145+ // be zero either, as `permute` maps zero to itself.
1146+ ThreadId ( NonZeroU64 :: new ( permute ( generate ( ) ) ) . unwrap ( ) )
11231147 }
11241148
11251149 /// This returns a numeric identifier for the thread identified by this
0 commit comments