@@ -1080,46 +1080,70 @@ pub struct ThreadId(NonZeroU64);
1080
1080
impl ThreadId {
1081
1081
// Generate a new unique thread ID.
1082
1082
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
+
1083
1100
#[ cold]
1084
1101
fn exhausted ( ) -> ! {
1085
1102
panic ! ( "failed to generate unique thread ID: bitspace exhausted" )
1086
1103
}
1087
1104
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 } ;
1091
1109
1092
- static COUNTER : AtomicU64 = AtomicU64 :: new( 0 ) ;
1110
+ static COUNTER : AtomicU64 = AtomicU64 :: new( 0 ) ;
1093
1111
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
+ } ;
1099
1117
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
+ }
1103
1122
}
1104
- }
1105
- } else {
1106
- use crate :: sync:: { Mutex , PoisonError } ;
1123
+ } else {
1124
+ use crate :: sync:: { Mutex , PoisonError } ;
1107
1125
1108
- static COUNTER : Mutex <u64 > = Mutex :: new( 0 ) ;
1126
+ static COUNTER : Mutex <u64 > = Mutex :: new( 0 ) ;
1109
1127
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
+ } ;
1117
1135
1118
- * counter = id;
1119
- drop( counter) ;
1120
- ThreadId ( NonZeroU64 :: new( id) . unwrap( ) )
1136
+ * counter = id;
1137
+ drop( counter) ;
1138
+ id
1139
+ }
1121
1140
}
1122
1141
}
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 ( ) )
1123
1147
}
1124
1148
1125
1149
/// This returns a numeric identifier for the thread identified by this
0 commit comments