ax_task/sched/
affinity.rs1use alloc::sync::Arc;
4use core::sync::atomic::{AtomicU64, Ordering};
5
6use crate::{
7 sync::WaitQueue,
8 thread::{TaskError, ThreadCore, ThreadHandle, ThreadState},
9};
10
11#[derive(Debug)]
13pub(crate) struct ThreadAffinityCompletion {
14 completed_generation: AtomicU64,
15 waiters: WaitQueue,
16}
17
18impl ThreadAffinityCompletion {
19 pub(crate) const fn new(completed_generation: u64) -> Self {
20 Self {
21 completed_generation: AtomicU64::new(completed_generation),
22 waiters: WaitQueue::new(),
23 }
24 }
25
26 pub(crate) fn publish(&self, generation: u64) -> bool {
27 let mut completed = self.completed_generation.load(Ordering::Acquire);
28 loop {
29 if completed >= generation {
30 return false;
31 }
32 match self.completed_generation.compare_exchange_weak(
33 completed,
34 generation,
35 Ordering::Release,
36 Ordering::Acquire,
37 ) {
38 Ok(_) => return true,
39 Err(observed) => completed = observed,
40 }
41 }
42 }
43
44 pub(crate) fn completed_generation(&self) -> u64 {
45 self.completed_generation.load(Ordering::Acquire)
46 }
47
48 pub(crate) fn notify_waiters(&self) {
49 self.waiters.notify_all();
50 }
51
52 fn wait_for(&self, request: &ThreadAffinityChange) -> Result<(), TaskError> {
53 self.waiters
54 .try_wait_until(|| request.try_result().is_some())?;
55 request
56 .try_result()
57 .expect("affinity wait predicate resolved the request")
58 }
59}
60
61#[derive(Debug)]
63#[must_use = "dropping the change leaves the affinity update asynchronous"]
64pub struct ThreadAffinityChange {
65 thread: ThreadHandle,
66 generation: u64,
67}
68
69impl ThreadAffinityChange {
70 pub(crate) fn new(core: Arc<ThreadCore>, generation: u64) -> Self {
71 Self {
72 thread: ThreadHandle::from_core(core),
73 generation,
74 }
75 }
76
77 pub const fn generation(&self) -> u64 {
79 self.generation
80 }
81
82 pub fn try_result(&self) -> Option<Result<(), TaskError>> {
84 if self
85 .thread
86 .core
87 .affinity_completion()
88 .completed_generation()
89 >= self.generation
90 {
91 Some(Ok(()))
92 } else if self.thread.state() == ThreadState::Exited {
93 Some(Err(TaskError::StaleThreadId))
94 } else {
95 None
96 }
97 }
98
99 pub fn wait(self) -> Result<(), TaskError> {
110 self.thread.core.affinity_completion().wait_for(&self)
111 }
112}