Multicore processing WORKS! Basically ...

- Rewrite processor.rs
  Refactor to `Processor` & `ProcessManager`
- Use Box<dyn> instead of generic.
- Wait/sleep/wakeup is not supported yet.
  I'm considering to implement them with WaitQueue.
toolchain_update
WangRunji 6 years ago
parent 6741ba399b
commit f7eb09e856

@ -5,3 +5,4 @@ authors = ["WangRunji <wangrunji0408@163.com>"]
[dependencies] [dependencies]
log = "0.4" log = "0.4"
spin = "0.4"

@ -5,6 +5,7 @@
extern crate alloc; extern crate alloc;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
extern crate spin;
// To use `println!` in test // To use `println!` in test
#[cfg(test)] #[cfg(test)]

@ -1,273 +1,208 @@
use alloc::{boxed::Box, collections::BTreeMap}; use alloc::boxed::Box;
use scheduler::*; use alloc::vec::Vec;
use event_hub::EventHub; use alloc::sync::Arc;
use util::GetMut2; use spin::Mutex;
use core::fmt::Debug; use scheduler::Scheduler;
use core::cell::UnsafeCell;
#[derive(Debug)]
pub struct Process<T> { /// Process executor
pid: Pid, ///
parent: Pid, /// Per-CPU struct. Defined at global.
status: Status, /// Only accessed by associated CPU with interrupt disabled.
context: T, #[derive(Default)]
pub struct Processor {
inner: UnsafeCell<Option<ProcessorInner>>,
} }
pub type Pid = usize; unsafe impl Sync for Processor {}
pub type ErrorCode = usize;
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Status {
Ready,
Running,
Waiting(Pid),
Sleeping,
Exited(ErrorCode),
}
pub trait Context: Debug { struct ProcessorInner {
unsafe fn switch(&mut self, target: &mut Self); id: usize,
fn new_kernel(entry: extern fn(usize) -> !, arg: usize) -> Self; proc: Option<(Pid, Box<Context>)>,
loop_context: Box<Context>,
manager: Arc<ProcessManager>,
} }
pub struct Processor_<T: Context, S: Scheduler> { impl Processor {
procs: BTreeMap<Pid, Process<T>>, pub const fn new() -> Self {
current_pid: Pid, Processor { inner: UnsafeCell::new(None) }
event_hub: EventHub<Event>,
// WARNING: if MAX_PROCESS_NUM is too large, will cause stack overflow
scheduler: S,
}
impl<T> Process<T> {
fn exit_code(&self) -> Option<ErrorCode> {
match self.status {
Status::Exited(code) => Some(code),
_ => None,
}
} }
}
// TODO: 除schedule()外的其它函数应该只设置进程状态不应调用schedule pub unsafe fn init(&self, id: usize, context: Box<Context>, manager: Arc<ProcessManager>) {
impl<T: Context, S: Scheduler> Processor_<T, S> { unsafe {
pub fn new(init_context: T, scheduler: S) -> Self { *self.inner.get() = Some(ProcessorInner {
let init_proc = Process { id,
pid: 0, proc: None,
parent: 0, loop_context: context,
status: Status::Running, manager,
context: init_context, });
};
Processor_ {
procs: {
let mut map = BTreeMap::<Pid, Process<T>>::new();
map.insert(0, init_proc);
map
},
current_pid: 0,
event_hub: EventHub::new(),
scheduler,
} }
} }
pub fn set_priority(&mut self, priority: u8) { fn inner(&self) -> &mut ProcessorInner {
self.scheduler.set_priority(self.current_pid, priority); unsafe { &mut *self.inner.get() }.as_mut()
} .expect("Processor is not initialized")
}
pub fn yield_now(&mut self) {
let pid = self.current_pid; /// Begin running processes after CPU setup.
self.set_status(pid, Status::Ready); ///
} /// This function never returns. It loops, doing:
/// - choose a process to run
fn alloc_pid(&self) -> Pid { /// - switch to start running that process
let mut next: Pid = 0; /// - eventually that process transfers control
for &i in self.procs.keys() { /// via switch back to the scheduler.
if i != next { pub fn run(&self) -> ! {
return next; let inner = self.inner();
} else { loop {
next = i + 1; let proc = inner.manager.run(inner.id);
trace!("CPU{} begin running process {}", inner.id, proc.0);
inner.proc = Some(proc);
unsafe {
inner.loop_context.switch_to(&mut *inner.proc.as_mut().unwrap().1);
} }
let (pid, context) = inner.proc.take().unwrap();
trace!("CPU{} stop running process {}", inner.id, pid);
inner.manager.stop(pid, context);
} }
return next;
} }
fn set_status(&mut self, pid: Pid, status: Status) { /// Called by process running on this Processor.
let status0 = self.get(pid).status.clone(); /// Yield and reschedule.
match (&status0, &status) { pub fn yield_now(&self) {
(&Status::Ready, &Status::Ready) => return, let inner = self.inner();
(&Status::Ready, _) => self.scheduler.remove(pid), unsafe {
(_, &Status::Ready) => self.scheduler.insert(pid), inner.proc.as_mut().unwrap().1.switch_to(&mut *inner.loop_context);
_ => {}
} }
trace!("process {} {:?} -> {:?}", pid, status0, status);
self.get_mut(pid).status = status;
} }
/// Called by timer. pub fn pid(&self) -> Pid {
/// Handle events. self.inner().proc.as_ref().unwrap().0
pub fn tick(&mut self) {
let current_pid = self.current_pid;
if self.scheduler.tick(current_pid) {
self.yield_now();
}
self.event_hub.tick();
while let Some(event) = self.event_hub.pop() {
debug!("event {:?}", event);
match event {
Event::Schedule => {
self.event_hub.push(10, Event::Schedule);
self.yield_now();
},
Event::Wakeup(pid) => {
self.set_status(pid, Status::Ready);
self.yield_now();
self.scheduler.move_to_head(pid);
},
}
}
} }
pub fn get_time(&self) -> usize { pub fn manager(&self) -> &ProcessManager {
self.event_hub.get_time() &*self.inner().manager
} }
pub fn add(&mut self, context: T) -> Pid { pub fn tick(&self) {
let pid = self.alloc_pid(); let need_reschedule = self.manager().tick(self.pid());
let process = Process { if need_reschedule {
pid, self.yield_now();
parent: self.current_pid,
status: Status::Ready,
context,
};
self.scheduler.insert(pid);
self.procs.insert(pid, process);
pid
}
/// Called every interrupt end
/// Do schedule ONLY IF current status != Running
pub fn schedule(&mut self) {
if self.get(self.current_pid).status == Status::Running {
return;
} }
let pid = self.scheduler.select().unwrap();
self.switch_to(pid);
} }
}
/// Switch to process `pid`. struct Process {
/// The current status must be set before, and not be `Running`. id: Pid,
/// The target status must be `Ready`. status: Status,
fn switch_to(&mut self, pid: Pid) { status_after_stop: Status,
// for debug print context: Option<Box<Context>>,
let pid0 = self.current_pid; }
if pid == self.current_pid {
if self.get(self.current_pid).status != Status::Running {
self.set_status(pid, Status::Running);
}
return;
}
self.current_pid = pid;
let (from, to) = self.procs.get_mut2(pid0, pid); type Pid = usize;
type ExitCode = usize;
const MAX_PROC_NUM: usize = 32;
assert_ne!(from.status, Status::Running); #[derive(Debug, Clone, Eq, PartialEq)]
assert_eq!(to.status, Status::Ready); pub enum Status {
to.status = Status::Running; Ready,
self.scheduler.remove(pid); Running(usize),
Waiting(Pid),
Sleeping,
Exited(ExitCode),
}
info!("switch from {} to {} {:x?}", pid0, pid, to.context); pub trait Context {
unsafe { from.context.switch(&mut to.context); } unsafe fn switch_to(&mut self, target: &mut Context);
} }
fn get(&self, pid: Pid) -> &Process<T> { pub struct ProcessManager {
self.procs.get(&pid).unwrap() procs: [Mutex<Option<Process>>; MAX_PROC_NUM],
} scheduler: Mutex<Box<Scheduler>>,
fn get_mut(&mut self, pid: Pid) -> &mut Process<T> { }
self.procs.get_mut(&pid).unwrap()
}
pub fn current_context(&self) -> &T {
&self.get(self.current_pid).context
}
pub fn current_pid(&self) -> Pid {
self.current_pid
}
pub fn kill(&mut self, pid: Pid) { impl ProcessManager {
self.exit(pid, 0x1000); // TODO: error code for killed
}
pub fn exit(&mut self, pid: Pid, error_code: ErrorCode) { pub fn new(scheduler: Box<Scheduler>) -> Self {
info!("{} exit, code: {}", pid, error_code); ProcessManager {
self.set_status(pid, Status::Exited(error_code)); procs: Default::default(),
if let Some(waiter) = self.find_waiter(pid) { scheduler: Mutex::new(scheduler),
info!(" then wakeup {}", waiter);
self.set_status(waiter, Status::Ready);
self.scheduler.move_to_head(waiter);
} }
} }
pub fn sleep(&mut self, pid: Pid, time: usize) { fn alloc_pid(&self) -> Pid {
self.set_status(pid, Status::Sleeping); for i in 0..MAX_PROC_NUM {
self.event_hub.push(time, Event::Wakeup(pid)); if self.procs[i].lock().is_none() {
} return i;
pub fn sleep_(&mut self, pid: Pid) { }
self.set_status(pid, Status::Sleeping); }
} panic!("Process number exceeded");
pub fn wakeup_(&mut self, pid: Pid) {
self.set_status(pid, Status::Ready);
} }
/// Let current process wait for another /// Add a new process
pub fn current_wait_for(&mut self, pid: Pid) -> WaitResult { pub fn add(&self, context: Box<Context>) -> Pid {
info!("current {} wait for {:?}", self.current_pid, pid); let pid = self.alloc_pid();
if self.procs.values().filter(|&p| p.parent == self.current_pid).next().is_none() { // TODO: check parent
return WaitResult::NotExist; *self.procs[pid].lock() = Some(Process {
} id: pid,
let pid = self.try_wait(pid).unwrap_or_else(|| { status: Status::Ready,
let current_pid = self.current_pid; status_after_stop: Status::Ready,
self.set_status(current_pid, Status::Waiting(pid)); context: Some(context),
self.schedule(); // yield
self.try_wait(pid).unwrap()
}); });
let exit_code = self.get(pid).exit_code().unwrap(); self.scheduler.lock().insert(pid);
info!("{} wait end and remove {}", self.current_pid, pid); pid
self.procs.remove(&pid);
WaitResult::Ok(pid, exit_code)
} }
/// Try to find a exited wait target /// Make process `pid` time slice -= 1.
fn try_wait(&mut self, pid: Pid) -> Option<Pid> { /// Return true if time slice == 0.
match pid { /// Called by timer interrupt handler.
0 => self.procs.values() pub fn tick(&self, pid: Pid) -> bool {
.find(|&p| p.parent == self.current_pid && p.exit_code().is_some()) self.scheduler.lock().tick(pid)
.map(|p| p.pid), }
_ => self.get(pid).exit_code().map(|_| pid),
/// Called by Processor to get a process to run.
/// The manager first mark it `Running`,
/// then take out and return its Context.
pub fn run(&self, cpu_id: usize) -> (Pid, Box<Context>) {
let mut scheduler = self.scheduler.lock();
let pid = scheduler.select()
.expect("failed to select a runnable process");
scheduler.remove(pid);
let mut proc_lock = self.procs[pid].lock();
let mut proc = proc_lock.as_mut().unwrap();
proc.status = Status::Running(cpu_id);
(pid, proc.context.take().unwrap())
}
/// Called by Processor to finish running a process
/// and give its context back.
pub fn stop(&self, pid: Pid, context: Box<Context>) {
let mut proc_lock = self.procs[pid].lock();
let mut proc = proc_lock.as_mut().unwrap();
proc.status = proc.status_after_stop.clone();
proc.status_after_stop = Status::Ready;
proc.context = Some(context);
if proc.status == Status::Ready {
self.scheduler.lock().insert(pid);
} }
} }
fn find_waiter(&self, pid: Pid) -> Option<Pid> { /// Switch the status of a process.
self.procs.values().find(|&p| { /// Insert/Remove it to/from scheduler if necessary.
p.status == Status::Waiting(pid) || pub fn set_status(&self, pid: Pid, status: Status) {
(p.status == Status::Waiting(0) && self.get(pid).parent == p.pid) let mut scheduler = self.scheduler.lock();
}).map(|ref p| p.pid) let mut proc_lock = self.procs[pid].lock();
} let mut proc = proc_lock.as_mut().unwrap();
} match (&proc.status, &status) {
(Status::Ready, Status::Ready) => return,
#[derive(Debug)] (Status::Ready, _) => scheduler.remove(pid),
pub enum WaitResult { (Status::Running(_), _) => {},
/// The target process is exited with `ErrorCode`. (_, Status::Ready) => scheduler.insert(pid),
Ok(Pid, ErrorCode), _ => {}
/// The target process is not exist. }
NotExist, trace!("process {} {:?} -> {:?}", pid, proc.status, status);
} match proc.status {
Status::Running(_) => proc.status_after_stop = status,
#[derive(Debug)] _ => proc.status = status,
enum Event { }
Schedule,
Wakeup(Pid),
}
impl<T: Context> GetMut2<Pid> for BTreeMap<Pid, Process<T>> {
type Output = Process<T>;
fn get_mut(&mut self, id: Pid) -> &mut Process<T> {
self.get_mut(&id).unwrap()
} }
} }

