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; }
pub type ErrorCode = usize;
unsafe impl Sync for Processor {}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Status { struct ProcessorInner {
Ready, id: usize,
Running, proc: Option<(Pid, Box<Context>)>,
Waiting(Pid), loop_context: Box<Context>,
Sleeping, manager: Arc<ProcessManager>,
Exited(ErrorCode), }
impl Processor {
pub const fn new() -> Self {
Processor { inner: UnsafeCell::new(None) }
}
pub unsafe fn init(&self, id: usize, context: Box<Context>, manager: Arc<ProcessManager>) {
unsafe {
*self.inner.get() = Some(ProcessorInner {
id,
proc: None,
loop_context: context,
manager,
});
} }
pub trait Context: Debug {
unsafe fn switch(&mut self, target: &mut Self);
fn new_kernel(entry: extern fn(usize) -> !, arg: usize) -> Self;
} }
pub struct Processor_<T: Context, S: Scheduler> { fn inner(&self) -> &mut ProcessorInner {
procs: BTreeMap<Pid, Process<T>>, unsafe { &mut *self.inner.get() }.as_mut()
current_pid: Pid, .expect("Processor is not initialized")
event_hub: EventHub<Event>,
// WARNING: if MAX_PROCESS_NUM is too large, will cause stack overflow
scheduler: S,
} }
impl<T> Process<T> { /// Begin running processes after CPU setup.
fn exit_code(&self) -> Option<ErrorCode> { ///
match self.status { /// This function never returns. It loops, doing:
Status::Exited(code) => Some(code), /// - choose a process to run
_ => None, /// - switch to start running that process
/// - eventually that process transfers control
/// via switch back to the scheduler.
pub fn run(&self) -> ! {
let inner = self.inner();
loop {
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);
} }
} }
// TODO: 除schedule()外的其它函数应该只设置进程状态不应调用schedule /// Called by process running on this Processor.
impl<T: Context, S: Scheduler> Processor_<T, S> { /// Yield and reschedule.
pub fn new(init_context: T, scheduler: S) -> Self { pub fn yield_now(&self) {
let init_proc = Process { let inner = self.inner();
pid: 0, unsafe {
parent: 0, inner.proc.as_mut().unwrap().1.switch_to(&mut *inner.loop_context);
status: Status::Running,
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) { pub fn pid(&self) -> Pid {
self.scheduler.set_priority(self.current_pid, priority); self.inner().proc.as_ref().unwrap().0
} }
pub fn yield_now(&mut self) { pub fn manager(&self) -> &ProcessManager {
let pid = self.current_pid; &*self.inner().manager
self.set_status(pid, Status::Ready);
} }
fn alloc_pid(&self) -> Pid { pub fn tick(&self) {
let mut next: Pid = 0; let need_reschedule = self.manager().tick(self.pid());
for &i in self.procs.keys() { if need_reschedule {
if i != next {
return next;
} else {
next = i + 1;
}
}
return next;
}
fn set_status(&mut self, pid: Pid, status: Status) {
let status0 = self.get(pid).status.clone();
match (&status0, &status) {
(&Status::Ready, &Status::Ready) => return,
(&Status::Ready, _) => self.scheduler.remove(pid),
(_, &Status::Ready) => self.scheduler.insert(pid),
_ => {}
}
trace!("process {} {:?} -> {:?}", pid, status0, status);
self.get_mut(pid).status = status;
}
/// Called by timer.
/// Handle events.
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.yield_now();
self.scheduler.move_to_head(pid);
},
} }
} }
} }
pub fn get_time(&self) -> usize { struct Process {
self.event_hub.get_time() id: Pid,
} status: Status,
status_after_stop: Status,
pub fn add(&mut self, context: T) -> Pid { context: Option<Box<Context>>,
let pid = self.alloc_pid();
let process = Process {
pid,
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`. type Pid = usize;
/// The current status must be set before, and not be `Running`. type ExitCode = usize;
/// The target status must be `Ready`. const MAX_PROC_NUM: usize = 32;
fn switch_to(&mut self, pid: Pid) {
// for debug print
let pid0 = self.current_pid;
if pid == self.current_pid { #[derive(Debug, Clone, Eq, PartialEq)]
if self.get(self.current_pid).status != Status::Running { pub enum Status {
self.set_status(pid, Status::Running); Ready,
} Running(usize),
return; Waiting(Pid),
Sleeping,
Exited(ExitCode),
} }
self.current_pid = pid;
let (from, to) = self.procs.get_mut2(pid0, pid);
assert_ne!(from.status, Status::Running);
assert_eq!(to.status, Status::Ready);
to.status = Status::Running;
self.scheduler.remove(pid);
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);
} }
pub fn wakeup_(&mut self, pid: Pid) { panic!("Process number exceeded");
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
fn try_wait(&mut self, pid: Pid) -> Option<Pid> {
match pid {
0 => self.procs.values()
.find(|&p| p.parent == self.current_pid && p.exit_code().is_some())
.map(|p| p.pid),
_ => self.get(pid).exit_code().map(|_| pid),
}
}
fn find_waiter(&self, pid: Pid) -> Option<Pid> {
self.procs.values().find(|&p| {
p.status == Status::Waiting(pid) ||
(p.status == Status::Waiting(0) && self.get(pid).parent == p.pid)
}).map(|ref p| p.pid)
}
} }
#[derive(Debug)] /// Make process `pid` time slice -= 1.
pub enum WaitResult { /// Return true if time slice == 0.
/// The target process is exited with `ErrorCode`. /// Called by timer interrupt handler.
Ok(Pid, ErrorCode), pub fn tick(&self, pid: Pid) -> bool {
/// The target process is not exist. self.scheduler.lock().tick(pid)
NotExist, }
/// 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);
}
}
/// Switch the status of a process.
/// Insert/Remove it to/from scheduler if necessary.
pub fn set_status(&self, pid: Pid, status: Status) {
let mut scheduler = self.scheduler.lock();
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,
(Status::Ready, _) => scheduler.remove(pid),
(Status::Running(_), _) => {},
(_, Status::Ready) => scheduler.insert(pid),
_ => {}
} }
trace!("process {} {:?} -> {:?}", pid, proc.status, status);
#[derive(Debug)] match proc.status {
enum Event { Status::Running(_) => proc.status_after_stop = status,
Schedule, _ => proc.status = status,
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() -> ! {
if arch::cpu::id() == 0 {
process::init(); process::init();
unsafe { arch::interrupt::enable(); } 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(||
SpinNoIrqLock::new({
let mut processor = Processor::new(
unsafe { Context::new_init() },
// NOTE: max_time_slice <= 5 to ensure 'priority' test pass // NOTE: max_time_slice <= 5 to ensure 'priority' test pass
StrideScheduler::new(5), let scheduler = Box::new(RRScheduler::new(5));
); let manager = Arc::new(ProcessManager::new(scheduler));
extern fn idle(arg: usize) -> ! {
loop {} extern fn idle(_arg: usize) -> ! {
} loop { cpu::halt(); }
processor.add(Context::new_kernel(idle, 0)); }
processor for i in 0..MAX_CPU_NUM {
}) manager.add(ContextImpl::new_kernel(idle, i));
); }
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