Skip to content

Commit ff3326d

Browse files
Rollup merge of #105903 - joboet:unify_parking, r=m-ou-se
Unify id-based thread parking implementations Multiple platforms currently use thread-id-based parking implementations (NetBSD and SGX[^1]). Even though the strategy does not differ, these are duplicated for each platform, as the id is encoded into an atomic thread variable in different ways for each platform. Since `park` is only called by one thread, it is possible to move the thread id into a separate field. By ensuring that the field is only written to once, before any other threads access it, these accesses can be unsynchronized, removing any restrictions on the size and niches of the thread id. This PR also renames the internal `thread_parker` modules to `thread_parking`, as that name now better reflects their contents. I hope this does not add too much reviewing noise. r? `@m-ou-se` `@rustbot` label +T-libs [^1]: SOLID supports this as well, I will switch it over in a follow-up PR.
2 parents 5570cda + 898302e commit ff3326d

File tree

19 files changed

+207
-240
lines changed

19 files changed

+207
-240
lines changed

library/std/src/sys/sgx/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub mod process;
3434
pub mod stdio;
3535
pub mod thread;
3636
pub mod thread_local_key;
37-
pub mod thread_parker;
37+
pub mod thread_parking;
3838
pub mod time;
3939

4040
mod condvar;

library/std/src/sys/sgx/thread.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ mod task_queue {
6565
/// execution. The signal is sent once all TLS destructors have finished at
6666
/// which point no new thread locals should be created.
6767
pub mod wait_notify {
68-
use super::super::thread_parker::Parker;
6968
use crate::pin::Pin;
7069
use crate::sync::Arc;
70+
use crate::sys_common::thread_parking::Parker;
7171

7272
pub struct Notifier(Arc<Parker>);
7373

@@ -87,14 +87,14 @@ pub mod wait_notify {
8787
/// called, this will return immediately, otherwise the current thread
8888
/// is blocked until notified.
8989
pub fn wait(self) {
90-
// This is not actually `unsafe`, but it uses the `Parker` API,
91-
// which needs `unsafe` on some platforms.
90+
// SAFETY:
91+
// This is only ever called on one thread.
9292
unsafe { Pin::new(&*self.0).park() }
9393
}
9494
}
9595

9696
pub fn new() -> (Notifier, Waiter) {
97-
let inner = Arc::new(Parker::new_internal());
97+
let inner = Arc::new(Parker::new());
9898
(Notifier(inner.clone()), Waiter(inner))
9999
}
100100
}

library/std/src/sys/sgx/thread_parker.rs

-107
This file was deleted.
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
use super::abi::usercalls;
2+
use crate::io::ErrorKind;
3+
use crate::time::Duration;
4+
use fortanix_sgx_abi::{EV_UNPARK, WAIT_INDEFINITE};
5+
6+
pub type ThreadId = fortanix_sgx_abi::Tcs;
7+
8+
pub use super::abi::thread::current;
9+
10+
pub fn park(_hint: usize) {
11+
usercalls::wait(EV_UNPARK, WAIT_INDEFINITE).unwrap();
12+
}
13+
14+
pub fn park_timeout(dur: Duration, _hint: usize) {
15+
let timeout = u128::min(dur.as_nanos(), WAIT_INDEFINITE as u128 - 1) as u64;
16+
if let Err(e) = usercalls::wait(EV_UNPARK, timeout) {
17+
assert!(matches!(e.kind(), ErrorKind::TimedOut | ErrorKind::WouldBlock))
18+
}
19+
}
20+
21+
pub fn unpark(tid: ThreadId, _hint: usize) {
22+
let _ = usercalls::send(EV_UNPARK, Some(tid));
23+
}

library/std/src/sys/unix/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ pub mod stdio;
4040
pub mod thread;
4141
pub mod thread_local_dtor;
4242
pub mod thread_local_key;
43-
pub mod thread_parker;
43+
pub mod thread_parking;
4444
pub mod time;
4545

4646
#[cfg(target_os = "espidf")]

library/std/src/sys/unix/thread_parker/netbsd.rs

-113
This file was deleted.

library/std/src/sys/unix/thread_parker/darwin.rs library/std/src/sys/unix/thread_parking/darwin.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ unsafe impl Sync for Parker {}
4646
unsafe impl Send for Parker {}
4747

4848
impl Parker {
49-
pub unsafe fn new(parker: *mut Parker) {
49+
pub unsafe fn new_in_place(parker: *mut Parker) {
5050
let semaphore = dispatch_semaphore_create(0);
5151
assert!(
5252
!semaphore.is_null(),

library/std/src/sys/unix/thread_parker/mod.rs library/std/src/sys/unix/thread_parking/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ cfg_if::cfg_if! {
2424
pub use darwin::Parker;
2525
} else if #[cfg(target_os = "netbsd")] {
2626
mod netbsd;
27-
pub use netbsd::Parker;
27+
pub use netbsd::{current, park, park_timeout, unpark, ThreadId};
2828
} else {
2929
mod pthread;
3030
pub use pthread::Parker;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
use crate::ffi::{c_int, c_void};
2+
use crate::ptr;
3+
use crate::time::Duration;
4+
use libc::{_lwp_self, clockid_t, lwpid_t, time_t, timespec, CLOCK_MONOTONIC};
5+
6+
extern "C" {
7+
fn ___lwp_park60(
8+
clock_id: clockid_t,
9+
flags: c_int,
10+
ts: *mut timespec,
11+
unpark: lwpid_t,
12+
hint: *const c_void,
13+
unparkhint: *const c_void,
14+
) -> c_int;
15+
fn _lwp_unpark(lwp: lwpid_t, hint: *const c_void) -> c_int;
16+
}
17+
18+
pub type ThreadId = lwpid_t;
19+
20+
#[inline]
21+
pub fn current() -> ThreadId {
22+
unsafe { _lwp_self() }
23+
}
24+
25+
#[inline]
26+
pub fn park(hint: usize) {
27+
unsafe {
28+
___lwp_park60(0, 0, ptr::null_mut(), 0, ptr::invalid(hint), ptr::null());
29+
}
30+
}
31+
32+
pub fn park_timeout(dur: Duration, hint: usize) {
33+
let mut timeout = timespec {
34+
// Saturate so that the operation will definitely time out
35+
// (even if it is after the heat death of the universe).
36+
tv_sec: dur.as_secs().try_into().ok().unwrap_or(time_t::MAX),
37+
tv_nsec: dur.subsec_nanos().into(),
38+
};
39+
40+
// Timeout needs to be mutable since it is modified on NetBSD 9.0 and
41+
// above.
42+
unsafe {
43+
___lwp_park60(CLOCK_MONOTONIC, 0, &mut timeout, 0, ptr::invalid(hint), ptr::null());
44+
}
45+
}
46+
47+
#[inline]
48+
pub fn unpark(tid: ThreadId, hint: usize) {
49+
unsafe {
50+
_lwp_unpark(tid, ptr::invalid(hint));
51+
}
52+
}

library/std/src/sys/unix/thread_parker/pthread.rs library/std/src/sys/unix/thread_parking/pthread.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ impl Parker {
9999
///
100100
/// # Safety
101101
/// The constructed parker must never be moved.
102-
pub unsafe fn new(parker: *mut Parker) {
102+
pub unsafe fn new_in_place(parker: *mut Parker) {
103103
// Use the default mutex implementation to allow for simpler initialization.
104104
// This could lead to undefined behaviour when deadlocking. This is avoided
105105
// by not deadlocking. Note in particular the unlocking operation before any

library/std/src/sys/windows/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub mod stdio;
3333
pub mod thread;
3434
pub mod thread_local_dtor;
3535
pub mod thread_local_key;
36-
pub mod thread_parker;
36+
pub mod thread_parking;
3737
pub mod time;
3838
cfg_if::cfg_if! {
3939
if #[cfg(not(target_vendor = "uwp"))] {

library/std/src/sys/windows/thread_parker.rs library/std/src/sys/windows/thread_parking.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ const NOTIFIED: i8 = 1;
9797
impl Parker {
9898
/// Construct the Windows parker. The UNIX parker implementation
9999
/// requires this to happen in-place.
100-
pub unsafe fn new(parker: *mut Parker) {
100+
pub unsafe fn new_in_place(parker: *mut Parker) {
101101
parker.write(Self { state: AtomicI8::new(EMPTY) });
102102
}
103103

library/std/src/sys_common/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub mod process;
3030
pub mod thread;
3131
pub mod thread_info;
3232
pub mod thread_local_dtor;
33-
pub mod thread_parker;
33+
pub mod thread_parking;
3434
pub mod wstr;
3535
pub mod wtf8;
3636

0 commit comments

Comments
 (0)