starnix_core/time/
timers.rs1use crate::signals::{SignalEvent, SignalEventNotify, SignalEventValue};
6use crate::task::CurrentTask;
7use crate::time::interval_timer::{IntervalTimer, IntervalTimerHandle};
8use crate::time::{Timeline, TimerWakeup};
9use starnix_logging::log_warn;
10use starnix_sync::{LockDepMutex, TimerTableStateLock};
11use starnix_uapi::errors::Errno;
12use starnix_uapi::signals::SIGALRM;
13use starnix_uapi::{TIMER_ABSTIME, error, itimerspec, uapi};
14use std::collections::HashMap;
15
16static_assertions::const_assert!(
17 std::mem::size_of::<uapi::__kernel_timer_t>()
18 == std::mem::size_of::<uapi::arch32::__kernel_timer_t>()
19);
20pub type TimerId = uapi::__kernel_timer_t;
21
22static_assertions::const_assert!(
23 std::mem::size_of::<uapi::__kernel_clockid_t>()
24 == std::mem::size_of::<uapi::arch32::__kernel_clockid_t>()
25);
26pub type ClockId = uapi::__kernel_clockid_t;
27
28#[derive(Debug, Default)]
31pub struct TimerTable {
32 state: LockDepMutex<TimerTableMutableState, TimerTableStateLock>,
33}
34
35#[derive(Debug)]
36struct TimerTableMutableState {
37 next_timer_id: TimerId,
39 timers: HashMap<TimerId, IntervalTimerHandle>,
40 itimer_real: IntervalTimerHandle,
41}
42
43impl Default for TimerTableMutableState {
44 fn default() -> Self {
45 let signal_event =
46 SignalEvent::new(SignalEventValue(0), SIGALRM, SignalEventNotify::Signal);
47 let itimer_real =
48 IntervalTimer::new(0, Timeline::RealTime, TimerWakeup::Regular, signal_event)
49 .expect("Failed to create itimer_real");
50 TimerTableMutableState {
51 itimer_real,
52 timers: Default::default(),
53 next_timer_id: Default::default(),
54 }
55 }
56}
57
58impl TimerTable {
59 pub fn create(
63 &self,
64 timeline: Timeline,
65 wakeup_type: TimerWakeup,
66 signal_event: Option<SignalEvent>,
67 ) -> Result<TimerId, Errno> {
68 let mut state = self.state.lock();
69
70 let end = state.next_timer_id;
72 let timer_id = loop {
73 let timer_id = state.next_timer_id;
74 state.next_timer_id += 1;
75
76 if state.next_timer_id == TimerId::MAX {
77 state.next_timer_id = 0;
78 } else if state.next_timer_id == end {
79 return error!(EAGAIN);
82 }
83
84 if !state.timers.contains_key(&timer_id) {
85 break timer_id;
86 }
87 };
88
89 state.timers.insert(
90 timer_id,
91 IntervalTimer::new(
92 timer_id,
93 timeline,
94 wakeup_type,
95 signal_event.unwrap_or_else(|| {
96 SignalEvent::new(
97 SignalEventValue(timer_id as u64),
98 SIGALRM,
99 SignalEventNotify::Signal,
100 )
101 }),
102 )?,
103 );
104
105 Ok(timer_id)
106 }
107
108 pub fn itimer_real(&self) -> IntervalTimerHandle {
109 self.state.lock().itimer_real.clone()
110 }
111
112 pub fn delete(&self, current_task: &CurrentTask, id: TimerId) -> Result<(), Errno> {
114 let mut state = self.state.lock();
115 match state.timers.remove_entry(&id) {
116 Some(entry) => entry.1.disarm(current_task),
117 None => error!(EINVAL),
118 }
119 }
120
121 pub fn get_time(&self, id: TimerId) -> Result<itimerspec, Errno> {
124 Ok(self.get_timer(id)?.time_remaining().into())
125 }
126
127 pub fn get_overrun(&self, id: TimerId) -> Result<i32, Errno> {
129 Ok(self.get_timer(id)?.overrun_last())
130 }
131
132 pub fn set_time(
136 &self,
137 current_task: &CurrentTask,
138 id: TimerId,
139 flags: i32,
140 new_value: itimerspec,
141 ) -> Result<itimerspec, Errno> {
142 let itimer = self.get_timer(id)?;
143 let old_value: itimerspec = itimer.time_remaining().into();
144 if new_value.it_value.tv_sec != 0 || new_value.it_value.tv_nsec != 0 {
145 let is_absolute = flags == TIMER_ABSTIME as i32;
146 itimer.arm(current_task, new_value, is_absolute)?;
147 } else {
148 itimer.disarm(current_task)?;
149 }
150
151 Ok(old_value)
152 }
153
154 pub fn get_timer(&self, id: TimerId) -> Result<IntervalTimerHandle, Errno> {
155 match self.state.lock().timers.get(&id) {
156 Some(itimer) => Ok(itimer.clone()),
157 None => error!(EINVAL),
158 }
159 }
160
161 pub fn reset_for_exec(&self, current_task: &CurrentTask) {
163 let timers = std::mem::take(&mut self.state.lock().timers);
167 for (_, timer) in timers {
168 if let Err(err) = timer.disarm(current_task) {
169 log_warn!("Failed to disarm POSIX timer on exec: {err:?}");
170 }
171 }
172 }
173}