ax_task/time/
registration.rs1use crate::{
4 runtime::{
5 context::{
6 RuntimeIrqGuard, runtime_current_cpu_mut, runtime_task_system, validate_task_context,
7 },
8 cpu::{CpuLocal, SchedulerDeadlineUpdate},
9 task_runtime,
10 },
11 sched::system::DeadlineBaseGuardSource,
12 thread::TaskError,
13 time::{
14 MonotonicDeadline,
15 hard_timer::HardKernelTimerHandle,
16 queue::{
17 HardKernelTimerCallback, KernelTimerCallback, KernelTimerCancelOutcome,
18 KernelTimerEntry, KernelTimerHandle, RestartableKernelTimerCallback, TaskDeadlineError,
19 },
20 },
21};
22
23enum KernelTimerRegistrationResult {
24 Registered(KernelTimerHandle, Option<SchedulerDeadlineUpdate>),
25 Rejected(TaskError, KernelTimerEntry),
26}
27
28struct KernelTimerCancellationResult {
29 outcome: Result<KernelTimerCancelOutcome, TaskError>,
30 removed: Option<KernelTimerEntry>,
31}
32
33pub fn register_kernel_timer(
45 deadline: MonotonicDeadline,
46 callback: KernelTimerCallback,
47) -> Result<KernelTimerHandle, TaskError> {
48 validate_task_context()?;
49 let entry = KernelTimerEntry::new(deadline, callback).map_err(kernel_timer_error)?;
50 register_kernel_timer_entry(entry)
51}
52
53pub fn register_restartable_kernel_timer(
60 deadline: MonotonicDeadline,
61 callback: RestartableKernelTimerCallback,
62) -> Result<KernelTimerHandle, TaskError> {
63 validate_task_context()?;
64 let entry =
65 KernelTimerEntry::new_restartable(deadline, callback).map_err(kernel_timer_error)?;
66 register_kernel_timer_entry(entry)
67}
68
69pub fn register_hard_restartable_kernel_timer(
76 deadline: MonotonicDeadline,
77 callback: HardKernelTimerCallback,
78) -> Result<HardKernelTimerHandle, TaskError> {
79 validate_task_context()?;
80 let entry =
81 KernelTimerEntry::new_hard_restartable(deadline, callback).map_err(kernel_timer_error)?;
82 register_kernel_timer_entry(entry).map(HardKernelTimerHandle::new)
83}
84
85pub fn arm_hard_kernel_timer(
96 handle: HardKernelTimerHandle,
97 deadline: MonotonicDeadline,
98) -> Result<(), TaskError> {
99 validate_task_context()?;
100 let update = {
101 let mut irq = RuntimeIrqGuard::enter();
102 let cpu = runtime_current_cpu_mut(&mut irq)?;
103 if cpu.owner() != handle.owner() {
104 return Err(TaskError::CpuOwnerMismatch {
105 expected: handle.owner().as_u32(),
106 actual: cpu.owner().as_u32(),
107 });
108 }
109 let mut deadline_base = cpu
110 .remote()
111 .lock_deadline_activity(DeadlineBaseGuardSource::Registration);
112 let non_timer = deadline_base.non_timer;
113 if !deadline_base
114 .kernel_timers
115 .arm_hard(handle.into(), deadline)
116 {
117 return Err(TaskError::InvalidConfiguration);
118 }
119 match CpuLocal::update_scheduler_deadline_registration_publication_if_changed(
120 &mut deadline_base,
121 non_timer,
122 ) {
123 Ok(update) => update,
124 Err(error) => {
125 assert_eq!(
126 deadline_base.kernel_timers.disarm_hard(handle.into()),
127 Some(Some(deadline)),
128 "failed hard-timer arm publication must restore inactivity"
129 );
130 return Err(error);
131 }
132 }
133 };
134 if let Some(update) = update {
135 task_runtime::publish_scheduler_deadline(update);
136 }
137 Ok(())
138}
139
140pub fn disarm_hard_kernel_timer(handle: HardKernelTimerHandle) -> Result<(), TaskError> {
146 validate_task_context()?;
147 let update = {
148 let mut irq = RuntimeIrqGuard::enter();
149 let current = runtime_current_cpu_mut(&mut irq)?;
150 let system = runtime_task_system()?;
151 let remote = system
152 .cpu_remote(handle.owner())
153 .ok_or(TaskError::InvalidConfiguration)?;
154 let local_owner = current.owner() == handle.owner();
155 let mut deadline_base =
156 remote.lock_deadline_activity(DeadlineBaseGuardSource::Registration);
157 let non_timer = local_owner.then_some(deadline_base.non_timer);
158 let transition = deadline_base
159 .kernel_timers
160 .disarm_hard(handle.into())
161 .ok_or(TaskError::InvalidConfiguration)?;
162 let (Some(non_timer), Some(previous_deadline)) = (non_timer, transition) else {
163 return Ok(());
164 };
165 match CpuLocal::update_scheduler_deadline_registration_publication_if_changed(
166 &mut deadline_base,
167 non_timer,
168 ) {
169 Ok(update) => update,
170 Err(error) => {
171 assert!(
172 deadline_base
173 .kernel_timers
174 .arm_hard(handle.into(), previous_deadline),
175 "failed hard-timer disarm publication must restore the active entry"
176 );
177 return Err(error);
178 }
179 }
180 };
181 if let Some(update) = update {
182 task_runtime::publish_scheduler_deadline(update);
183 }
184 Ok(())
185}
186
187fn register_kernel_timer_entry(entry: KernelTimerEntry) -> Result<KernelTimerHandle, TaskError> {
188 let result = {
189 let mut irq = RuntimeIrqGuard::enter();
190 let cpu = runtime_current_cpu_mut(&mut irq)?;
191 let owner = cpu.owner();
192 let mut deadline_base = cpu
193 .remote()
194 .lock_deadline_activity(DeadlineBaseGuardSource::Registration);
195 let non_timer = deadline_base.non_timer;
196 let inserted = deadline_base.kernel_timers.insert(owner, entry);
197 match inserted {
198 Ok(handle) => {
199 match CpuLocal::update_scheduler_deadline_registration_publication_if_changed(
200 &mut deadline_base,
201 non_timer,
202 ) {
203 Ok(update) => KernelTimerRegistrationResult::Registered(handle, update),
204 Err(error) => {
205 let removed = deadline_base
206 .kernel_timers
207 .cancel(handle)
208 .1
209 .expect("failed timer publication must roll back its new entry");
210 KernelTimerRegistrationResult::Rejected(error, removed)
211 }
212 }
213 }
214 Err(entry) => KernelTimerRegistrationResult::Rejected(TaskError::TimerCapacity, entry),
215 }
216 };
217 finish_kernel_timer_registration(result)
218}
219
220pub fn cancel_kernel_timer(
229 handle: KernelTimerHandle,
230) -> Result<KernelTimerCancelOutcome, TaskError> {
231 validate_task_context()?;
232 let system = runtime_task_system()?;
233 let result = {
234 let mut irq = RuntimeIrqGuard::enter();
235 let current = runtime_current_cpu_mut(&mut irq)?;
236 let remote = system
237 .cpu_remote(handle.owner())
238 .ok_or(TaskError::InvalidConfiguration)?;
239 let local_owner = current.owner() == handle.owner();
240 let mut deadline_base =
241 remote.lock_deadline_activity(DeadlineBaseGuardSource::Registration);
242 let non_timer = local_owner.then_some(deadline_base.non_timer);
243 let (cancel_outcome, mut removed) = deadline_base.kernel_timers.cancel(handle);
244 let outcome = if removed.is_some() {
245 if let Some(non_timer) = non_timer {
246 match CpuLocal::update_scheduler_deadline_registration_publication_if_changed(
247 &mut deadline_base,
248 non_timer,
249 ) {
250 Ok(Some(update)) => {
251 drop(deadline_base);
252 task_runtime::publish_scheduler_deadline(update);
253 Ok(KernelTimerCancelOutcome::Cancelled)
254 }
255 Ok(None) => Ok(KernelTimerCancelOutcome::Cancelled),
256 Err(error) => {
257 deadline_base.kernel_timers.restore_cancelled(
258 removed
259 .take()
260 .expect("failed cancellation publication must restore its entry"),
261 );
262 Err(error)
263 }
264 }
265 } else {
266 Ok(KernelTimerCancelOutcome::Cancelled)
267 }
268 } else {
269 Ok(cancel_outcome)
270 };
271 KernelTimerCancellationResult { outcome, removed }
272 };
273 drop(result.removed);
274 result.outcome
275}
276
277fn finish_kernel_timer_registration(
278 result: KernelTimerRegistrationResult,
279) -> Result<KernelTimerHandle, TaskError> {
280 match result {
281 KernelTimerRegistrationResult::Registered(handle, update) => {
282 if let Some(update) = update {
283 task_runtime::publish_scheduler_deadline(update);
284 }
285 Ok(handle)
286 }
287 KernelTimerRegistrationResult::Rejected(error, entry) => {
288 drop(entry);
289 Err(error)
290 }
291 }
292}
293
294fn kernel_timer_error(error: TaskDeadlineError) -> TaskError {
295 match error {
296 TaskDeadlineError::Capacity => TaskError::TimerCapacity,
297 TaskDeadlineError::GenerationExhausted | TaskDeadlineError::KindMismatch => {
298 TaskError::InvalidConfiguration
299 }
300 }
301}