Skip to content

Commit 07b03a2

Browse files
authored
Unrolled build for rust-lang#116839
Rollup merge of rust-lang#116839 - joboet:xous_thread_parking, r=m-ou-se Implement thread parking for xous This follows the pattern set by [the Windows parker](https://github.com/rust-lang/rust/blob/ddef56d5dfa18f169af9db912dc8e8343797eebb/library/std/src/sys/windows/thread_parking.rs) when it uses keyed events. An atomic variable is used to track the state and optimize the fast path, while notifications are send via the ticktime server to block and unblock the thread. ping `@xobs` `@rustbot` label +T-libs +A-atomic r? libs
2 parents e9b7bf0 + 2dc6ba2 commit 07b03a2

File tree

3 files changed

+95
-1
lines changed

3 files changed

+95
-1
lines changed

library/std/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@
336336
#![feature(portable_simd)]
337337
#![feature(prelude_2024)]
338338
#![feature(ptr_as_uninit)]
339+
#![feature(ptr_from_ref)]
339340
#![feature(raw_os_nonzero)]
340341
#![feature(round_ties_even)]
341342
#![feature(slice_internals)]

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

-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ pub mod process;
2828
pub mod stdio;
2929
pub mod thread;
3030
pub mod thread_local_key;
31-
#[path = "../unsupported/thread_parking.rs"]
3231
pub mod thread_parking;
3332
pub mod time;
3433

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
use crate::os::xous::ffi::{blocking_scalar, scalar};
2+
use crate::os::xous::services::{ticktimer_server, TicktimerScalar};
3+
use crate::pin::Pin;
4+
use crate::ptr;
5+
use crate::sync::atomic::{
6+
AtomicI8,
7+
Ordering::{Acquire, Release},
8+
};
9+
use crate::time::Duration;
10+
11+
const NOTIFIED: i8 = 1;
12+
const EMPTY: i8 = 0;
13+
const PARKED: i8 = -1;
14+
15+
pub struct Parker {
16+
state: AtomicI8,
17+
}
18+
19+
impl Parker {
20+
pub unsafe fn new_in_place(parker: *mut Parker) {
21+
unsafe { parker.write(Parker { state: AtomicI8::new(EMPTY) }) }
22+
}
23+
24+
fn index(&self) -> usize {
25+
ptr::from_ref(self).addr()
26+
}
27+
28+
pub unsafe fn park(self: Pin<&Self>) {
29+
// Change NOTIFIED to EMPTY and EMPTY to PARKED.
30+
let state = self.state.fetch_sub(1, Acquire);
31+
if state == NOTIFIED {
32+
return;
33+
}
34+
35+
// The state was set to PARKED. Wait until the `unpark` wakes us up.
36+
blocking_scalar(
37+
ticktimer_server(),
38+
TicktimerScalar::WaitForCondition(self.index(), 0).into(),
39+
)
40+
.expect("failed to send WaitForCondition command");
41+
42+
self.state.swap(EMPTY, Acquire);
43+
}
44+
45+
pub unsafe fn park_timeout(self: Pin<&Self>, timeout: Duration) {
46+
// Change NOTIFIED to EMPTY and EMPTY to PARKED.
47+
let state = self.state.fetch_sub(1, Acquire);
48+
if state == NOTIFIED {
49+
return;
50+
}
51+
52+
// A value of zero indicates an indefinite wait. Clamp the number of
53+
// milliseconds to the allowed range.
54+
let millis = usize::max(timeout.as_millis().try_into().unwrap_or(usize::MAX), 1);
55+
56+
let was_timeout = blocking_scalar(
57+
ticktimer_server(),
58+
TicktimerScalar::WaitForCondition(self.index(), millis).into(),
59+
)
60+
.expect("failed to send WaitForCondition command")[0]
61+
!= 0;
62+
63+
let state = self.state.swap(EMPTY, Acquire);
64+
if was_timeout && state == NOTIFIED {
65+
// The state was set to NOTIFIED after we returned from the wait
66+
// but before we reset the state. Therefore, a wakeup is on its
67+
// way, which we need to consume here.
68+
// NOTICE: this is a priority hole.
69+
blocking_scalar(
70+
ticktimer_server(),
71+
TicktimerScalar::WaitForCondition(self.index(), 0).into(),
72+
)
73+
.expect("failed to send WaitForCondition command");
74+
}
75+
}
76+
77+
pub fn unpark(self: Pin<&Self>) {
78+
let state = self.state.swap(NOTIFIED, Release);
79+
if state == PARKED {
80+
// The thread is parked, wake it up.
81+
blocking_scalar(
82+
ticktimer_server(),
83+
TicktimerScalar::NotifyCondition(self.index(), 1).into(),
84+
)
85+
.expect("failed to send NotifyCondition command");
86+
}
87+
}
88+
}
89+
90+
impl Drop for Parker {
91+
fn drop(&mut self) {
92+
scalar(ticktimer_server(), TicktimerScalar::FreeCondition(self.index()).into()).ok();
93+
}
94+
}

0 commit comments

Comments
 (0)