ax_task/sched/system/thread_sched/
mod.rs1mod deadline_state;
4mod pi_state;
5mod placement;
6mod policy_state;
7mod runtime_state;
8
9use alloc::sync::{Arc, Weak};
10
11pub(in crate::sched::system) use pi_state::PiScheduleUpdate;
12pub(in crate::sched::system) use placement::SchedulerPlacement;
13
14use crate::{
15 runtime::{
16 lock::{IrqTicketGuard, IrqTicketLock},
17 resource::{AddressSpaceHandle, ExecutionContextHandle},
18 },
19 sched::{
20 CpuId, CpuSet, SchedulePolicy, SchedulerTimestamp,
21 algorithm::{
22 ActiveSchedulingState, DetachedActiveGuard, DetachedActivePublication,
23 DetachedActiveState, SchedulingEntity,
24 },
25 },
26 thread::{DeadlineServer, TaskError, ThreadCore, ThreadId, ThreadLifecycle, ThreadState},
27 time::queue::TaskDeadlineRegistration,
28};
29
30#[derive(Clone, Copy, Debug, Eq, PartialEq)]
32pub enum DeadlineActivity {
33 ActiveContending,
35 ActiveNonContending,
37 Inactive,
39}
40
41#[derive(Debug)]
47pub(crate) struct ThreadSchedCell {
48 id: ThreadId,
49 lifecycle: alloc::sync::Arc<ThreadLifecycle>,
50 placement: alloc::sync::Arc<placement::SchedulerPlacement>,
51 deadline_server: DeadlineServer,
52 detached_active: DetachedActiveState,
53 state: IrqTicketLock<ThreadSchedState>,
54}
55
56impl ThreadSchedCell {
57 pub(super) fn new(id: ThreadId, init: ThreadSchedInit) -> Result<Self, TaskError> {
58 let (state, active) = ThreadSchedState::new(init)?;
59 let lifecycle = alloc::sync::Arc::clone(&state.lifecycle);
60 let placement = alloc::sync::Arc::clone(&state.placement);
61 let deadline_server = state.deadline.server.clone();
62 Ok(Self {
63 id,
64 lifecycle,
65 placement,
66 deadline_server,
67 detached_active: DetachedActiveState::new(active),
68 state: IrqTicketLock::new(state),
69 })
70 }
71
72 pub(crate) const fn id(&self) -> ThreadId {
73 self.id
74 }
75
76 pub(super) fn lock(&self) -> IrqTicketGuard<'_, ThreadSchedState> {
77 loop {
78 let guard = self
79 .state
80 .lock(crate::runtime::IrqGuardSource::ThreadSchedTicket);
81 if !self.detached_active.publication_in_progress() {
82 return guard;
83 }
84 drop(guard);
89 self.detached_active.wait_for_publication();
90 }
91 }
92
93 pub(super) unsafe fn lock_scheduler_frame(&self) -> IrqTicketGuard<'_, ThreadSchedState> {
100 loop {
101 let guard = unsafe { self.state.lock_irq_disabled() };
103 if !self.detached_active.publication_in_progress() {
104 return guard;
105 }
106 drop(guard);
107 self.detached_active.wait_for_publication();
108 }
109 }
110
111 pub(super) unsafe fn try_lock_from_owner_rq(
122 &self,
123 ) -> Option<IrqTicketGuard<'_, ThreadSchedState>> {
124 let guard = unsafe { self.state.try_lock_irq_disabled() }?;
126 if self.detached_active.publication_in_progress() {
127 drop(guard);
128 return None;
129 }
130 Some(guard)
131 }
132
133 pub(super) unsafe fn lock_bootstrap(&self) -> IrqTicketGuard<'_, ThreadSchedState> {
140 loop {
141 let guard = unsafe { self.state.lock_irq_disabled() };
143 if !self.detached_active.publication_in_progress() {
144 return guard;
145 }
146 drop(guard);
147 self.detached_active.wait_for_publication();
148 }
149 }
150
151 pub(super) fn active(&self, _sched: &ThreadSchedState) -> DetachedActiveGuard<'_> {
153 self.detached_active.active()
154 }
155
156 pub(super) fn active_option(
158 &self,
159 _sched: &ThreadSchedState,
160 ) -> Option<DetachedActiveGuard<'_>> {
161 self.detached_active.active_option()
162 }
163
164 pub(super) fn take_active(&self, _sched: &mut ThreadSchedState) -> ActiveSchedulingState {
166 self.detached_active
167 .take()
168 .expect("active scheduling state must have exactly one owner")
169 }
170
171 pub(super) fn install_active(
173 &self,
174 _sched: &mut ThreadSchedState,
175 active: ActiveSchedulingState,
176 ) {
177 self.detached_active.install(active);
178 }
179
180 pub(super) fn begin_active_publication(&self) -> Option<DetachedActivePublication<'_>> {
182 self.detached_active.begin_publication()
183 }
184
185 pub(crate) fn scheduler_fence_cpu(&self) -> Option<CpuId> {
186 self.placement.on_cpu()
187 }
188
189 pub(crate) fn assigned_cpu(&self) -> Option<CpuId> {
190 self.placement.assigned_cpu()
191 }
192
193 pub(in crate::sched::system) fn placement(&self) -> &placement::SchedulerPlacement {
194 self.placement.as_ref()
195 }
196
197 pub(crate) fn lifecycle(&self) -> &alloc::sync::Arc<ThreadLifecycle> {
198 &self.lifecycle
199 }
200
201 pub(crate) fn deadline_server(&self) -> DeadlineServer {
202 self.deadline_server.clone()
203 }
204}
205
206#[derive(Debug)]
207pub(super) struct ThreadSchedState {
208 pub(super) lifecycle: alloc::sync::Arc<ThreadLifecycle>,
209 pub(super) policy: policy_state::ThreadPolicyState,
210 pub(super) placement: alloc::sync::Arc<placement::SchedulerPlacement>,
211 pub(super) affinity: placement::ThreadAffinityState,
212 pub(super) deadline: deadline_state::ThreadDeadlineState,
213 pub(super) pi: pi_state::ThreadPiState,
214 pub(super) runtime: runtime_state::ThreadRuntimeState,
215}
216
217pub(super) struct ThreadPolicyInit {
218 pub(super) policy: SchedulePolicy,
219 pub(super) entity: SchedulingEntity,
220}
221
222pub(super) struct ThreadPlacementInit {
223 pub(super) initial_cpu: CpuId,
224 pub(super) affinity: alloc::sync::Arc<CpuSet>,
225}
226
227pub(super) struct ThreadDeadlineInit {
228 pub(super) server: DeadlineServer,
229 pub(super) reservation_scaled: u64,
230}
231
232pub(super) struct ThreadRuntimeInit {
233 pub(super) context: ExecutionContextHandle,
234 pub(super) address_space: AddressSpaceHandle,
235}
236
237pub(super) struct ThreadSchedInit {
238 pub(super) policy: ThreadPolicyInit,
239 pub(super) placement: ThreadPlacementInit,
240 pub(super) deadline: ThreadDeadlineInit,
241 pub(super) runtime: ThreadRuntimeInit,
242}
243
244impl ThreadSchedState {
245 pub(super) fn new(init: ThreadSchedInit) -> Result<(Self, ActiveSchedulingState), TaskError> {
246 let active = ActiveSchedulingState::new(init.policy.policy, init.policy.entity)?;
247 Ok((
248 Self {
249 lifecycle: crate::thread::allocation::try_arc(ThreadLifecycle::new())?,
250 policy: policy_state::ThreadPolicyState::new(init.policy.policy),
251 placement: crate::thread::allocation::try_arc(placement::SchedulerPlacement::new(
252 init.placement.initial_cpu,
253 ))?,
254 affinity: placement::ThreadAffinityState::new(init.placement.affinity),
255 deadline: deadline_state::ThreadDeadlineState::new(
256 init.deadline.server,
257 init.deadline.reservation_scaled,
258 ),
259 pi: pi_state::ThreadPiState::new(),
260 runtime: runtime_state::ThreadRuntimeState::new(
261 init.runtime.context,
262 init.runtime.address_space,
263 ),
264 },
265 active,
266 ))
267 }
268
269 pub(super) fn transition(
270 &mut self,
271 core: &ThreadCore,
272 state: ThreadState,
273 ) -> Result<(), TaskError> {
274 core.transition_state(state)
275 }
276
277 pub(super) fn is_pi_boosted_rt_owner_for(&self, policy: SchedulePolicy) -> bool {
278 !self.pi.donors.is_empty()
279 && self.is_pi_boosted()
280 && matches!(
281 policy,
282 SchedulePolicy::Fifo { .. } | SchedulePolicy::RoundRobin { .. }
283 )
284 }
285
286 pub(super) const fn is_pi_boosted(&self) -> bool {
287 self.pi.donor.is_some()
288 }
289
290 pub(super) fn held_deadline_reservation(&self) -> u64 {
297 self.deadline.bandwidth.reservation_scaled().max(
298 self.policy
299 .pending_update()
300 .map_or(0, |pending| pending.reservation_scaled),
301 )
302 }
303
304 pub(super) fn rq_task_metadata(
309 &self,
310 ) -> Result<crate::sched::algorithm::RqTaskMetadata, TaskError> {
311 Ok(crate::sched::algorithm::RqTaskMetadata {
312 affinity: Arc::clone(&self.affinity.affinity),
313 deadline_bandwidth_scaled: self.deadline.bandwidth.reservation_scaled(),
314 runtime_binding: self.runtime.binding(),
315 })
316 }
317}