1use super::{
7 errno,
8 signal::{LinuxSignal, SignalState},
9};
10use crate::{
11 abi::linux::riscv64::LinuxRiscv64Abi,
12 arch::Trapframe,
13 sched::scheduler::get_scheduler,
14 task::mytask,
15 time::current_time,
16 timer::{TimerHandler, add_timer, cancel_timer, get_tick, ns_to_ticks, ticks_to_ns},
17};
18use alloc::sync::{Arc, Weak};
19use spin::Mutex;
20
21const NSEC_PER_SEC_I64: i64 = 1_000_000_000;
22const NSEC_PER_SEC_U64: u64 = 1_000_000_000;
23const TIMER_ABSTIME: i32 = 1;
24
25pub struct PosixTimerShared {
27 state: Mutex<PosixTimerState>,
28}
29
30impl PosixTimerShared {
31 fn new(
32 id: u64,
33 clock_id: i32,
34 sigev_notify: i32,
35 sigev_signo: i32,
36 sigev_value: u64,
37 owner_task_id: usize,
38 signal_state: Arc<spin::Mutex<SignalState>>,
39 ) -> Self {
40 Self {
41 state: Mutex::new(PosixTimerState {
42 id,
43 clock_id,
44 sigev_notify,
45 sigev_signo,
46 sigev_value,
47 interval_ns: 0,
48 timer_entry_id: None,
49 next_deadline_tick: None,
50 active: false,
51 owner_task_id,
52 signal_state,
53 overrun_count: 0,
54 }),
55 }
56 }
57
58 fn lock(&self) -> spin::MutexGuard<'_, PosixTimerState> {
59 self.state.lock()
60 }
61}
62
63pub struct PosixTimerState {
65 pub id: u64,
66 pub clock_id: i32,
67 pub sigev_notify: i32,
68 pub sigev_signo: i32,
69 pub sigev_value: u64,
70 pub interval_ns: u64,
71 pub timer_entry_id: Option<u64>,
72 pub next_deadline_tick: Option<u64>,
73 pub active: bool,
74 pub owner_task_id: usize,
75 pub signal_state: Arc<spin::Mutex<SignalState>>,
76 pub overrun_count: u32,
77}
78
79#[derive(Clone)]
81pub struct PosixTimer {
82 pub id: u64,
83 shared: Arc<PosixTimerShared>,
84 handler: Arc<PosixTimerHandler>,
85}
86
87impl PosixTimer {
88 pub fn new(
89 id: u64,
90 clock_id: i32,
91 sigev_notify: i32,
92 sigev_signo: i32,
93 sigev_value: u64,
94 owner_task_id: usize,
95 signal_state: Arc<spin::Mutex<SignalState>>,
96 ) -> Self {
97 let shared = Arc::new(PosixTimerShared::new(
98 id,
99 clock_id,
100 sigev_notify,
101 sigev_signo,
102 sigev_value,
103 owner_task_id,
104 signal_state,
105 ));
106 let handler = Arc::new(PosixTimerHandler {
107 timer_id: id,
108 shared: Arc::downgrade(&shared),
109 });
110 Self {
111 id,
112 shared,
113 handler,
114 }
115 }
116
117 pub fn schedule(&self, first_ns: u64, interval_ns: u64) {
121 let mut state = self.shared.lock();
122 if let Some(entry_id) = state.timer_entry_id.take() {
123 cancel_timer(entry_id);
124 }
125 state.interval_ns = interval_ns;
126 state.overrun_count = 0;
127
128 if first_ns == 0 {
129 state.active = false;
130 state.next_deadline_tick = None;
131 return;
132 }
133
134 let mut ticks = ns_to_ticks(first_ns);
135 if ticks == 0 {
136 ticks = 1;
137 }
138 let target_tick = get_tick().saturating_add(ticks);
139 let handler_dyn: Arc<dyn TimerHandler> = self.handler.clone();
140 let new_id = add_timer(target_tick, &handler_dyn, self.id as usize);
141 state.timer_entry_id = Some(new_id);
142 state.next_deadline_tick = Some(target_tick);
143 state.active = true;
144 }
145
146 pub fn cancel(&self) {
148 let mut state = self.shared.lock();
149 if let Some(entry_id) = state.timer_entry_id.take() {
150 cancel_timer(entry_id);
151 }
152 state.active = false;
153 state.next_deadline_tick = None;
154 }
155
156 pub fn snapshot(&self) -> (u64, u64) {
158 let state = self.shared.lock();
159 let interval = state.interval_ns;
160 let remaining = match state.next_deadline_tick {
161 Some(deadline) => {
162 let now = get_tick();
163 if deadline > now {
164 ticks_to_ns(deadline - now)
165 } else {
166 0
167 }
168 }
169 None => 0,
170 };
171 (remaining, interval)
172 }
173
174 pub fn state(&self) -> spin::MutexGuard<'_, PosixTimerState> {
175 self.shared.lock()
176 }
177}
178
179struct PosixTimerHandler {
180 timer_id: u64,
181 shared: Weak<PosixTimerShared>,
182}
183
184impl TimerHandler for PosixTimerHandler {
185 fn on_timer_expired(self: Arc<Self>, _context: usize) {
186 let Some(shared) = self.shared.upgrade() else {
187 return;
188 };
189
190 let (notify, signo, interval_ns, owner_task_id, signal_state) = {
192 let mut state = shared.lock();
193 if !state.active {
194 return;
195 }
196 state.timer_entry_id = None;
197 state.next_deadline_tick = None;
198 (
199 state.sigev_notify,
200 state.sigev_signo,
201 state.interval_ns,
202 state.owner_task_id,
203 state.signal_state.clone(),
204 )
205 };
206
207 if notify == SIGEV_SIGNAL {
209 if let Some(signal) = LinuxSignal::from_u32(signo as u32) {
210 let mut locked = signal_state.lock();
211 locked.add_pending(signal);
212 drop(locked);
213 let scheduler = get_scheduler();
214 let _ = scheduler.wake_task(owner_task_id);
215 }
216 }
217
218 if notify == SIGEV_NONE {
219 }
221
222 if interval_ns > 0 {
224 let mut state = shared.lock();
225 let mut ticks = ns_to_ticks(interval_ns);
226 if ticks == 0 {
227 ticks = 1;
228 }
229 let target_tick = get_tick().saturating_add(ticks);
230 let handler_dyn: Arc<dyn TimerHandler> = self.clone();
231 let entry_id = add_timer(target_tick, &handler_dyn, self.timer_id as usize);
232 state.timer_entry_id = Some(entry_id);
233 state.next_deadline_tick = Some(target_tick);
234 state.active = true;
235 } else {
236 let mut state = shared.lock();
237 state.active = false;
238 }
239 }
240}
241
242pub const SIGEV_SIGNAL: i32 = 0;
244pub const SIGEV_NONE: i32 = 1;
245pub const SIGEV_THREAD: i32 = 2;
246pub const SIGEV_THREAD_ID: i32 = 4;
247
248fn is_supported_clock(clock_id: i32) -> bool {
249 matches!(
250 clock_id,
251 CLOCK_REALTIME
252 | CLOCK_MONOTONIC
253 | CLOCK_PROCESS_CPUTIME_ID
254 | CLOCK_THREAD_CPUTIME_ID
255 | CLOCK_MONOTONIC_RAW
256 | CLOCK_REALTIME_COARSE
257 | CLOCK_MONOTONIC_COARSE
258 | CLOCK_BOOTTIME
259 )
260}
261
262fn timespec_to_ns(ts: &TimeSpec) -> Result<u64, usize> {
263 if ts.tv_sec < 0 || ts.tv_nsec < 0 || ts.tv_nsec >= NSEC_PER_SEC_I64 {
264 return Err(errno::EINVAL);
265 }
266 let sec = ts.tv_sec as u128;
267 let nsec = ts.tv_nsec as u128;
268 let total = sec
269 .saturating_mul(NSEC_PER_SEC_U64 as u128)
270 .saturating_add(nsec);
271 Ok(total.min(u64::MAX as u128) as u64)
272}
273
274fn ns_to_timespec(ns: u64) -> TimeSpec {
275 let sec = (ns / NSEC_PER_SEC_U64).min(i64::MAX as u64);
276 let nsec = if sec >= i64::MAX as u64 {
277 (NSEC_PER_SEC_U64 - 1) as i64
278 } else {
279 (ns % NSEC_PER_SEC_U64) as i64
280 };
281 TimeSpec {
282 tv_sec: sec as i64,
283 tv_nsec: nsec,
284 }
285}
286
287#[repr(C)]
289#[derive(Debug, Clone, Copy)]
290pub struct TimeSpec {
291 pub tv_sec: i64, pub tv_nsec: i64, }
294
295#[repr(C)]
297#[derive(Clone, Copy)]
298struct ItimerSpec {
299 it_interval: TimeSpec,
300 it_value: TimeSpec,
301}
302
303pub const CLOCK_REALTIME: i32 = 0;
305pub const CLOCK_MONOTONIC: i32 = 1;
306pub const CLOCK_PROCESS_CPUTIME_ID: i32 = 2;
307pub const CLOCK_THREAD_CPUTIME_ID: i32 = 3;
308pub const CLOCK_MONOTONIC_RAW: i32 = 4;
309pub const CLOCK_REALTIME_COARSE: i32 = 5;
310pub const CLOCK_MONOTONIC_COARSE: i32 = 6;
311pub const CLOCK_BOOTTIME: i32 = 7;
312
313pub fn sys_timer_create(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
317 let task = match mytask() {
318 Some(task) => task,
319 None => return errno::to_result(errno::EFAULT),
320 };
321
322 let clock_id = trapframe.get_arg(0) as i32;
323 let sevp_ptr = trapframe.get_arg(1);
324 let timerid_ptr = trapframe.get_arg(2);
325
326 trapframe.increment_pc_next(&task);
327
328 if !is_supported_clock(clock_id) {
329 return errno::to_result(errno::EINVAL);
330 }
331
332 if timerid_ptr == 0 {
333 return errno::to_result(errno::EFAULT);
334 }
335
336 let timerid_paddr = match task.vm_manager.translate_vaddr(timerid_ptr) {
337 Some(ptr) => ptr as *mut u64,
338 None => return errno::to_result(errno::EFAULT),
339 };
340
341 let mut sigev_notify = SIGEV_SIGNAL;
343 let mut sigev_signo = LinuxSignal::SIGALRM as i32;
344 let mut sigev_value = 0u64;
345
346 if sevp_ptr != 0 {
347 let sevp_paddr = match task.vm_manager.translate_vaddr(sevp_ptr) {
348 Some(addr) => addr,
349 None => return errno::to_result(errno::EFAULT),
350 };
351
352 unsafe {
353 let base = sevp_paddr as *const u8;
354 sigev_value = *(base as *const u64);
355 sigev_signo = *(base.add(8) as *const i32);
356 sigev_notify = *(base.add(12) as *const i32);
357 }
358
359 match sigev_notify {
360 SIGEV_SIGNAL => {
361 if sigev_signo <= 0 || LinuxSignal::from_u32(sigev_signo as u32).is_none() {
362 return errno::to_result(errno::EINVAL);
363 }
364 }
365 SIGEV_NONE => {
366 }
368 SIGEV_THREAD | SIGEV_THREAD_ID => {
369 return errno::to_result(errno::ENOSYS);
371 }
372 _ => {
373 return errno::to_result(errno::EINVAL);
374 }
375 }
376 }
377
378 let timer_id = abi.allocate_posix_timer_id();
379 let timer = PosixTimer::new(
380 timer_id,
381 clock_id,
382 sigev_notify,
383 sigev_signo,
384 sigev_value,
385 task.get_id(),
386 abi.signal_state.clone(),
387 );
388 abi.store_posix_timer(timer);
389
390 unsafe {
391 *timerid_paddr = timer_id as u64;
392 }
393
394 trapframe.set_return_value(0);
395 0
396}
397
398pub fn sys_timer_settime(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
400 let task = match mytask() {
401 Some(task) => task,
402 None => return errno::to_result(errno::EFAULT),
403 };
404
405 let timer_id = trapframe.get_arg(0) as u64;
406 let flags = trapframe.get_arg(1) as i32;
407 let new_value_ptr = trapframe.get_arg(2);
408 let old_value_ptr = trapframe.get_arg(3);
409
410 trapframe.increment_pc_next(&task);
411
412 if (flags & !TIMER_ABSTIME) != 0 {
413 return errno::to_result(errno::EINVAL);
414 }
415 if (flags & TIMER_ABSTIME) != 0 {
416 return errno::to_result(errno::ENOSYS);
417 }
418 if new_value_ptr == 0 {
419 return errno::to_result(errno::EINVAL);
420 }
421
422 let timer = match abi.get_posix_timer(timer_id) {
423 Some(timer) => timer,
424 None => return errno::to_result(errno::EINVAL),
425 };
426
427 let new_value_paddr = match task.vm_manager.translate_vaddr(new_value_ptr) {
428 Some(addr) => addr,
429 None => return errno::to_result(errno::EFAULT),
430 };
431
432 let new_spec = unsafe { *(new_value_paddr as *const ItimerSpec) };
433
434 let first_ns = match timespec_to_ns(&new_spec.it_value) {
435 Ok(ns) => ns,
436 Err(errno_val) => return errno::to_result(errno_val),
437 };
438 let interval_ns = match timespec_to_ns(&new_spec.it_interval) {
439 Ok(ns) => ns,
440 Err(errno_val) => return errno::to_result(errno_val),
441 };
442
443 if old_value_ptr != 0 {
444 let old_value_paddr = match task.vm_manager.translate_vaddr(old_value_ptr) {
445 Some(addr) => addr as *mut ItimerSpec,
446 None => return errno::to_result(errno::EFAULT),
447 };
448 let (remaining_ns, previous_interval_ns) = timer.snapshot();
449 let snapshot = ItimerSpec {
450 it_interval: ns_to_timespec(previous_interval_ns),
451 it_value: ns_to_timespec(remaining_ns),
452 };
453 unsafe {
454 *old_value_paddr = snapshot;
455 }
456 }
457
458 timer.schedule(first_ns, interval_ns);
459
460 trapframe.set_return_value(0);
461 0
462}
463
464pub fn sys_timer_gettime(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
466 let task = match mytask() {
467 Some(task) => task,
468 None => return errno::to_result(errno::EFAULT),
469 };
470
471 let timer_id = trapframe.get_arg(0) as u64;
472 let setting_ptr = trapframe.get_arg(1);
473
474 trapframe.increment_pc_next(&task);
475
476 if setting_ptr == 0 {
477 return errno::to_result(errno::EFAULT);
478 }
479
480 let timer = match abi.get_posix_timer(timer_id) {
481 Some(timer) => timer,
482 None => return errno::to_result(errno::EINVAL),
483 };
484
485 let setting_paddr = match task.vm_manager.translate_vaddr(setting_ptr) {
486 Some(addr) => addr as *mut ItimerSpec,
487 None => return errno::to_result(errno::EFAULT),
488 };
489
490 let (remaining_ns, interval_ns) = timer.snapshot();
491 let current = ItimerSpec {
492 it_interval: ns_to_timespec(interval_ns),
493 it_value: ns_to_timespec(remaining_ns),
494 };
495
496 unsafe {
497 *setting_paddr = current;
498 }
499
500 trapframe.set_return_value(0);
501 0
502}
503
504pub fn sys_timer_getoverrun(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
506 let task = match mytask() {
507 Some(task) => task,
508 None => return errno::to_result(errno::EFAULT),
509 };
510
511 let timer_id = trapframe.get_arg(0) as u64;
512
513 trapframe.increment_pc_next(&task);
514
515 let timer = match abi.get_posix_timer(timer_id) {
516 Some(timer) => timer,
517 None => return errno::to_result(errno::EINVAL),
518 };
519
520 let overrun = {
521 let state = timer.state();
522 state.overrun_count as usize
523 };
524
525 trapframe.set_return_value(overrun);
526 overrun
527}
528
529pub fn sys_timer_delete(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
531 let task = match mytask() {
532 Some(task) => task,
533 None => return errno::to_result(errno::EFAULT),
534 };
535
536 let timer_id = trapframe.get_arg(0) as u64;
537
538 trapframe.increment_pc_next(&task);
539
540 let timer = match abi.remove_posix_timer(timer_id) {
541 Some(timer) => timer,
542 None => return errno::to_result(errno::EINVAL),
543 };
544
545 timer.cancel();
546
547 trapframe.set_return_value(0);
548 0
549}
550
551pub fn sys_clock_gettime(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
562 let task = mytask().expect("No current task found");
563 let clock_id = trapframe.get_arg(0) as i32; trapframe.increment_pc_next(&task);
566
567 let timespec_ptr = match task.vm_manager.translate_vaddr(trapframe.get_arg(1)) {
568 Some(ptr) => ptr as *mut TimeSpec, None => return (-14_isize) as usize, };
571
572 let timespec = match clock_id {
574 CLOCK_REALTIME | CLOCK_REALTIME_COARSE => {
575 let time_us = current_time();
578 TimeSpec {
579 tv_sec: (time_us / 1_000_000) as i64,
580 tv_nsec: ((time_us % 1_000_000) * 1000) as i64,
581 }
582 }
583 CLOCK_MONOTONIC | CLOCK_MONOTONIC_RAW | CLOCK_MONOTONIC_COARSE => {
584 let time_us = current_time();
586 TimeSpec {
587 tv_sec: (time_us / 1_000_000) as i64,
588 tv_nsec: ((time_us % 1_000_000) * 1000) as i64,
589 }
590 }
591 CLOCK_BOOTTIME => {
592 let time_us = current_time();
594 TimeSpec {
595 tv_sec: (time_us / 1_000_000) as i64,
596 tv_nsec: ((time_us % 1_000_000) * 1000) as i64,
597 }
598 }
599 CLOCK_PROCESS_CPUTIME_ID | CLOCK_THREAD_CPUTIME_ID => {
600 let time_us = current_time();
603 TimeSpec {
604 tv_sec: (time_us / 1_000_000) as i64,
605 tv_nsec: ((time_us % 1_000_000) * 1000) as i64,
606 }
607 }
608 _ => {
609 return (-22_isize) as usize; }
611 };
612
613 unsafe {
615 *timespec_ptr = timespec;
616 }
617
618 0 }
620
621pub fn sys_nanosleep(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
632 let task = match mytask() {
634 Some(task) => task,
635 None => return (-14_isize) as usize, };
637 trapframe.increment_pc_next(&task);
638
639 let rqtp_ptr = trapframe.get_arg(0);
641 let _rmtp_ptr = trapframe.get_arg(1);
642 let rqtp = match task.vm_manager.translate_vaddr(rqtp_ptr) {
643 Some(ptr) => unsafe { &*(ptr as *const TimeSpec) },
644 None => return (-14_isize) as usize, };
646 let ns = rqtp
648 .tv_sec
649 .saturating_mul(1_000_000_000)
650 .saturating_add(rqtp.tv_nsec);
651 if ns <= 0 {
652 return 0;
653 }
654 let ticks = ns_to_ticks(ns as u64);
656 trapframe.set_return_value(0); task.sleep(trapframe, ticks);
659 0
661}
662
663pub fn sys_clock_getres(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
678 let task = match mytask() {
679 Some(t) => t,
680 None => return usize::MAX,
681 };
682
683 let _clk_id = trapframe.get_arg(0) as i32;
684 let res_ptr = trapframe.get_arg(1);
685
686 trapframe.increment_pc_next(task);
688
689 if res_ptr != 0 {
691 if let Some(res_paddr) = task.vm_manager.translate_vaddr(res_ptr) {
692 unsafe {
693 let timespec = res_paddr as *mut [u64; 2];
696 *timespec = [
697 0, 1_000_000, ];
700 }
701 }
702 }
703
704 0 }
706
707#[cfg(test)]
708mod tests {
709 use super::*;
710
711 #[test_case]
712 fn test_timespec_size() {
713 assert_eq!(core::mem::size_of::<TimeSpec>(), 16);
715 assert_eq!(core::mem::align_of::<TimeSpec>(), 8);
716 }
717
718 #[test_case]
719 fn test_clock_constants() {
720 assert_eq!(CLOCK_REALTIME, 0);
722 assert_eq!(CLOCK_MONOTONIC, 1);
723 assert_eq!(CLOCK_PROCESS_CPUTIME_ID, 2);
724 assert_eq!(CLOCK_THREAD_CPUTIME_ID, 3);
725 }
726}