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