Rollup merge of #126953 - joboet:lazy_key, r=jhpratt · model-checking/verify-rust-std@77a5b51 (original) (raw)
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,9 +13,9 @@
`
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
(std
's
``
21
21
`` //! 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,
`
45
``
`-
next: AtomicPtr,
`
``
45
`+
next: AtomicPtr,
`
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) -> StaticKey {
`
55
``
`-
StaticKey {
`
``
54
`+
pub const fn new(dtor: Option) -> 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 = AtomicPtr::new(ptr::null_mut());
`
``
147
`+
static DTORS: AtomicPtr = 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;
`