@@ -47,6 +47,11 @@ pub struct LazyKey {
4747 once : UnsafeCell < c:: INIT_ONCE > ,
4848}
4949
50+ #[ cold]
51+ fn fail ( ) -> ! {
52+ rtabort ! ( "Unexpected TLS failure" )
53+ }
54+
5055impl LazyKey {
5156 #[ inline]
5257 pub const fn new ( dtor : Option < Dtor > ) -> LazyKey {
@@ -66,9 +71,9 @@ impl LazyKey {
6671 guard:: enable ( ) ;
6772 }
6873
69- match self . key . load ( Acquire ) {
70- 0 => unsafe { self . init ( ) } ,
71- key => key - 1 ,
74+ match self . key . load ( Acquire ) . checked_sub ( 1 ) {
75+ None => unsafe { self . init ( ) } ,
76+ Some ( dec ) => dec ,
7277 }
7378 }
7479
@@ -79,11 +84,13 @@ impl LazyKey {
7984 let r = unsafe {
8085 c:: InitOnceBeginInitialize ( self . once . get ( ) , 0 , & mut pending, ptr:: null_mut ( ) )
8186 } ;
82- assert_eq ! ( r, c:: TRUE ) ;
87+ if r != c:: TRUE {
88+ fail ( )
89+ }
8390
8491 if pending == c:: FALSE {
8592 // Some other thread initialized the key, load it.
86- self . key . load ( Relaxed ) - 1
93+ self . key . load ( Relaxed ) . wrapping_sub ( 1 )
8794 } else {
8895 let key = unsafe { c:: TlsAlloc ( ) } ;
8996 if key == c:: TLS_OUT_OF_INDEXES {
@@ -104,10 +111,12 @@ impl LazyKey {
104111 // and if that sees this write then it will entirely bypass the `InitOnce`. We thus
105112 // need to establish synchronization through `key`. In particular that acquire load
106113 // must happen-after the register_dtor above, to ensure the dtor actually runs!
107- self . key . store ( key + 1 , Release ) ;
114+ self . key . store ( key. wrapping_add ( 1 ) , Release ) ;
108115
109116 let r = unsafe { c:: InitOnceComplete ( self . once . get ( ) , 0 , ptr:: null_mut ( ) ) } ;
110- debug_assert_eq ! ( r, c:: TRUE ) ;
117+ if r != c:: TRUE {
118+ fail ( )
119+ }
111120
112121 key
113122 }
@@ -119,14 +128,16 @@ impl LazyKey {
119128 rtabort ! ( "out of TLS indexes" ) ;
120129 }
121130
122- match self . key . compare_exchange ( 0 , key + 1 , AcqRel , Acquire ) {
131+ match self . key . compare_exchange ( 0 , key. wrapping_add ( 1 ) , AcqRel , Acquire ) {
123132 Ok ( _) => key,
124133 Err ( new) => unsafe {
125134 // Some other thread completed initialization first, so destroy
126135 // our key and use theirs.
127136 let r = c:: TlsFree ( key) ;
128- debug_assert_eq ! ( r, c:: TRUE ) ;
129- new - 1
137+ if r != c:: TRUE {
138+ fail ( )
139+ }
140+ new. wrapping_sub ( 1 )
130141 } ,
131142 }
132143 }
@@ -138,10 +149,6 @@ unsafe impl Sync for LazyKey {}
138149
139150#[ inline]
140151pub unsafe fn set ( key : Key , val : * mut u8 ) {
141- #[ cold]
142- fn fail ( ) -> ! {
143- rtabort ! ( "Failed to set value of thread local" )
144- }
145152 let r = unsafe { c:: TlsSetValue ( key, val. cast ( ) ) } ;
146153 // According to MS documentation, `TlsSetValue` returns zero "if it fails"
147154 if r != c:: TRUE {
@@ -181,22 +188,21 @@ pub unsafe fn run_dtors() {
181188 let mut cur = DTORS . load ( Acquire ) ;
182189 while !cur. is_null ( ) {
183190 let pre_key = unsafe { ( * cur) . key . load ( Acquire ) } ;
184- let dtor = unsafe { ( * cur) . dtor . unwrap ( ) } ;
191+ let dtor = unsafe { rtunwrap ! ( Some , ( * cur) . dtor) } ;
185192 cur = unsafe { ( * cur) . next . load ( Relaxed ) } ;
186193
187194 // In LazyKey::init, we register the dtor before setting `key`.
188195 // So if one thread's `run_dtors` races with another thread executing `init` on the same
189196 // `LazyKey`, we can encounter a key of 0 here. That means this key was never
190197 // initialized in this thread so we can safely skip it.
191- if pre_key == 0 {
198+ let Some ( key ) = pre_key . checked_sub ( 1 ) else {
192199 continue ;
193- }
200+ } ;
201+
194202 // If this is non-zero, then via the `Acquire` load above we synchronized with
195203 // everything relevant for this key. (It's not clear that this is needed, since the
196204 // release-acquire pair on DTORS also establishes synchronization, but better safe than
197205 // sorry.)
198- let key = pre_key - 1 ;
199-
200206 let ptr = unsafe { c:: TlsGetValue ( key) } ;
201207 if !ptr. is_null ( ) {
202208 unsafe {
0 commit comments