diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index e5054e19..dbcf37cc 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -5,6 +5,7 @@ const SYSCALL_PIPE: usize = 59; const SYSCALL_READ: usize = 63; const SYSCALL_WRITE: usize = 64; const SYSCALL_EXIT: usize = 93; +const SYSCALL_SLEEP: usize = 101; const SYSCALL_YIELD: usize = 124; const SYSCALL_GET_TIME: usize = 169; const SYSCALL_GETPID: usize = 172; @@ -37,6 +38,7 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { SYSCALL_READ => sys_read(args[0], args[1] as *const u8, args[2]), SYSCALL_WRITE => sys_write(args[0], args[1] as *const u8, args[2]), SYSCALL_EXIT => sys_exit(args[0] as i32), + SYSCALL_SLEEP => sys_sleep(args[0]), SYSCALL_YIELD => sys_yield(), SYSCALL_GET_TIME => sys_get_time(), SYSCALL_GETPID => sys_getpid(), diff --git a/os/src/syscall/sync.rs b/os/src/syscall/sync.rs index 1f080131..c4808c52 100644 --- a/os/src/syscall/sync.rs +++ b/os/src/syscall/sync.rs @@ -1,7 +1,16 @@ -use crate::task::current_process; +use crate::task::{current_task, current_process, block_current_and_run_next}; use crate::sync::{MutexSpin, MutexBlocking}; +use crate::timer::{get_time_ms, add_timer}; use alloc::sync::Arc; +pub fn sys_sleep(ms: usize) -> isize { + let expire_ms = get_time_ms() + ms; + let task = current_task().unwrap(); + add_timer(expire_ms, task); + block_current_and_run_next(); + 0 +} + pub fn sys_mutex_create(blocking: bool) -> isize { let process = current_process(); let mut process_inner = process.inner_exclusive_access(); diff --git a/os/src/timer.rs b/os/src/timer.rs index ad226e64..70c5d72b 100644 --- a/os/src/timer.rs +++ b/os/src/timer.rs @@ -1,6 +1,13 @@ +use core::cmp::Ordering; + use riscv::register::time; use crate::sbi::set_timer; use crate::config::CLOCK_FREQ; +use crate::task::{TaskControlBlock, add_task}; +use crate::sync::UPSafeCell; +use alloc::collections::BinaryHeap; +use alloc::sync::Arc; +use lazy_static::*; const TICKS_PER_SEC: usize = 100; const MSEC_PER_SEC: usize = 1000; @@ -16,3 +23,54 @@ pub fn get_time_ms() -> usize { pub fn set_next_trigger() { set_timer(get_time() + CLOCK_FREQ / TICKS_PER_SEC); } + +pub struct TimerCondVar { + pub expire_ms: usize, + pub task: Arc, +} + +impl PartialEq for TimerCondVar { + fn eq(&self, other: &Self) -> bool { + self.expire_ms == other.expire_ms + } +} +impl Eq for TimerCondVar {} +impl PartialOrd for TimerCondVar { + fn partial_cmp(&self, other: &Self) -> Option { + let a = -(self.expire_ms as isize); + let b = -(other.expire_ms as isize); + Some(a.cmp(&b)) + } +} + +impl Ord for TimerCondVar { + fn cmp(&self, other: &Self) -> Ordering { + self.partial_cmp(other).unwrap() + } +} + +lazy_static! { + static ref TIMERS: UPSafeCell> = unsafe { UPSafeCell::new( + BinaryHeap::::new() + )}; +} + +pub fn add_timer(expire_ms: usize, task: Arc) { + let mut timers = TIMERS.exclusive_access(); + timers.push(TimerCondVar { + expire_ms, + task, + }); +} + +pub fn check_timer() { + let current_ms = get_time_ms(); + let mut timers = TIMERS.exclusive_access(); + while let Some(timer) = timers.peek() { + if timer.expire_ms <= current_ms { + add_task(Arc::clone(&timer.task)); + drop(timer); + timers.pop(); + } else { break; } + } +} diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs index 7f214195..5fd95f5b 100644 --- a/os/src/trap/mod.rs +++ b/os/src/trap/mod.rs @@ -20,7 +20,7 @@ use crate::task::{ current_trap_cx, current_trap_cx_user_va, }; -use crate::timer::set_next_trigger; +use crate::timer::{set_next_trigger, check_timer}; use crate::config::TRAMPOLINE; global_asm!(include_str!("trap.S")); @@ -83,6 +83,7 @@ pub fn trap_handler() -> ! { } Trap::Interrupt(Interrupt::SupervisorTimer) => { set_next_trigger(); + check_timer(); suspend_current_and_run_next(); } _ => { diff --git a/user/src/lib.rs b/user/src/lib.rs index 7d3dd70b..356360e9 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -100,11 +100,8 @@ pub fn waitpid(pid: usize, exit_code: &mut i32) -> isize { } } } -pub fn sleep(period_ms: usize) { - let start = sys_get_time(); - while sys_get_time() < start + period_ms as isize { - sys_yield(); - } +pub fn sleep(sleep_ms: usize) { + sys_sleep(sleep_ms); } pub fn thread_create(entry: usize) -> isize { sys_thread_create(entry) } diff --git a/user/src/syscall.rs b/user/src/syscall.rs index df6f4cb8..793b36dd 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -5,6 +5,7 @@ const SYSCALL_PIPE: usize = 59; const SYSCALL_READ: usize = 63; const SYSCALL_WRITE: usize = 64; const SYSCALL_EXIT: usize = 93; +const SYSCALL_SLEEP: usize = 101; const SYSCALL_YIELD: usize = 124; const SYSCALL_GET_TIME: usize = 169; const SYSCALL_GETPID: usize = 172; @@ -61,6 +62,10 @@ pub fn sys_exit(exit_code: i32) -> ! { panic!("sys_exit never returns!"); } +pub fn sys_sleep(sleep_ms: usize) -> isize { + syscall(SYSCALL_SLEEP, [sleep_ms, 0, 0]) +} + pub fn sys_yield() -> isize { syscall(SYSCALL_YIELD, [0, 0, 0]) }