Add an event system in the Processor. Can sleep and wakeup.

master
WangRunji 7 years ago
parent c02c82cbd6
commit 601d0f85bd

@ -32,6 +32,10 @@ features := $(features) test
qemu_opts := $(qemu_opts) -device isa-debug-exit
endif
ifdef int
qemu_opts := $(qemu_opts) -d int
endif
ifeq ($(OS),Windows_NT)
uname := Win32

@ -72,8 +72,8 @@ interrupt!(com2, {
});
interrupt_switch!(timer, stack, rsp, {
use schedule;
schedule::timer_handler(stack, &mut rsp);
use process;
process::timer_handler(stack, &mut rsp);
ack(IRQ_TIMER);
});

@ -144,11 +144,10 @@ impl ActivePageTable {
pub fn switch(&mut self, new_table: InactivePageTable) -> InactivePageTable {
use x86_64::PhysicalAddress;
use x86_64::registers::control_regs;
debug!("switch table to {:?}", new_table.p4_frame);
let old_table = InactivePageTable {
p4_frame: Frame::of_addr(
control_regs::cr3().0 as usize
),
p4_frame: Frame::of_addr(control_regs::cr3().0 as usize),
};
unsafe {
control_regs::cr3_write(new_table.p4_frame.start_address());

@ -49,7 +49,6 @@ mod consts;
mod process;
mod syscall;
mod fs;
mod schedule;
#[allow(dead_code)]
#[cfg(target_arch = "x86_64")]
@ -106,7 +105,7 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) -> ! {
loop{
println!("init ...");
let mut i = 0;
while i < 1 << 22 {
while i < 1 << 23 {
i += 1;
}
}

@ -31,18 +31,11 @@ pub fn init(mut mc: MemoryController) {
static PROCESSOR: Once<Mutex<Processor>> = Once::new();
static MC: Once<Mutex<MemoryController>> = Once::new();
/// Called by timer handler in arch
/// 设置rsp指向接下来要执行线程的 内核栈顶
/// 之后中断处理例程会重置rsp恢复对应线程的上下文
pub fn schedule(rsp: &mut usize) {
PROCESSOR.try().unwrap().lock().schedule(rsp);
}
extern fn idle_thread() {
loop {
println!("idle ...");
let mut i = 0;
while i < 1 << 22 {
while i < 1 << 23 {
i += 1;
}
}
@ -97,7 +90,21 @@ pub fn sys_exit(rsp: &mut usize, error_code: ErrorCode) -> i32 {
pub fn sys_sleep(rsp: &mut usize, time: usize) -> i32 {
info!("sleep: {} ticks", time);
unimplemented!()
let mut processor = PROCESSOR.try().unwrap().lock();
let pid = processor.current().pid;
processor.schedule(rsp);
processor.sleep(pid, time);
0
}
pub fn sys_get_time() -> i32 {
let processor = PROCESSOR.try().unwrap().lock();
processor.get_time() as i32
}
pub fn timer_handler(tf: &TrapFrame, rsp: &mut usize) {
let mut processor = PROCESSOR.try().unwrap().lock();
processor.tick(rsp);
}
pub fn add_user_process(name: impl AsRef<str>, data: &[u8]) {

@ -24,7 +24,8 @@ pub type ErrorCode = usize;
pub enum Status {
Ready,
Running,
Sleeping(Pid),
Waiting(Pid),
Sleeping,
Exited(ErrorCode),
}

@ -3,10 +3,15 @@ use memory::{ActivePageTable, InactivePageTable};
use super::*;
use core::cell::RefCell;
use core::fmt::{Debug, Formatter, Error};
use util::{EventHub, GetMut2};
pub struct Processor {
procs: BTreeMap<Pid, Process>,
current_pid: Pid,
event_hub: EventHub<Event>,
/// All kernel threads share one page table.
/// When running user process, it will be stored here.
kernel_page_table: Option<InactivePageTable>,
}
impl Processor {
@ -14,6 +19,12 @@ impl Processor {
Processor {
procs: BTreeMap::<Pid, Process>::new(),
current_pid: 0,
event_hub: {
let mut e = EventHub::new();
e.push(100, Event::Schedule);
e
},
kernel_page_table: None,
}
}
@ -29,6 +40,29 @@ impl Processor {
return next;
}
/// Called by timer.
/// Handle events.
pub fn tick(&mut self, rsp: &mut usize) {
self.event_hub.tick();
while let Some(event) = self.event_hub.pop() {
debug!("Processor: event {:?}", event);
match event {
Event::Schedule => {
self.event_hub.push(100, Event::Schedule);
self.schedule(rsp);
},
Event::Wakeup(pid) => {
self.get_mut(pid).status = Status::Ready;
self.switch_to(pid, rsp);
},
}
}
}
pub fn get_time(&self) -> usize {
self.event_hub.get_time()
}
pub fn add(&mut self, mut process: Process) -> Pid {
let pid = self.alloc_pid();
process.pid = pid;
@ -61,7 +95,7 @@ impl Processor {
}
self.current_pid = pid;
let (from, to) = self.get_mut2(pid0, pid);
let (from, to) = self.procs.get_mut2(pid0, pid);
// set `from`
if from.status == Status::Running {
@ -75,10 +109,18 @@ impl Processor {
*rsp = to.rsp;
// switch page table
if let Some(page_table) = to.page_table.take() {
if from.is_user || to.is_user {
let (from_pt, to_pt) = match (from.is_user, to.is_user) {
(true, true) => (&mut from.page_table, &mut to.page_table),
(true, false) => (&mut from.page_table, &mut self.kernel_page_table),
(false, true) => (&mut self.kernel_page_table, &mut to.page_table),
_ => panic!(),
};
assert!(from_pt.is_none());
assert!(to_pt.is_some());
let mut active_table = unsafe { ActivePageTable::new() };
let old_table = active_table.switch(page_table);
from.page_table = Some(old_table);
let old_table = active_table.switch(to_pt.take().unwrap());
*from_pt = Some(old_table);
}
info!("Processor: switch from {} to {}\n rsp: {:#x} -> {:#x}", pid0, pid, rsp0, rsp);
@ -90,14 +132,6 @@ impl Processor {
fn get_mut(&mut self, pid: Pid) -> &mut Process {
self.procs.get_mut(&pid).unwrap()
}
fn get_mut2(&mut self, pid1: Pid, pid2: Pid) -> (&mut Process, &mut Process) {
assert_ne!(pid1, pid2);
let procs1 = &mut self.procs as *mut BTreeMap<_, _>;
let procs2 = procs1;
let p1 = unsafe { &mut *procs1 }.get_mut(&pid1).unwrap();
let p2 = unsafe { &mut *procs2 }.get_mut(&pid2).unwrap();
(p1, p2)
}
pub fn current(&self) -> &Process {
self.get(self.current_pid)
}
@ -121,6 +155,11 @@ impl Processor {
}
}
pub fn sleep(&mut self, pid: Pid, time: usize) {
self.get_mut(pid).status = Status::Sleeping;
self.event_hub.push(time, Event::Wakeup(pid));
}
/// Let current process wait for another
pub fn current_wait_for(&mut self, target: WaitTarget) -> WaitResult {
// Find one target process and it's exit code
@ -145,15 +184,15 @@ impl Processor {
} else {
info!("Processor: {} wait for {}", self.current_pid, pid);
let current_pid = self.current_pid;
self.get_mut(current_pid).status = Status::Sleeping(pid);
self.get_mut(current_pid).status = Status::Waiting(pid);
WaitResult::Blocked
}
}
fn find_waiter(&self, pid: Pid) -> Option<Pid> {
self.procs.values().find(|&p| {
p.status == Status::Sleeping(pid) ||
(p.status == Status::Sleeping(0) && self.get(pid).parent == p.pid)
p.status == Status::Waiting(pid) ||
(p.status == Status::Waiting(0) && self.get(pid).parent == p.pid)
}).map(|ref p| p.pid)
}
}
@ -173,10 +212,23 @@ pub enum WaitTarget {
pub enum WaitResult {
/// The target process is still running.
/// The waiter's status will be set to `Sleeping`.
/// The waiter's status will be set to `Waiting`.
Blocked,
/// The target process is exited with `ErrorCode`.
Ok(ErrorCode),
/// The target process is not exist.
NotExist,
}
#[derive(Debug)]
enum Event {
Schedule,
Wakeup(Pid),
}
impl GetMut2<Pid> for BTreeMap<Pid, Process> {
type Output = Process;
fn get_mut(&mut self, id: Pid) -> &mut Process {
self.get_mut(&id).unwrap()
}
}

@ -1,89 +0,0 @@
use spin::Mutex;
use alloc::BinaryHeap;
use arch::interrupt::TrapFrame;
use core::cmp::{Ordering, PartialOrd};
pub fn get_time() -> i32 {
info!("get_time:");
EVENT_HUB.get_time() as i32
}
pub fn timer_handler(tf: &TrapFrame, rsp: &mut usize) {
// Store rsp to global for `schedule`
*RSP.lock() = Some(*rsp);
EVENT_HUB.tick();
// Take rsp from global
*rsp = RSP.lock().take().unwrap();
}
static RSP: Mutex<Option<usize>> = Mutex::new(None);
fn schedule() {
info!("Schedule at time {}", EVENT_HUB.get_time());
use process;
process::schedule(RSP.lock().as_mut().unwrap());
// Repeat
EVENT_HUB.add(100, schedule);
}
lazy_static! {
static ref EVENT_HUB: EventHub = {
let e = EventHub::default();
e.add(100, schedule);
info!("EventHub: init");
e
};
}
type Time = usize;
type TimerHandler = fn();
#[derive(Debug, Eq, PartialEq)]
struct Timer {
time: Time,
handler: TimerHandler,
}
impl PartialOrd for Timer {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
other.time.partial_cmp(&self.time)
}
}
impl Ord for Timer {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(&other).unwrap()
}
}
#[derive(Default)]
struct EventHub {
tick: Mutex<Time>,
timers: Mutex<BinaryHeap<Timer>>,
}
impl EventHub {
fn tick(&self) {
*self.tick.lock() += 1;
let tick = *self.tick.lock();
loop {
match self.timers.lock().peek() {
None => return,
Some(timer) if timer.time != tick => return,
_ => {}
}
let timer = self.timers.lock().pop().unwrap();
(timer.handler)();
}
}
pub fn add(&self, time_after: Time, handler: TimerHandler) {
let time = self.get_time() + time_after;
self.timers.lock().push(Timer { time, handler });
}
pub fn get_time(&self) -> Time {
*self.tick.lock()
}
}

@ -34,7 +34,7 @@ pub unsafe fn syscall(tf: &TrapFrame, rsp: &mut usize, is32: bool) -> i32 {
Syscall::Ucore(UCORE_SYS_SLEEP) =>
process::sys_sleep(rsp, args[0]),
Syscall::Ucore(UCORE_SYS_GETTIME) =>
schedule::get_time(),
process::sys_get_time(),
Syscall::Ucore(UCORE_SYS_PUTC) =>
{
print!("{}", args[0] as u8 as char);

@ -18,3 +18,87 @@ pub unsafe fn find_in_memory<T: Checkable>
(begin .. begin + len).step_by(step)
.find(|&addr| { (&*(addr as *const T)).check() })
}
use core::ops::IndexMut;
use core::fmt::Debug;
/// Get values by 2 diff keys at the same time
pub trait GetMut2<Idx: Debug + Eq> {
type Output;
fn get_mut(&mut self, id: Idx) -> &mut Self::Output;
fn get_mut2(&mut self, id1: Idx, id2: Idx) -> (&mut Self::Output, &mut Self::Output) {
assert_ne!(id1, id2);
let self1 = self as *mut Self;
let self2 = self1;
let p1 = unsafe { &mut *self1 }.get_mut(id1);
let p2 = unsafe { &mut *self2 }.get_mut(id2);
(p1, p2)
}
}
pub use self::event::EventHub;
mod event {
use alloc::BinaryHeap;
use core::cmp::{Ordering, PartialOrd};
type Time = usize;
struct Timer<T> {
time: Time,
data: T,
}
impl<T> PartialEq for Timer<T> {
fn eq(&self, other: &Self) -> bool {
self.time.eq(&other.time)
}
}
impl<T> Eq for Timer<T> {}
impl<T> PartialOrd for Timer<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
other.time.partial_cmp(&self.time)
}
}
impl<T> Ord for Timer<T> {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(&other).unwrap()
}
}
pub struct EventHub<T> {
tick: Time,
timers: BinaryHeap<Timer<T>>,
}
impl<T> EventHub<T> {
pub fn new() -> Self {
EventHub {
tick: 0,
timers: BinaryHeap::new(),
}
}
pub fn tick(&mut self) {
self.tick += 1;
}
pub fn pop(&mut self) -> Option<T> {
match self.timers.peek() {
None => return None,
Some(timer) if timer.time != self.tick => return None,
_ => {}
};
self.timers.pop().map(|t| t.data)
}
pub fn push(&mut self, time_after: Time, data: T) {
let time = self.tick + time_after;
self.timers.push(Timer { time, data });
}
pub fn get_time(&self) -> Time {
self.tick
}
}
}
Loading…
Cancel
Save