ax_task/sched/system/task_system/park_exit/
park_commit.rs1use super::*;
4
5impl TaskSystem {
6 pub fn commit_park(
8 &self,
9 cpu: Pin<&mut CpuLocal>,
10 current: &ThreadHandle,
11 token: &mut ParkTicket,
12 ) -> Result<ParkCommit, TaskError> {
13 self.commit_park_owner(
14 cpu,
15 current.runtime_core_arc(),
16 token,
17 OwnerRqEntry::IrqSave,
18 )
19 }
20
21 pub(crate) unsafe fn commit_park_in_scheduler_frame(
27 &self,
28 cpu: Pin<&mut CpuLocal>,
29 current: &Arc<ThreadCore>,
30 token: &mut ParkTicket,
31 ) -> Result<ParkCommit, TaskError> {
32 self.commit_park_owner(cpu, current, token, OwnerRqEntry::SchedulerFrame)
33 }
34
35 pub(super) fn commit_park_owner(
36 &self,
37 mut cpu: Pin<&mut CpuLocal>,
38 current: &Arc<ThreadCore>,
39 token: &mut ParkTicket,
40 rq_entry: OwnerRqEntry,
41 ) -> Result<ParkCommit, TaskError> {
42 if token.is_resolved() || current.id() != token.thread() {
43 return Err(TaskError::StaleThreadId);
44 }
45 if rq_entry.requires_owner_context_validation() {
46 self.ensure_owner_cpu_context(&cpu)?;
47 }
48 let remote = unsafe { cpu.as_ref().get_ref().remote_for_owner() };
51 if let Some(registration) = token.deadline()
52 && registration.may_enter_soft_expiry_buffer()
53 && let Some(event) = cpu.as_mut().take_buffered_expiration(registration)
54 {
55 self.service_expired_park_deadline(event)?;
56 }
57 let initial_request = remote.claim_scheduler_request(SchedulerRequestScope::All);
58 self.drain_owner_work(cpu.as_mut())?;
59 self.ensure_owner_cpu_online(&cpu)?;
60
61 if matches!(
62 current.effective_policy_snapshot(),
63 SchedulePolicy::Fair { .. }
64 | SchedulePolicy::Fifo { .. }
65 | SchedulePolicy::RoundRobin { .. }
66 ) && !current.sched().placement().has_pending_migration()
67 && let Some(commit) = self.try_commit_park_in_rq(
68 cpu.as_mut(),
69 token,
70 remote,
71 current,
72 initial_request,
73 rq_entry,
74 )?
75 {
76 return Ok(commit);
77 }
78
79 let mut previous_sched = unsafe { rq_entry.lock_thread_sched(current.sched()) };
81 let mut transaction = unsafe { rq_entry.begin(self, remote) };
83
84 transaction.adopt_scheduler_request(initial_request);
85 let scheduler_request = transaction.merge_scheduler_request(SchedulerRequestScope::All);
86 let now_ns = transaction.clock().wall().as_nanos();
87
88 if transaction.current_thread() != Some(token.thread()) {
89 transaction.commit_and_finish_scheduler_request();
90 return Err(TaskError::StaleThreadId);
91 }
92 let Some(previous_core) = transaction.current_core() else {
93 transaction.commit_and_finish_scheduler_request();
94 return Err(TaskError::NoRunnableThread);
95 };
96 if !Arc::ptr_eq(&previous_core, current) {
97 transaction.commit_and_finish_scheduler_request();
98 return Err(TaskError::InvalidConfiguration);
99 }
100 let generation = previous_core.park_generation();
101 if generation != token.generation() {
102 transaction.commit_and_finish_scheduler_request();
103 return Err(TaskError::StaleThreadId);
104 }
105 let notified = previous_core.take_park_notification();
106 if notified {
107 previous_sched
108 .transition(&previous_core, ThreadState::Running)
109 .unwrap_or_else(|_| {
110 task_runtime::fatal_invariant(0x504b_1101, previous_core.id().as_u64() as usize)
111 });
112 cpu.restore_claimed_park_preemption(scheduler_request);
113 transaction.commit_and_finish_scheduler_request();
114 token.mark_resolved();
115 return Ok(ParkCommit::Notified);
116 }
117 cpu.defer_park_preemption(scheduler_request);
118 let dispatch_commit = self.settle_owner_current_dispatch_in_rq(&mut transaction);
119
120 let previous_endpoint = transaction.current_switch_endpoint().unwrap_or_else(|| {
121 task_runtime::fatal_invariant(0x504b_1102, previous_core.id().as_u64() as usize)
122 });
123 let previous_urgency = transaction.current_scheduling_urgency().unwrap_or_else(|| {
124 task_runtime::fatal_invariant(0x504b_1102, previous_core.id().as_u64() as usize)
125 });
126 let resumed = {
127 let placement = previous_core.sched().placement();
128 let sched = &mut *previous_sched;
129 if previous_core
135 .publish_blocked_from_parking()
136 .unwrap_or_else(|_| {
137 task_runtime::fatal_invariant(0x504b_1103, previous_core.id().as_u64() as usize)
138 })
139 == ParkPublication::Notified
140 {
141 true
142 } else {
143 if sched.lifecycle.state() != ThreadState::Blocked
144 || placement.queued_cpu() != Some(cpu.owner())
145 || placement.on_cpu() != Some(cpu.owner())
146 {
147 task_runtime::fatal_invariant(
148 0x504b_1104,
149 previous_core.id().as_u64() as usize,
150 );
151 }
152 let force_delayed = false;
158 let timing_granularity_ns = self.config.timing_granularity_ns();
159 let delayed = !transaction.is_linked_current(previous_core.id())
160 && transaction
161 .delay_dequeue_unlinked_current(
162 previous_core.id(),
163 timing_granularity_ns,
164 force_delayed,
165 )
166 .is_some();
167 if delayed {
168 placement.delay_dequeue_current(cpu.owner());
169 } else {
170 let active = if transaction.is_linked_current(previous_core.id()) {
171 transaction
172 .deactivate_task(previous_core.id())
173 .into_active()
174 } else {
175 transaction.deactivate_unlinked_current(previous_core.id());
176 transaction
177 .take_current()
178 .and_then(CurrentDispatch::into_active)
179 .unwrap_or_else(|| {
180 task_runtime::fatal_invariant(
181 0x504b_1105,
182 previous_core.id().as_u64() as usize,
183 )
184 })
185 };
186 previous_core.sched().install_active(sched, active);
187 }
188 self.mark_owner_deadline_non_contending_in_rq(
189 &previous_core,
190 sched,
191 cpu.as_mut(),
192 now_ns,
193 &mut transaction,
194 );
195 if !delayed {
196 let mut active = previous_core.sched().active(sched);
197 if let Some(fair) = active.base_entity().fair() {
198 let virtual_time = transaction.virtual_time();
199 let rq_max_slice_ns = transaction
200 .max_fair_service_request_ns()
201 .unwrap_or(fair.service_request_ns())
202 .max(fair.service_request_ns());
203 active.base_entity_mut().capture_fair_sleep_lag(
204 virtual_time,
205 rq_max_slice_ns,
206 timing_granularity_ns,
207 );
208 }
209 }
210 if !delayed {
211 placement.block_current(cpu.owner());
212 }
213 false
214 }
215 };
216 if resumed {
217 transaction.commit_and_finish_scheduler_request();
218 drop(previous_sched);
219 self.finish_owner_dispatch_commit(dispatch_commit);
220 cpu.finish_park_preemption(true);
221 token.mark_resolved();
222 return Ok(ParkCommit::Notified);
223 }
224
225 cpu.finish_park_preemption(false);
226 transaction.take_current();
227 transaction.merge_scheduler_request(SchedulerRequestScope::All);
231
232 let next = self.pick_owner_next_in_rq(
233 cpu.as_mut(),
234 &mut transaction,
235 Some((&previous_core, &mut previous_sched)),
236 );
237 let OwnerNext {
238 core: next_core,
239 policy: next_policy_ref,
240 urgency: next_urgency,
241 } = next;
242 let next_endpoint = transaction.current_switch_endpoint().unwrap_or_else(|| {
243 task_runtime::fatal_invariant(0x504b_1107, next_core.as_ref().id().as_u64() as usize)
244 });
245 let handoff = Self::prepare_switch_handoff(
246 Some(token.thread()),
247 Some(PreviousSwitchOwnership::retained(previous_core)),
248 next_core,
249 next_policy_ref,
250 PreviousSwitchDisposition::Live,
251 None,
252 );
253
254 let deadline_rq_observation =
255 transaction.scheduler_deadline_rq_observation(cpu.as_ref().get_ref());
256
257 self.commit_owner_switch_selection(
258 cpu.as_mut(),
259 transaction,
260 handoff,
261 !dispatch_commit.has_deferred_task_lock_work(),
262 );
263
264 drop(previous_sched);
265 self.finish_owner_dispatch_commit(dispatch_commit);
266 self.finish_owner_selection(
267 cpu.as_mut(),
268 Some(previous_endpoint.thread()),
269 next_endpoint.thread(),
270 Some(previous_urgency),
271 next_urgency,
272 OwnerSchedulerDeadline::Reevaluate(deadline_rq_observation),
273 );
274 let decision = Self::owner_switch_plan(
275 Some(previous_endpoint),
276 next_endpoint,
277 SwitchReason::Blocked,
278 now_ns,
279 );
280
281 token.mark_resolved();
282 Ok(ParkCommit::Blocked(decision))
283 }
284}