@ -38,10 +38,8 @@ use scheduler::Scheduler;
/// All dependencies for thread mod. /// All dependencies for thread mod.
pub trait ThreadSupport { pub trait ThreadSupport {
type Context: Context; fn processor() -> &'static Processor;
type Scheduler: Scheduler; fn new_kernel(entry: extern fn(usize) -> !, arg: usize) -> Box<Context>;
type ProcessorGuard: DerefMut<Target=Processor_<Self::Context, Self::Scheduler>>;
fn processor() -> Self::ProcessorGuard;
} }
/// Root structure served as thread mod /// Root structure served as thread mod
@ -53,7 +51,7 @@ impl<S: ThreadSupport> ThreadMod<S> {
/// Gets a handle to the thread that invokes it. /// Gets a handle to the thread that invokes it.
pub fn current() -> Thread<S> { pub fn current() -> Thread<S> {
Thread { Thread {
pid: S::processor().current_pid(), pid: S::processor().pid(),
mark: PhantomData, mark: PhantomData,
} }
} }
@ -62,10 +60,8 @@ impl<S: ThreadSupport> ThreadMod<S> {
pub fn sleep(dur: Duration) { pub fn sleep(dur: Duration) {
let time = dur_to_ticks(dur); let time = dur_to_ticks(dur);
info!("sleep: {:?} ticks", time); info!("sleep: {:?} ticks", time);
let mut processor = S::processor(); // TODO: register wakeup
let pid = processor.current_pid(); Self::park();
processor.sleep(pid, time);
processor.schedule();
fn dur_to_ticks(dur: Duration) -> usize { fn dur_to_ticks(dur: Duration) -> usize {
return dur.as_secs() as usize * 100 + dur.subsec_nanos() as usize / 10_000_000; return dur.as_secs() as usize * 100 + dur.subsec_nanos() as usize / 10_000_000;
@ -111,16 +107,17 @@ impl<S: ThreadSupport> ThreadMod<S> {
// unsafe { LocalKey::<usize>::get_map() }.clear(); // unsafe { LocalKey::<usize>::get_map() }.clear();
// 让Processor退出当前线程 // 让Processor退出当前线程
// 把f返回值在堆上的指针以线程返回码的形式传递出去 // 把f返回值在堆上的指针以线程返回码的形式传递出去
let mut processor = S::processor(); let pid = S::processor().pid();
let pid = processor.current_pid(); let exit_code = Box::into_raw(ret) as usize;
processor.exit(pid, Box::into_raw(ret) as usize); S::processor().manager().set_status(pid, Status::Exited(exit_code));
processor.schedule(); S::processor().yield_now();
// 再也不会被调度回来了 // 再也不会被调度回来了
unreachable!() unreachable!()
} }
// 在Processor中创建新的线程 // 在Processor中创建新的线程
let pid = S::processor().add(Context::new_kernel(kernel_thread_entry::<S, F, T>, f as usize)); let context = S::new_kernel(kernel_thread_entry::<S, F, T>, f as usize);
let pid = S::processor().manager().add(context);
// 接下来看看`JoinHandle::join()`的实现 // 接下来看看`JoinHandle::join()`的实现
// 了解是如何获取f返回值的 // 了解是如何获取f返回值的
@ -133,18 +130,15 @@ impl<S: ThreadSupport> ThreadMod<S> {
/// Cooperatively gives up a timeslice to the OS scheduler. /// Cooperatively gives up a timeslice to the OS scheduler.
pub fn yield_now() { pub fn yield_now() {
info!("yield:"); info!("yield:");
let mut processor = S::processor(); S::processor().yield_now();
processor.yield_now();
processor.schedule();
} }
/// Blocks unless or until the current thread's token is made available. /// Blocks unless or until the current thread's token is made available.
pub fn park() { pub fn park() {
info!("park:"); info!("park:");
let mut processor = S::processor(); let pid = S::processor().pid();
let pid = processor.current_pid(); S::processor().manager().set_status(pid, Status::Sleeping);
processor.sleep_(pid); S::processor().yield_now();
processor.schedule();
} }
} }
@ -157,8 +151,7 @@ pub struct Thread<S: ThreadSupport> {
impl<S: ThreadSupport> Thread<S> { impl<S: ThreadSupport> Thread<S> {
/// Atomically makes the handle's token available if it is not already. /// Atomically makes the handle's token available if it is not already.
pub fn unpark(&self) { pub fn unpark(&self) {
let mut processor = S::processor(); S::processor().manager().set_status(self.pid, Status::Ready);
processor.wakeup_(self.pid);
} }
/// Gets the thread's unique identifier. /// Gets the thread's unique identifier.
pub fn id(&self) -> usize { pub fn id(&self) -> usize {
@ -179,14 +172,8 @@ impl<S: ThreadSupport, T> JoinHandle<S, T> {
} }
/// Waits for the associated thread to finish. /// Waits for the associated thread to finish.
pub fn join(self) -> Result<T, ()> { pub fn join(self) -> Result<T, ()> {
let mut processor = S::processor(); // TODO: wait for the thread
match processor.current_wait_for(self.thread.pid) { unimplemented!()
WaitResult::Ok(_, exit_code) => unsafe {
// Find return value on the heap from the exit code.
Ok(*Box::from_raw(exit_code as *mut T))
}
WaitResult::NotExist => Err(()),
}
} }
} }

1
kernel/Cargo.lock generated

@ -285,6 +285,7 @@ name = "ucore-process"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]

@ -57,6 +57,5 @@ fn other_start() -> ! {
idt::init(); idt::init();
gdt::init(); gdt::init();
cpu::init(); cpu::init();
// unsafe{ let a = *(0xdeadbeaf as *const u8); } // Page fault ::kmain();
loop {}
} }

@ -46,8 +46,8 @@ pub fn shell() {
if let Ok(file) = root.borrow().lookup(name.as_str()) { if let Ok(file) = root.borrow().lookup(name.as_str()) {
use process::*; use process::*;
let len = file.borrow().read_at(0, &mut *buf).unwrap(); let len = file.borrow().read_at(0, &mut *buf).unwrap();
let pid = processor().add(Context::new_user(&buf[..len])); processor().manager().add(ContextImpl::new_user(&buf[..len]));
processor().current_wait_for(pid); // TODO: wait for new process
} else { } else {
println!("Program not exist"); println!("Program not exist");
} }

@ -9,6 +9,7 @@
#![feature(panic_info_message)] #![feature(panic_info_message)]
#![feature(global_asm)] #![feature(global_asm)]
#![feature(compiler_builtins_lib)] #![feature(compiler_builtins_lib)]
#![feature(raw)]
#![no_std] #![no_std]
@ -61,18 +62,18 @@ pub mod arch;
pub mod arch; pub mod arch;
pub fn kmain() -> ! { pub fn kmain() -> ! {
process::init(); if arch::cpu::id() == 0 {
unsafe { arch::interrupt::enable(); } process::init();
thread::spawn(fs::shell);
}
fs::shell(); process::processor().run();
// thread::test::local_key(); // thread::test::local_key();
// thread::test::unpack(); // thread::test::unpack();
// sync::test::philosopher_using_mutex(); // sync::test::philosopher_using_mutex();
// sync::test::philosopher_using_monitor(); // sync::test::philosopher_using_monitor();
// sync::mpsc::test::test_all(); // sync::mpsc::test::test_all();
loop {}
} }
/// Global heap allocator /// Global heap allocator

@ -2,39 +2,45 @@ use arch::interrupt::{TrapFrame, Context as ArchContext};
use memory::{MemoryArea, MemoryAttr, MemorySet}; use memory::{MemoryArea, MemoryAttr, MemorySet};
use xmas_elf::{ElfFile, header, program::{Flags, ProgramHeader, Type}}; use xmas_elf::{ElfFile, header, program::{Flags, ProgramHeader, Type}};
use core::fmt::{Debug, Error, Formatter}; use core::fmt::{Debug, Error, Formatter};
use ucore_process::processor::Context;
use alloc::boxed::Box;
pub struct Context { pub struct ContextImpl {
arch: ArchContext, arch: ArchContext,
memory_set: MemorySet, memory_set: MemorySet,
} }
impl ::ucore_process::processor::Context for Context { impl Context for ContextImpl {
unsafe fn switch(&mut self, target: &mut Self) { unsafe fn switch_to(&mut self, target: &mut Context) {
super::PROCESSOR.try().unwrap().force_unlock(); use core::raw::TraitObject;
self.arch.switch(&mut target.arch); use core::mem::transmute;
use core::mem::forget;
forget(super::processor());
}
fn new_kernel(entry: extern fn(usize) -> !, arg: usize) -> Self { // Cast &mut Context -> &mut ContextImpl
let ms = MemorySet::new(); let raw: TraitObject = transmute(target);
Context { let target = &mut *(raw.data as *mut ContextImpl);
arch: unsafe { ArchContext::new_kernel_thread(entry, arg, ms.kstack_top(), ms.token()) },
memory_set: ms, self.arch.switch(&mut target.arch);
}
} }
} }
impl Context { impl ContextImpl {
pub unsafe fn new_init() -> Self { pub unsafe fn new_init() -> Box<Context> {
Context { Box::new(ContextImpl {
arch: ArchContext::null(), arch: ArchContext::null(),
memory_set: MemorySet::new(), memory_set: MemorySet::new(),
} })
}
pub fn new_kernel(entry: extern fn(usize) -> !, arg: usize) -> Box<Context> {
let ms = MemorySet::new();
Box::new(ContextImpl {
arch: unsafe { ArchContext::new_kernel_thread(entry, arg, ms.kstack_top(), ms.token()) },
memory_set: ms,
})
} }
/// Make a new user thread from ELF data /// Make a new user thread from ELF data
pub fn new_user(data: &[u8]) -> Self { pub fn new_user(data: &[u8]) -> Box<Context> {
// Parse elf // Parse elf
let elf = ElfFile::new(data).expect("failed to read elf"); let elf = ElfFile::new(data).expect("failed to read elf");
let is32 = match elf.header.pt2 { let is32 = match elf.header.pt2 {
@ -81,17 +87,17 @@ impl Context {
}); });
} }
Context { Box::new(ContextImpl {
arch: unsafe { arch: unsafe {
ArchContext::new_user_thread( ArchContext::new_user_thread(
entry_addr, user_stack_top - 8, memory_set.kstack_top(), is32, memory_set.token()) entry_addr, user_stack_top - 8, memory_set.kstack_top(), is32, memory_set.token())
}, },
memory_set, memory_set,
} })
} }
/// Fork /// Fork
pub fn fork(&self, tf: &TrapFrame) -> Self { pub fn fork(&self, tf: &TrapFrame) -> Box<Context> {
// Clone memory set, make a new page table // Clone memory set, make a new page table
let memory_set = self.memory_set.clone(); let memory_set = self.memory_set.clone();
@ -110,14 +116,14 @@ impl Context {
}); });
} }
Context { Box::new(ContextImpl {
arch: unsafe { ArchContext::new_fork(tf, memory_set.kstack_top(), memory_set.token()) }, arch: unsafe { ArchContext::new_fork(tf, memory_set.kstack_top(), memory_set.token()) },
memory_set, memory_set,
} })
} }
} }
impl Debug for Context { impl Debug for ContextImpl {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "{:x?}", self.arch) write!(f, "{:x?}", self.arch)
} }

