1- //! Implementation of `StaticKey ` for Windows.
1+ //! Implementation of `LazyKey ` for Windows.
22//!
33//! Windows has no native support for running destructors so we manage our own
44//! list of destructors to keep track of how to destroy keys. We then install a
1313//! don't reach a fixed point after a short while then we just inevitably leak
1414//! something.
1515//!
16- //! The list is implemented as an atomic single-linked list of `StaticKey `s and
16+ //! The list is implemented as an atomic single-linked list of `LazyKey `s and
1717//! does not support unregistration. Unfortunately, this means that we cannot
18- //! use racy initialization for creating the keys in `StaticKey `, as that could
18+ //! use racy initialization for creating the keys in `LazyKey `, as that could
1919//! result in destructors being missed. Hence, we synchronize the creation of
2020//! keys with destructors through [`INIT_ONCE`](c::INIT_ONCE) (`std`'s
2121//! [`Once`](crate::sync::Once) cannot be used since it might use TLS itself).
@@ -33,26 +33,26 @@ use crate::sync::atomic::{
3333use crate :: sys:: c;
3434use crate :: sys:: thread_local:: guard;
3535
36- type Key = c:: DWORD ;
36+ pub type Key = c:: DWORD ;
3737type Dtor = unsafe extern "C" fn ( * mut u8 ) ;
3838
39- pub struct StaticKey {
39+ pub struct LazyKey {
4040 /// The key value shifted up by one. Since TLS_OUT_OF_INDEXES == DWORD::MAX
4141 /// is not a valid key value, this allows us to use zero as sentinel value
4242 /// without risking overflow.
4343 key : AtomicU32 ,
4444 dtor : Option < Dtor > ,
45- next : AtomicPtr < StaticKey > ,
45+ next : AtomicPtr < LazyKey > ,
4646 /// Currently, destructors cannot be unregistered, so we cannot use racy
4747 /// initialization for keys. Instead, we need synchronize initialization.
4848 /// Use the Windows-provided `Once` since it does not require TLS.
4949 once : UnsafeCell < c:: INIT_ONCE > ,
5050}
5151
52- impl StaticKey {
52+ impl LazyKey {
5353 #[ inline]
54- pub const fn new ( dtor : Option < Dtor > ) -> StaticKey {
55- StaticKey {
54+ pub const fn new ( dtor : Option < Dtor > ) -> LazyKey {
55+ LazyKey {
5656 key : AtomicU32 :: new ( 0 ) ,
5757 dtor,
5858 next : AtomicPtr :: new ( ptr:: null_mut ( ) ) ,
@@ -61,18 +61,7 @@ impl StaticKey {
6161 }
6262
6363 #[ inline]
64- pub unsafe fn set ( & ' static self , val : * mut u8 ) {
65- let r = unsafe { c:: TlsSetValue ( self . key ( ) , val. cast ( ) ) } ;
66- debug_assert_eq ! ( r, c:: TRUE ) ;
67- }
68-
69- #[ inline]
70- pub unsafe fn get ( & ' static self ) -> * mut u8 {
71- unsafe { c:: TlsGetValue ( self . key ( ) ) . cast ( ) }
72- }
73-
74- #[ inline]
75- fn key ( & ' static self ) -> Key {
64+ pub fn force ( & ' static self ) -> Key {
7665 match self . key . load ( Acquire ) {
7766 0 => unsafe { self . init ( ) } ,
7867 key => key - 1 ,
@@ -141,17 +130,28 @@ impl StaticKey {
141130 }
142131}
143132
144- unsafe impl Send for StaticKey { }
145- unsafe impl Sync for StaticKey { }
133+ unsafe impl Send for LazyKey { }
134+ unsafe impl Sync for LazyKey { }
135+
136+ #[ inline]
137+ pub unsafe fn set ( key : Key , val : * mut u8 ) {
138+ let r = unsafe { c:: TlsSetValue ( key, val. cast ( ) ) } ;
139+ debug_assert_eq ! ( r, c:: TRUE ) ;
140+ }
141+
142+ #[ inline]
143+ pub unsafe fn get ( key : Key ) -> * mut u8 {
144+ unsafe { c:: TlsGetValue ( key) . cast ( ) }
145+ }
146146
147- static DTORS : AtomicPtr < StaticKey > = AtomicPtr :: new ( ptr:: null_mut ( ) ) ;
147+ static DTORS : AtomicPtr < LazyKey > = AtomicPtr :: new ( ptr:: null_mut ( ) ) ;
148148
149149/// Should only be called once per key, otherwise loops or breaks may occur in
150150/// the linked list.
151- unsafe fn register_dtor ( key : & ' static StaticKey ) {
151+ unsafe fn register_dtor ( key : & ' static LazyKey ) {
152152 guard:: enable ( ) ;
153153
154- let this = <* const StaticKey >:: cast_mut ( key) ;
154+ let this = <* const LazyKey >:: cast_mut ( key) ;
155155 // Use acquire ordering to pass along the changes done by the previously
156156 // registered keys when we store the new head with release ordering.
157157 let mut head = DTORS . load ( Acquire ) ;
@@ -176,9 +176,9 @@ pub unsafe fn run_dtors() {
176176 let dtor = unsafe { ( * cur) . dtor . unwrap ( ) } ;
177177 cur = unsafe { ( * cur) . next . load ( Relaxed ) } ;
178178
179- // In StaticKey ::init, we register the dtor before setting `key`.
179+ // In LazyKey ::init, we register the dtor before setting `key`.
180180 // So if one thread's `run_dtors` races with another thread executing `init` on the same
181- // `StaticKey `, we can encounter a key of 0 here. That means this key was never
181+ // `LazyKey `, we can encounter a key of 0 here. That means this key was never
182182 // initialized in this thread so we can safely skip it.
183183 if pre_key == 0 {
184184 continue ;
0 commit comments