Skip to content

Commit 8e9f7bc

Browse files
committed
Add LazyKey to destructor list on value initialization
1 parent 5b6cc98 commit 8e9f7bc

File tree

2 files changed

+29
-33
lines changed

2 files changed

+29
-33
lines changed

library/std/src/sys/thread_local/key/racy.rs

Lines changed: 21 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ impl LazyKey {
6464
};
6565
rtassert!(key as usize != KEY_SENTVAL);
6666

67-
let final_key = match self.key.compare_exchange(
67+
match self.key.compare_exchange(
6868
KEY_SENTVAL,
6969
key as usize,
7070
Ordering::Release,
@@ -77,15 +77,18 @@ impl LazyKey {
7777
super::destroy(key);
7878
n
7979
},
80-
};
80+
}
81+
}
8182

82-
// TODO: This must be called for every thread that uses this LazyKey once!
83-
#[cfg(not(target_thread_local))]
84-
if self.dtor.is_some() {
85-
unsafe { register_dtor(self) };
83+
/// Registers destructor to run at process exit.
84+
#[cfg(not(target_thread_local))]
85+
pub fn register_process_dtor(&'static self) {
86+
if self.dtor.is_none() {
87+
return;
8688
}
8789

88-
final_key
90+
crate::sys::thread_local::guard::enable();
91+
lazy_keys().borrow_mut().push(self);
8992
}
9093
}
9194

@@ -131,42 +134,31 @@ fn lazy_keys() -> &'static crate::cell::RefCell<Vec<&'static LazyKey>> {
131134
unsafe { &*ptr }
132135
}
133136

134-
/// Registers destructor to run at process exit.
135-
#[cfg(not(target_thread_local))]
136-
unsafe fn register_dtor(lazy_key: &'static LazyKey) {
137-
crate::sys::thread_local::guard::enable();
138-
139-
lazy_keys().borrow_mut().push(lazy_key);
140-
}
141-
142137
/// Run destructors at process exit.
143138
///
144139
/// SAFETY: This will and must only be run by the destructor callback in [`guard`].
145140
#[cfg(not(target_thread_local))]
146141
pub unsafe fn run_dtors() {
147142
let lazy_keys_cell = lazy_keys();
148-
let mut lazy_keys = lazy_keys_cell.take();
149143

150144
for _ in 0..5 {
151145
let mut any_run = false;
152-
for lazy_key in &lazy_keys {
153-
if let Some(dtor) = &lazy_key.dtor {
154-
let key = lazy_key.force();
155-
let ptr = unsafe { super::get(key) };
156-
if !ptr.is_null() {
157-
unsafe { dtor(ptr) };
158-
unsafe { super::set(key, crate::ptr::null_mut()) };
159-
any_run = true;
146+
147+
for lazy_key in lazy_keys_cell.take() {
148+
let key = lazy_key.force();
149+
let ptr = unsafe { super::get(key) };
150+
if !ptr.is_null() {
151+
// SAFETY: only keys with destructors are registered.
152+
unsafe {
153+
let Some(dtor) = &lazy_key.dtor else { crate::hint::unreachable_unchecked() };
154+
dtor(ptr);
160155
}
156+
any_run = true;
161157
}
162158
}
163159

164-
let mut new_lazy_keys = lazy_keys_cell.borrow_mut();
165-
166-
if !any_run && new_lazy_keys.is_empty() {
160+
if !any_run {
167161
break;
168162
}
169-
170-
lazy_keys.extend(new_lazy_keys.drain(..));
171163
}
172164
}

library/std/src/sys/thread_local/os.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,11 @@ impl<T: 'static> Storage<T> {
7979
unsafe { &(*ptr).value }
8080
} else {
8181
// SAFETY: trivially correct.
82-
unsafe { Self::try_initialize(key, ptr, i, f) }
82+
let (ptr, was_null) = unsafe { Self::try_initialize(key, ptr, i, f) };
83+
if was_null {
84+
self.key.register_process_dtor();
85+
}
86+
ptr
8387
}
8488
}
8589

@@ -91,10 +95,10 @@ impl<T: 'static> Storage<T> {
9195
ptr: *mut Value<T>,
9296
i: Option<&mut Option<T>>,
9397
f: impl FnOnce() -> T,
94-
) -> *const T {
98+
) -> (*const T, bool) {
9599
if ptr.addr() == 1 {
96100
// destructor is running
97-
return ptr::null();
101+
return (ptr::null(), false);
98102
}
99103

100104
let value = Box::new(Value { value: i.and_then(Option::take).unwrap_or_else(f), key });
@@ -120,7 +124,7 @@ impl<T: 'static> Storage<T> {
120124
}
121125

122126
// SAFETY: We just created this value above.
123-
unsafe { &(*ptr).value }
127+
(unsafe { &(*ptr).value }, old.is_null())
124128
}
125129
}
126130

0 commit comments

Comments
 (0)