Implement sleep using blocking & BinaryHeap.
This commit is contained in:
parent
db6a93e60d
commit
c951c1781e
6 changed files with 79 additions and 7 deletions
|
@ -5,6 +5,7 @@ const SYSCALL_PIPE: usize = 59;
|
||||||
const SYSCALL_READ: usize = 63;
|
const SYSCALL_READ: usize = 63;
|
||||||
const SYSCALL_WRITE: usize = 64;
|
const SYSCALL_WRITE: usize = 64;
|
||||||
const SYSCALL_EXIT: usize = 93;
|
const SYSCALL_EXIT: usize = 93;
|
||||||
|
const SYSCALL_SLEEP: usize = 101;
|
||||||
const SYSCALL_YIELD: usize = 124;
|
const SYSCALL_YIELD: usize = 124;
|
||||||
const SYSCALL_GET_TIME: usize = 169;
|
const SYSCALL_GET_TIME: usize = 169;
|
||||||
const SYSCALL_GETPID: usize = 172;
|
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_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_WRITE => sys_write(args[0], args[1] as *const u8, args[2]),
|
||||||
SYSCALL_EXIT => sys_exit(args[0] as i32),
|
SYSCALL_EXIT => sys_exit(args[0] as i32),
|
||||||
|
SYSCALL_SLEEP => sys_sleep(args[0]),
|
||||||
SYSCALL_YIELD => sys_yield(),
|
SYSCALL_YIELD => sys_yield(),
|
||||||
SYSCALL_GET_TIME => sys_get_time(),
|
SYSCALL_GET_TIME => sys_get_time(),
|
||||||
SYSCALL_GETPID => sys_getpid(),
|
SYSCALL_GETPID => sys_getpid(),
|
||||||
|
|
|
@ -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::sync::{MutexSpin, MutexBlocking};
|
||||||
|
use crate::timer::{get_time_ms, add_timer};
|
||||||
use alloc::sync::Arc;
|
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 {
|
pub fn sys_mutex_create(blocking: bool) -> isize {
|
||||||
let process = current_process();
|
let process = current_process();
|
||||||
let mut process_inner = process.inner_exclusive_access();
|
let mut process_inner = process.inner_exclusive_access();
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
|
use core::cmp::Ordering;
|
||||||
|
|
||||||
use riscv::register::time;
|
use riscv::register::time;
|
||||||
use crate::sbi::set_timer;
|
use crate::sbi::set_timer;
|
||||||
use crate::config::CLOCK_FREQ;
|
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 TICKS_PER_SEC: usize = 100;
|
||||||
const MSEC_PER_SEC: usize = 1000;
|
const MSEC_PER_SEC: usize = 1000;
|
||||||
|
@ -16,3 +23,54 @@ pub fn get_time_ms() -> usize {
|
||||||
pub fn set_next_trigger() {
|
pub fn set_next_trigger() {
|
||||||
set_timer(get_time() + CLOCK_FREQ / TICKS_PER_SEC);
|
set_timer(get_time() + CLOCK_FREQ / TICKS_PER_SEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct TimerCondVar {
|
||||||
|
pub expire_ms: usize,
|
||||||
|
pub task: Arc<TaskControlBlock>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Ordering> {
|
||||||
|
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<BinaryHeap<TimerCondVar>> = unsafe { UPSafeCell::new(
|
||||||
|
BinaryHeap::<TimerCondVar>::new()
|
||||||
|
)};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_timer(expire_ms: usize, task: Arc<TaskControlBlock>) {
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ use crate::task::{
|
||||||
current_trap_cx,
|
current_trap_cx,
|
||||||
current_trap_cx_user_va,
|
current_trap_cx_user_va,
|
||||||
};
|
};
|
||||||
use crate::timer::set_next_trigger;
|
use crate::timer::{set_next_trigger, check_timer};
|
||||||
use crate::config::TRAMPOLINE;
|
use crate::config::TRAMPOLINE;
|
||||||
|
|
||||||
global_asm!(include_str!("trap.S"));
|
global_asm!(include_str!("trap.S"));
|
||||||
|
@ -83,6 +83,7 @@ pub fn trap_handler() -> ! {
|
||||||
}
|
}
|
||||||
Trap::Interrupt(Interrupt::SupervisorTimer) => {
|
Trap::Interrupt(Interrupt::SupervisorTimer) => {
|
||||||
set_next_trigger();
|
set_next_trigger();
|
||||||
|
check_timer();
|
||||||
suspend_current_and_run_next();
|
suspend_current_and_run_next();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
@ -100,11 +100,8 @@ pub fn waitpid(pid: usize, exit_code: &mut i32) -> isize {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn sleep(period_ms: usize) {
|
pub fn sleep(sleep_ms: usize) {
|
||||||
let start = sys_get_time();
|
sys_sleep(sleep_ms);
|
||||||
while sys_get_time() < start + period_ms as isize {
|
|
||||||
sys_yield();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn thread_create(entry: usize) -> isize { sys_thread_create(entry) }
|
pub fn thread_create(entry: usize) -> isize { sys_thread_create(entry) }
|
||||||
|
|
|
@ -5,6 +5,7 @@ const SYSCALL_PIPE: usize = 59;
|
||||||
const SYSCALL_READ: usize = 63;
|
const SYSCALL_READ: usize = 63;
|
||||||
const SYSCALL_WRITE: usize = 64;
|
const SYSCALL_WRITE: usize = 64;
|
||||||
const SYSCALL_EXIT: usize = 93;
|
const SYSCALL_EXIT: usize = 93;
|
||||||
|
const SYSCALL_SLEEP: usize = 101;
|
||||||
const SYSCALL_YIELD: usize = 124;
|
const SYSCALL_YIELD: usize = 124;
|
||||||
const SYSCALL_GET_TIME: usize = 169;
|
const SYSCALL_GET_TIME: usize = 169;
|
||||||
const SYSCALL_GETPID: usize = 172;
|
const SYSCALL_GETPID: usize = 172;
|
||||||
|
@ -61,6 +62,10 @@ pub fn sys_exit(exit_code: i32) -> ! {
|
||||||
panic!("sys_exit never returns!");
|
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 {
|
pub fn sys_yield() -> isize {
|
||||||
syscall(SYSCALL_YIELD, [0, 0, 0])
|
syscall(SYSCALL_YIELD, [0, 0, 0])
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue