//! Timers that send signals (stage 17): alarm, setitimer/getitimer and //! the POSIX timers (timer_create, timer_settime, ...). //! //! A timer is a deadline, maybe with an interval to repeat at, and what to //! do when it's reached: send a signal (SIGALRM for alarm and setitimer; //! any signal, maybe to one thread, for timer_create). //! //! All timers live in one table. One kernel thread, "timerd", sleeps until //! the nearest deadline, sends the signals that are due, and goes back to //! sleep. Why a thread and not the timer interrupt? Sending a signal takes //! locks and may wake threads; doing that from normal thread context keeps //! the interrupt handler tiny and follows the locking rules in thread.rs. //! timerd is started the first time anyone arms a timer. //! //! Resolution: timerd sleeps in PIT ticks (~55 ms), so a timer fires up //! to ~110 ms late, never early. A periodic timer whose signals come late //! counts the periods it missed as "overruns" (timer_getoverrun), like //! Linux does when a signal is still pending. //! //! Lifetime, as on Linux: fork doesn't copy timers; execve deletes the //! POSIX timers but keeps the alarm / ITIMER_REAL; exit deletes them all. use crate::errno::Errno; use crate::process; use crate::signal::{self, SigInfo}; use crate::thread::WaitQueue; use crate::time; use alloc::vec::Vec; use core::sync::atomic::{AtomicBool, Ordering}; use spin::Mutex; use x86_64::instructions::interrupts::without_interrupts; /// si_code for a POSIX timer's signal. pub const SI_TIMER: i32 = -2; // The clocks timer_create understands. pub const CLOCK_REALTIME: u64 = 0; pub const CLOCK_MONOTONIC: u64 = 1; pub const CLOCK_BOOTTIME: u64 = 7; // sigev_notify: what to do when it fires. pub const SIGEV_SIGNAL: i32 = 0; // send sigev_signo to the process pub const SIGEV_NONE: i32 = 1; // nothing (the program polls timer_gettime) pub const SIGEV_THREAD_ID: i32 = 4; // send sigev_signo to thread sigev_tid /// At most this many POSIX timers per process: EAGAIN after that. const MAX_TIMERS: usize = 32; /// The id we use for a process's ITIMER_REAL (POSIX ids are 0..MAX_TIMERS). const ITIMER_ID: i32 = -1; #[derive(Clone, Copy)] struct Timer { pid: u64, /// timer_create's id, or ITIMER_ID. id: i32, clock: u64, /// Next expiry, in `time::now_us` microseconds (None = disarmed). next: Option, /// Repeat every this many microseconds (0 = once). interval: u64, signo: u32, notify: i32, /// SIGEV_THREAD_ID's thread. tid: u64, sigval: u64, /// Expirations missed at the last firing (timer_getoverrun). overrun: u64, } static TIMERS: Mutex> = Mutex::new(Vec::new()); /// timerd sleeps here; poked when the table changes. static CHANGED_QUEUE: WaitQueue = WaitQueue::new(); static CHANGED: AtomicBool = AtomicBool::new(false); static STARTED: AtomicBool = AtomicBool::new(false); fn with_table(f: impl FnOnce(&mut Vec) -> R) -> R { without_interrupts(|| f(&mut TIMERS.lock())) } /// Tell timerd to look again (starting it the first time). fn poke() { if !STARTED.swap(true, Ordering::AcqRel) { crate::thread::spawn("timerd", timerd); } CHANGED.store(true, Ordering::Release); CHANGED_QUEUE.wake_all(); } /// How far CLOCK_REALTIME is ahead of the monotonic clock (µs), to turn /// absolute wall-clock deadlines into ours. fn realtime_offset() -> u64 { time::realtime_us().saturating_sub(time::now_us()) } /// The kernel thread that fires timers (see the top). fn timerd() { loop { let now = time::now_us(); let mut due = Vec::new(); let next = with_table(|t| { for timer in t.iter_mut() { let Some(at) = timer.next else { continue }; if at > now { continue; } if timer.interval > 0 { let missed = (now - at) / timer.interval; timer.overrun = missed; timer.next = Some(at + (missed + 1) * timer.interval); } else { timer.overrun = 0; timer.next = None; } due.push(*timer); } t.iter().filter_map(|t| t.next).min() }); for timer in due { fire(&timer); } let changed = || CHANGED.swap(false, Ordering::AcqRel).then_some(()); match next { Some(at) => { let deadline = time::deadline_after_us(at.saturating_sub(time::now_us())); let _ = CHANGED_QUEUE.wait_until_deadline(deadline, changed); } None => CHANGED_QUEUE.wait_until(changed), } } } /// Send a due timer's signal. fn fire(timer: &Timer) { if timer.notify == SIGEV_NONE { return; } let Some(p) = process::get(timer.pid) else { return }; let info = if timer.id == ITIMER_ID { SigInfo::from_pid(timer.signo, 0) // SI_KERNEL, like Linux's itimers } else { let mut info = SigInfo::new(timer.signo, SI_TIMER); info.fields[0] = timer.id as u32 as u64 | (timer.overrun.min(i32::MAX as u64)) << 32; // si_tid, si_overrun info.fields[1] = timer.sigval; // si_value info }; if timer.notify == SIGEV_THREAD_ID { if let Some(t) = p.tasks().into_iter().find(|t| t.tid() == timer.tid) { signal::send_thread(&t, timer.signo, info); } return; } signal::send(&p, timer.signo, info); } /// (value, interval) of a timer in microseconds: time left, and the period. fn read(timer: &Timer, now: u64) -> (u64, u64) { (timer.next.map_or(0, |at| at.saturating_sub(now).max(1)), timer.interval) } // --- setitimer / getitimer / alarm --------------------------------------- /// getitimer(ITIMER_REAL): (time left, interval), in microseconds. pub fn get_itimer(pid: u64) -> (u64, u64) { let now = time::now_us(); with_table(|t| t.iter().find(|x| x.pid == pid && x.id == ITIMER_ID).map_or((0, 0), |x| read(x, now))) } /// setitimer(ITIMER_REAL, value, interval) (µs; value 0 disarms). Returns /// the old (value, interval). pub fn set_itimer(pid: u64, value: u64, interval: u64) -> (u64, u64) { let now = time::now_us(); let old = with_table(|t| { let old = t.iter().position(|x| x.pid == pid && x.id == ITIMER_ID).map(|i| t.remove(i)); if value > 0 { t.push(Timer { pid, id: ITIMER_ID, clock: CLOCK_MONOTONIC, next: Some(now + value), interval, signo: signal::SIGALRM, notify: SIGEV_SIGNAL, tid: 0, sigval: 0, overrun: 0, }); } old.map_or((0, 0), |x| read(&x, now)) }); if value > 0 { poke(); } old } // --- POSIX timers -------------------------------------------------------- /// What timer_create's `struct sigevent` asked for. pub struct SigEvent { pub notify: i32, pub signo: u32, pub tid: u64, /// None: no sigevent was given, so the value is the timer's id. pub sigval: Option, } /// timer_create: a new, disarmed timer. Returns its id. pub fn create(pid: u64, clock: u64, ev: SigEvent) -> Result { with_table(|t| { let ids: Vec = t.iter().filter(|x| x.pid == pid && x.id != ITIMER_ID).map(|x| x.id).collect(); if ids.len() >= MAX_TIMERS { return Err(Errno::EAGAIN); } let id = (0..).find(|i| !ids.contains(i)).unwrap(); // No sigevent: SIGALRM with the timer id as the value (Linux's default). let sigval = ev.sigval.unwrap_or(id as u64); t.push(Timer { pid, id, clock, next: None, interval: 0, signo: ev.signo, notify: ev.notify, tid: ev.tid, sigval, overrun: 0 }); Ok(id) }) } /// timer_settime: arm (value > 0) or disarm. `absolute`: value is a time on /// the timer's clock, not a delay. Returns the old (value, interval). pub fn settime(pid: u64, id: i32, absolute: bool, value: u64, interval: u64) -> Result<(u64, u64), Errno> { let now = time::now_us(); let old = with_table(|t| { let timer = t.iter_mut().find(|x| x.pid == pid && x.id == id && id != ITIMER_ID).ok_or(Errno::EINVAL)?; let old = read(timer, now); timer.overrun = 0; timer.interval = interval; timer.next = match (value, absolute) { (0, _) => None, (v, false) => Some(now + v), (v, true) if timer.clock == CLOCK_REALTIME => Some(v.saturating_sub(realtime_offset()).max(1)), (v, true) => Some(v.max(1)), // MONOTONIC/BOOTTIME: our own clock }; Ok(old) })?; if value > 0 { poke(); } Ok(old) } /// timer_gettime: (time left, interval) in microseconds. pub fn gettime(pid: u64, id: i32) -> Result<(u64, u64), Errno> { let now = time::now_us(); with_table(|t| t.iter().find(|x| x.pid == pid && x.id == id && id != ITIMER_ID).map(|x| read(x, now)).ok_or(Errno::EINVAL)) } /// timer_getoverrun: periods missed at the last expiry. pub fn getoverrun(pid: u64, id: i32) -> Result { with_table(|t| t.iter().find(|x| x.pid == pid && x.id == id && id != ITIMER_ID).map(|x| x.overrun.min(i32::MAX as u64)).ok_or(Errno::EINVAL)) } /// timer_delete. pub fn delete(pid: u64, id: i32) -> Result<(), Errno> { with_table(|t| { let i = t.iter().position(|x| x.pid == pid && x.id == id && id != ITIMER_ID).ok_or(Errno::EINVAL)?; t.remove(i); Ok(()) }) } /// execve: POSIX timers go, the alarm stays. pub fn exec(pid: u64) { with_table(|t| t.retain(|x| x.pid != pid || x.id == ITIMER_ID)); } /// The process ended: all its timers go. pub fn process_exited(pid: u64) { with_table(|t| t.retain(|x| x.pid != pid)); } /// How many timers exist (tests: nothing left behind). pub fn count() -> usize { with_table(|t| t.len()) }