@ -1,36 +1,41 @@
use spin::Once; use spin::Once;
use sync::{SpinNoIrqLock, Mutex, MutexGuard, SpinNoIrq}; use sync::{SpinNoIrqLock, Mutex, MutexGuard, SpinNoIrq};
pub use self::context::Context; pub use self::context::ContextImpl;
pub use ucore_process::processor::{*, Context as _whatever}; pub use ucore_process::processor::*;
pub use ucore_process::scheduler::*; pub use ucore_process::scheduler::*;
pub use ucore_process::thread::*; pub use ucore_process::thread::*;
use alloc::boxed::Box;
use consts::MAX_CPU_NUM;
use arch::cpu;
use alloc::sync::Arc;
use alloc::vec::Vec;
mod context; mod context;
type Processor = Processor_<Context, StrideScheduler>;
pub fn init() { pub fn init() {
PROCESSOR.call_once(|| // NOTE: max_time_slice <= 5 to ensure 'priority' test pass
SpinNoIrqLock::new({ let scheduler = Box::new(RRScheduler::new(5));
let mut processor = Processor::new( let manager = Arc::new(ProcessManager::new(scheduler));
unsafe { Context::new_init() },
// NOTE: max_time_slice <= 5 to ensure 'priority' test pass extern fn idle(_arg: usize) -> ! {
StrideScheduler::new(5), loop { cpu::halt(); }
); }
extern fn idle(arg: usize) -> ! { for i in 0..MAX_CPU_NUM {
loop {} manager.add(ContextImpl::new_kernel(idle, i));
} }
processor.add(Context::new_kernel(idle, 0));
processor unsafe {
}) for cpu_id in 0..MAX_CPU_NUM {
); PROCESSORS[cpu_id].init(cpu_id, ContextImpl::new_init(), manager.clone());
}
}
info!("process init end"); info!("process init end");
} }
pub static PROCESSOR: Once<SpinNoIrqLock<Processor>> = Once::new(); static PROCESSORS: [Processor; MAX_CPU_NUM] = [Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new()];
pub fn processor() -> MutexGuard<'static, Processor, SpinNoIrq> { pub fn processor() -> &'static Processor {
PROCESSOR.try().unwrap().lock() &PROCESSORS[cpu::id()]
} }
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
@ -43,11 +48,10 @@ pub mod thread_ {
pub struct ThreadSupportImpl; pub struct ThreadSupportImpl;
impl ThreadSupport for ThreadSupportImpl { impl ThreadSupport for ThreadSupportImpl {
type Context = Context; fn processor() -> &'static Processor {
type Scheduler = StrideScheduler;
type ProcessorGuard = MutexGuard<'static, Processor, SpinNoIrq>;
fn processor() -> Self::ProcessorGuard {
processor() processor()
} }
fn new_kernel(entry: extern fn(usize) -> !, arg: usize) -> Box<Context> {
ContextImpl::new_kernel(entry, arg)
}
} }

