1
- //! Implementation of `StaticKey ` for Windows.
1
+ //! Implementation of `LazyKey ` for Windows.
2
2
//!
3
3
//! Windows has no native support for running destructors so we manage our own
4
4
//! list of destructors to keep track of how to destroy keys. We then install a
13
13
//! don't reach a fixed point after a short while then we just inevitably leak
14
14
//! something.
15
15
//!
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
17
17
//! 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
19
19
//! result in destructors being missed. Hence, we synchronize the creation of
20
20
//! keys with destructors through [`INIT_ONCE`](c::INIT_ONCE) (`std`'s
21
21
//! [`Once`](crate::sync::Once) cannot be used since it might use TLS itself).
@@ -33,26 +33,26 @@ use crate::sync::atomic::{
33
33
use crate :: sys:: c;
34
34
use crate :: sys:: thread_local:: guard;
35
35
36
- type Key = c:: DWORD ;
36
+ pub type Key = c:: DWORD ;
37
37
type Dtor = unsafe extern "C" fn ( * mut u8 ) ;
38
38
39
- pub struct StaticKey {
39
+ pub struct LazyKey {
40
40
/// The key value shifted up by one. Since TLS_OUT_OF_INDEXES == DWORD::MAX
41
41
/// is not a valid key value, this allows us to use zero as sentinel value
42
42
/// without risking overflow.
43
43
key : AtomicU32 ,
44
44
dtor : Option < Dtor > ,
45
- next : AtomicPtr < StaticKey > ,
45
+ next : AtomicPtr < LazyKey > ,
46
46
/// Currently, destructors cannot be unregistered, so we cannot use racy
47
47
/// initialization for keys. Instead, we need synchronize initialization.
48
48
/// Use the Windows-provided `Once` since it does not require TLS.
49
49
once : UnsafeCell < c:: INIT_ONCE > ,
50
50
}
51
51
52
- impl StaticKey {
52
+ impl LazyKey {
53
53
#[ inline]
54
- pub const fn new ( dtor : Option < Dtor > ) -> StaticKey {
55
- StaticKey {
54
+ pub const fn new ( dtor : Option < Dtor > ) -> LazyKey {
55
+ LazyKey {
56
56
key : AtomicU32 :: new ( 0 ) ,
57
57
dtor,
58
58
next : AtomicPtr :: new ( ptr:: null_mut ( ) ) ,
@@ -61,18 +61,7 @@ impl StaticKey {
61
61
}
62
62
63
63
#[ 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 {
76
65
match self . key . load ( Acquire ) {
77
66
0 => unsafe { self . init ( ) } ,
78
67
key => key - 1 ,
@@ -141,17 +130,28 @@ impl StaticKey {
141
130
}
142
131
}
143
132
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
+ }
146
146
147
- static DTORS : AtomicPtr < StaticKey > = AtomicPtr :: new ( ptr:: null_mut ( ) ) ;
147
+ static DTORS : AtomicPtr < LazyKey > = AtomicPtr :: new ( ptr:: null_mut ( ) ) ;
148
148
149
149
/// Should only be called once per key, otherwise loops or breaks may occur in
150
150
/// the linked list.
151
- unsafe fn register_dtor ( key : & ' static StaticKey ) {
151
+ unsafe fn register_dtor ( key : & ' static LazyKey ) {
152
152
guard:: enable ( ) ;
153
153
154
- let this = <* const StaticKey >:: cast_mut ( key) ;
154
+ let this = <* const LazyKey >:: cast_mut ( key) ;
155
155
// Use acquire ordering to pass along the changes done by the previously
156
156
// registered keys when we store the new head with release ordering.
157
157
let mut head = DTORS . load ( Acquire ) ;
@@ -176,9 +176,9 @@ pub unsafe fn run_dtors() {
176
176
let dtor = unsafe { ( * cur) . dtor . unwrap ( ) } ;
177
177
cur = unsafe { ( * cur) . next . load ( Relaxed ) } ;
178
178
179
- // In StaticKey ::init, we register the dtor before setting `key`.
179
+ // In LazyKey ::init, we register the dtor before setting `key`.
180
180
// 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
182
182
// initialized in this thread so we can safely skip it.
183
183
if pre_key == 0 {
184
184
continue ;
0 commit comments