Skip to main content

ax_task/sched/system/task_system/park_exit/
park.rs

1//! Park under the owning scheduler transaction.
2
3use super::*;
4
5impl TaskSystem {
6    /// Publishes `PARKING` after consuming a wake-before-park notification.
7    pub fn prepare_park(
8        &self,
9        cpu: Pin<&mut CpuLocal>,
10        current: &ThreadHandle,
11    ) -> Result<ParkPrepare, TaskError> {
12        self.ensure_owner_cpu_context(&cpu)?;
13        self.ensure_owner_cpu_online(&cpu)?;
14        let core = current.runtime_core_arc();
15        let placement = core.sched().placement();
16        if placement.queued_cpu() != Some(cpu.owner()) || placement.on_cpu() != Some(cpu.owner()) {
17            return Err(TaskError::StaleThreadId);
18        }
19        self.prepare_current_park(core)
20    }
21
22    /// Publishes the current task's wait state before its later schedule pass.
23    ///
24    /// The runtime's current-thread publication is the architecture-context
25    /// identity, like Linux `current`. Resumed and fresh task contexts complete
26    /// switch tail before calling task code, so this state publication neither
27    /// reclaims `CpuLocal` nor repeats switch-tail completion.
28    pub(crate) fn prepare_current_park(
29        &self,
30        current: &ThreadCore,
31    ) -> Result<ParkPrepare, TaskError> {
32        let core = current;
33        let placement = core.sched().placement();
34        let queued_cpu = placement.queued_cpu();
35        if core.state() != ThreadState::Running
36            || queued_cpu.is_none()
37            || placement.on_cpu() != queued_cpu
38        {
39            return Err(TaskError::StaleThreadId);
40        }
41        if core.take_park_notification() {
42            return Ok(ParkPrepare::Notified);
43        }
44        let generation = core.next_park_generation()?;
45        core.transition_state(ThreadState::Parking)?;
46        Ok(ParkPrepare::Prepared(ParkTicket::new(
47            core.id(),
48            generation,
49        )))
50    }
51
52    /// Cancels a prepared park because an independent grant won the race.
53    pub fn cancel_park(
54        &self,
55        cpu: Pin<&mut CpuLocal>,
56        current: &ThreadHandle,
57        token: &mut ParkTicket,
58    ) -> Result<(), TaskError> {
59        self.cancel_current_park(cpu, current.runtime_core_arc(), token)
60    }
61
62    pub(crate) fn cancel_current_park(
63        &self,
64        cpu: Pin<&mut CpuLocal>,
65        current: &ThreadCore,
66        token: &mut ParkTicket,
67    ) -> Result<(), TaskError> {
68        self.ensure_owner_cpu_context(&cpu)?;
69        if token.is_resolved() || current.id() != token.thread() {
70            return Err(TaskError::StaleThreadId);
71        }
72        self.ensure_owner_cpu_online(&cpu)?;
73        let core = current;
74        if core.park_generation() != token.generation() {
75            return Err(TaskError::StaleThreadId);
76        }
77        let placement = core.sched().placement();
78        if core.state() != ThreadState::Parking
79            || placement.queued_cpu() != Some(cpu.owner())
80            || placement.on_cpu() != Some(cpu.owner())
81        {
82            return Err(TaskError::StaleThreadId);
83        }
84        core.transition_state(ThreadState::Running)?;
85        cpu.finish_park_preemption(true);
86        token.mark_resolved();
87        Ok(())
88    }
89}