@ -58,26 +58,13 @@ fn sys_close(fd: usize) -> i32 {
/// Fork the current process. Return the child's PID. /// Fork the current process. Return the child's PID.
fn sys_fork(tf: &TrapFrame) -> i32 { fn sys_fork(tf: &TrapFrame) -> i32 {
let mut processor = processor(); unimplemented!();
let context = processor.current_context().fork(tf);
let pid = processor.add(context);
info!("fork: {} -> {}", processor.current_pid(), pid);
pid as i32
} }
/// Wait the process exit. /// Wait the process exit.
/// Return the PID. Store exit code to `code` if it's not null. /// Return the PID. Store exit code to `code` if it's not null.
fn sys_wait(pid: usize, code: *mut i32) -> i32 { fn sys_wait(pid: usize, code: *mut i32) -> i32 {
let mut processor = processor(); unimplemented!();
match processor.current_wait_for(pid) {
WaitResult::Ok(pid, error_code) => {
if !code.is_null() {
unsafe { *code = error_code as i32 };
}
0
}
WaitResult::NotExist => -1,
}
} }
fn sys_yield() -> i32 { fn sys_yield() -> i32 {
@ -87,7 +74,7 @@ fn sys_yield() -> i32 {
/// Kill the process /// Kill the process
fn sys_kill(pid: usize) -> i32 { fn sys_kill(pid: usize) -> i32 {
processor().kill(pid); processor().manager().set_status(pid, Status::Exited(0x100));
0 0
} }
@ -97,10 +84,10 @@ fn sys_getpid() -> i32 {
} }
/// Exit the current process /// Exit the current process
fn sys_exit(error_code: usize) -> i32 { fn sys_exit(exit_code: usize) -> i32 {
let mut processor = processor(); let pid = processor().pid();
let pid = processor.current_pid(); processor().manager().set_status(pid, Status::Exited(exit_code));
processor.exit(pid, error_code); processor().yield_now();
0 0
} }
@ -111,13 +98,11 @@ fn sys_sleep(time: usize) -> i32 {
} }
fn sys_get_time() -> i32 { fn sys_get_time() -> i32 {
let processor = processor(); unimplemented!();
processor.get_time() as i32
} }
fn sys_lab6_set_priority(priority: usize) -> i32 { fn sys_lab6_set_priority(priority: usize) -> i32 {
let mut processor = processor(); unimplemented!();
processor.set_priority(priority as u8);
0 0
} }

@ -1,26 +1,19 @@
use process::*; use process::*;
use arch::interrupt::TrapFrame; use arch::interrupt::TrapFrame;
use arch::cpu;
pub fn timer() { pub fn timer() {
let mut processor = processor(); processor().tick();
processor.tick();
} }
pub fn before_return() { pub fn before_return() {
if let Some(processor) = PROCESSOR.try() {
processor.lock().schedule();
}
} }
pub fn error(tf: &TrapFrame) -> ! { pub fn error(tf: &TrapFrame) -> ! {
if let Some(processor) = PROCESSOR.try() { let pid = processor().pid();
let mut processor = processor.lock(); error!("On CPU{} Process {}:\n{:#x?}", cpu::id(), pid, tf);
let pid = processor.current_pid();
error!("Process {} error:\n{:#x?}", pid, tf); processor().manager().set_status(pid, Status::Exited(0x100));
processor.exit(pid, 0x100); // TODO: Exit code for error processor().yield_now();
processor.schedule(); unreachable!();
unreachable!();
} else {
panic!("Exception when processor not inited\n{:#x?}", tf);
}
} }
Loading…
Cancel
Save