diff --git a/crate/process/src/event_hub.rs b/crate/process/src/event_hub.rs deleted file mode 100644 index 62d2cec..0000000 --- a/crate/process/src/event_hub.rs +++ /dev/null @@ -1,93 +0,0 @@ -use alloc::collections::VecDeque; -use core::cmp::{Ordering, PartialOrd}; - -type Time = usize; - -struct Timer { - time: Time, - data: T, -} - -impl PartialEq for Timer { - fn eq(&self, other: &Self) -> bool { - self.time.eq(&other.time) - } -} - -impl Eq for Timer {} - -impl PartialOrd for Timer { - fn partial_cmp(&self, other: &Self) -> Option { - other.time.partial_cmp(&self.time) - } -} - -impl Ord for Timer { - fn cmp(&self, other: &Self) -> Ordering { - self.partial_cmp(&other).unwrap() - } -} - -pub struct EventHub { - tick: Time, - timers: VecDeque>, -} - -impl EventHub { - pub fn new() -> Self { - EventHub { - tick: 0, - timers: VecDeque::new(), - } - } - pub fn tick(&mut self) { - self.tick += 1; - } - pub fn pop(&mut self) -> Option { - match self.timers.front() { - None => return None, - Some(timer) if timer.time != self.tick => return None, - _ => {} - }; - self.timers.pop_front().map(|t| t.data) - } - pub fn push(&mut self, time_after: Time, data: T) { - //debug!("{:?} {:?}", self.tick, time_after); - let time = self.tick + time_after; - let timer = Timer { time, data }; - let mut it = self.timers.iter(); - let mut i : usize = 0; - loop { - let now = it.next(); - if now == None { - break - }; - if now.unwrap() < &timer { - break - }; - i += 1; - } - self.timers.insert(i, timer); - } - #[allow(dead_code)] - pub fn get_time(&self) -> Time { - self.tick - } - pub fn remove(&mut self, data: T) { - let mut it = self.timers.iter(); - let mut i : usize = 0; - loop { - let now = it.next(); - if now == None { - break - }; - if now.map(|t| &t.data).unwrap() == &data { - break - }; - i += 1; - } - if i < self.timers.len() { - self.timers.remove(i); - } - } -} \ No newline at end of file diff --git a/crate/process/src/process_manager.rs b/crate/process/src/process_manager.rs deleted file mode 100644 index 2ca17b5..0000000 --- a/crate/process/src/process_manager.rs +++ /dev/null @@ -1,222 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec::Vec; -use spin::Mutex; -use log::*; -use crate::scheduler::Scheduler; -use crate::event_hub::EventHub; - -struct Process { - #[allow(dead_code)] - id: Pid, - status: Status, - status_after_stop: Status, - context: Option>, - parent: Pid, - children: Vec, -} - -pub type Pid = usize; -type ExitCode = usize; - -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum Status { - Ready, - Running(usize), - Sleeping, - Waiting(Pid), - /// aka ZOMBIE. Its context was dropped. - Exited(ExitCode), -} - -#[derive(Eq, PartialEq)] -enum Event { - Wakeup(Pid), -} - -pub trait Context { - unsafe fn switch_to(&mut self, target: &mut Context); -} - -pub struct ProcessManager { - procs: Vec>>, - scheduler: Mutex>, - event_hub: Mutex>, -} - -impl ProcessManager { - pub fn new(scheduler: Box, max_proc_num: usize) -> Self { - ProcessManager { - procs: new_vec_default(max_proc_num), - scheduler: Mutex::new(scheduler), - event_hub: Mutex::new(EventHub::new()), - } - } - - fn alloc_pid(&self) -> Pid { - for (i, proc) in self.procs.iter().enumerate() { - if proc.lock().is_none() { - return i; - } - } - panic!("Process number exceeded"); - } - - /// Add a new process - pub fn add(&self, context: Box, parent: Pid) -> Pid { - let pid = self.alloc_pid(); - *(&self.procs[pid]).lock() = Some(Process { - id: pid, - status: Status::Ready, - status_after_stop: Status::Ready, - context: Some(context), - parent, - children: Vec::new(), - }); - self.scheduler.lock().insert(pid); - self.procs[parent].lock().as_mut().expect("invalid parent proc") - .children.push(pid); - pid - } - - /// Make process `pid` time slice -= 1. - /// Return true if time slice == 0. - /// Called by timer interrupt handler. - pub fn tick(&self, pid: Pid) -> bool { - let mut event_hub = self.event_hub.lock(); - event_hub.tick(); - while let Some(event) = event_hub.pop() { - match event { - Event::Wakeup(pid) => self.set_status(pid, Status::Ready), - } - } - self.scheduler.lock().tick(pid) - } - - /// Set the priority of process `pid` - pub fn set_priority(&self, pid: Pid, priority: u8) { - self.scheduler.lock().set_priority(pid, priority); - } - - /// 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) { - 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().expect("process not exist"); - proc.status = Status::Running(cpu_id); - (pid, proc.context.take().expect("context not exist")) - } - - /// Called by Processor to finish running a process - /// and give its context back. - pub fn stop(&self, pid: Pid, context: Box) { - let mut proc_lock = self.procs[pid].lock(); - let mut proc = proc_lock.as_mut().expect("process not exist"); - proc.status = proc.status_after_stop.clone(); - proc.status_after_stop = Status::Ready; - proc.context = Some(context); - match proc.status { - Status::Ready => self.scheduler.lock().insert(pid), - Status::Exited(_) => self.exit_handler(pid, proc), - _ => {} - } - } - - /// Switch the status of a process. - /// Insert/Remove it to/from scheduler if necessary. - fn set_status(&self, pid: Pid, status: Status) { - let mut proc_lock = self.procs[pid].lock(); - let mut proc = proc_lock.as_mut().expect("process not exist"); - trace!("process {} {:?} -> {:?}", pid, proc.status, status); - match (&proc.status, &status) { - (Status::Ready, Status::Ready) => return, - (Status::Ready, _) => self.scheduler.lock().remove(pid), - (Status::Exited(_), _) => panic!("can not set status for a exited process"), - (Status::Sleeping, Status::Exited(_)) => self.event_hub.lock().remove(Event::Wakeup(pid)), - (_, Status::Ready) => self.scheduler.lock().insert(pid), - _ => {} - } - match proc.status { - Status::Running(_) => proc.status_after_stop = status, - _ => proc.status = status, - } - match proc.status { - Status::Exited(_) => self.exit_handler(pid, proc), - _ => {} - } - } - - pub fn get_status(&self, pid: Pid) -> Option { - self.procs[pid].lock().as_ref().map(|p| p.status.clone()) - } - - /// Remove an exited proc `pid`. - /// Its all children will be set parent to 0. - pub fn remove(&self, pid: Pid) { - let mut proc_lock = self.procs[pid].lock(); - let proc = proc_lock.as_ref().expect("process not exist"); - match proc.status { - Status::Exited(_) => {} - _ => panic!("can not remove non-exited process"), - } - // orphan procs - for child in proc.children.iter() { - (&self.procs[*child]).lock().as_mut().expect("process not exist").parent = 0; - } - // remove self from parent's children list - self.procs[proc.parent].lock().as_mut().expect("process not exist") - .children.retain(|&i| i != pid); - // release the pid - *proc_lock = None; - } - - /// Sleep `pid` for `time` ticks. - /// `time` == 0 means sleep forever - pub fn sleep(&self, pid: Pid, time: usize) { - self.set_status(pid, Status::Sleeping); - if time != 0 { - self.event_hub.lock().push(time, Event::Wakeup(pid)); - } - } - - pub fn wakeup(&self, pid: Pid) { - self.set_status(pid, Status::Ready); - } - - pub fn wait(&self, pid: Pid, target: Pid) { - self.set_status(pid, Status::Waiting(target)); - } - pub fn wait_child(&self, pid: Pid) { - self.set_status(pid, Status::Waiting(0)); - } - - pub fn get_children(&self, pid: Pid) -> Vec { - self.procs[pid].lock().as_ref().expect("process not exist").children.clone() - } - - pub fn exit(&self, pid: Pid, code: ExitCode) { - // NOTE: if `pid` is running, status change will be deferred. - self.set_status(pid, Status::Exited(code)); - } - /// Called when a process exit - fn exit_handler(&self, pid: Pid, proc: &mut Process) { - // wakeup parent if waiting - let parent = proc.parent; - match self.get_status(parent).expect("process not exist") { - Status::Waiting(target) if target == pid || target == 0 => self.wakeup(parent), - _ => {} - } - // drop its context - proc.context = None; - } -} - -fn new_vec_default(size: usize) -> Vec { - let mut vec = Vec::new(); - vec.resize_default(size); - vec -} diff --git a/crate/process/Cargo.toml b/crate/thread/Cargo.toml similarity index 57% rename from crate/process/Cargo.toml rename to crate/thread/Cargo.toml index 29d4995..a228acf 100644 --- a/crate/process/Cargo.toml +++ b/crate/thread/Cargo.toml @@ -1,7 +1,8 @@ [package] -name = "rcore-process" +name = "rcore-thread" version = "0.1.0" authors = ["WangRunji "] +description = "Bare-metal thread scheduler and executor" edition = "2018" [dependencies] diff --git a/crate/process/build.rs b/crate/thread/build.rs similarity index 100% rename from crate/process/build.rs rename to crate/thread/build.rs diff --git a/crate/thread/example/Cargo.toml b/crate/thread/example/Cargo.toml new file mode 100644 index 0000000..0ecc867 --- /dev/null +++ b/crate/thread/example/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "example" +version = "0.1.0" +authors = ["WangRunji "] +edition = "2018" + +[dependencies] +log = "0.4" +linked_list_allocator = "0.6" +blog_os = { git = "https://github.com/phil-opp/blog_os.git" } +rcore-thread = { path = ".." } + +[package.metadata.bootimage] +default-target = "x86_64-blog_os.json" +run-command = ["qemu-system-x86_64", + "-drive", "format=raw,file={}", + "-serial", "mon:stdio", + "-device", "isa-debug-exit,iobase=0xf4,iosize=0x04" +] \ No newline at end of file diff --git a/crate/thread/example/README.md b/crate/thread/example/README.md new file mode 100644 index 0000000..2b14623 --- /dev/null +++ b/crate/thread/example/README.md @@ -0,0 +1,5 @@ +# Example of `rcore-thread` crate + +```bash +bootimage run --release +``` \ No newline at end of file diff --git a/crate/thread/example/src/main.rs b/crate/thread/example/src/main.rs new file mode 100644 index 0000000..2c7ada9 --- /dev/null +++ b/crate/thread/example/src/main.rs @@ -0,0 +1,199 @@ +#![no_std] +#![no_main] +#![feature(asm)] +#![feature(alloc)] +#![feature(naked_functions)] +#![feature(panic_info_message)] +#![feature(lang_items)] + +extern crate alloc; + +use core::alloc::Layout; +use core::panic::PanicInfo; +use alloc::{boxed::Box, sync::Arc}; + +use blog_os::{exit_qemu, gdt, interrupts::init_idt, serial_println}; +use linked_list_allocator::LockedHeap; +use rcore_thread::{*, std_thread as thread}; + +const STACK_SIZE: usize = 0x2000; +const HEAP_SIZE: usize = 0x100000; +const MAX_CPU_NUM: usize = 1; +const MAX_PROC_NUM: usize = 32; + + +/// The entry of the kernel +#[no_mangle] +pub extern "C" fn _start() -> ! { + // init x86 + gdt::init(); + init_idt(); + // init log + init_log(); + // init heap + unsafe { HEAP_ALLOCATOR.lock().init(HEAP.as_ptr() as usize, HEAP_SIZE); } + // init processor + let scheduler = Box::new(scheduler::RRScheduler::new(5)); + let thread_pool = Arc::new(ThreadPool::new(scheduler, MAX_PROC_NUM)); + unsafe { processor().init(0, Thread::init(), thread_pool); } + // init threads + thread::spawn(|| { + let tid = processor().tid(); + serial_println!("I'm thread {}! yield...", tid); + thread::yield_now(); + serial_println!("I'm thread {}! exit...", tid); + }); + thread::spawn(|| { + let tid = processor().tid(); + serial_println!("I'm thread {}! yield...", tid); + thread::yield_now(); + serial_println!("I'm thread {}! exit...", tid); + }); + // run threads + processor().run(); +} + +fn init_log() { + use log::*; + struct SimpleLogger; + impl Log for SimpleLogger { + fn enabled(&self, _metadata: &Metadata) -> bool { + true + } + fn log(&self, record: &Record) { + serial_println!("[{:>5}] {}", record.level(), record.args()); + } + fn flush(&self) {} + } + static LOGGER: SimpleLogger = SimpleLogger; + set_logger(&LOGGER).unwrap(); + set_max_level(LevelFilter::Trace); +} + +/// The context of a thread. +/// +/// When a thread yield, its context will be stored at its stack. +#[derive(Debug, Default)] +#[repr(C)] +struct ContextData { + rdi: usize, // arg0 + r15: usize, + r14: usize, + r13: usize, + r12: usize, + rbp: usize, + rbx: usize, + rip: usize, +} + +impl ContextData { + fn new(entry: extern fn(usize) -> !, arg0: usize) -> Self { + ContextData { + rip: entry as usize, + rdi: arg0, + ..ContextData::default() + } + } +} + +#[repr(C)] +struct Thread { + rsp: usize, + stack: [u8; STACK_SIZE], +} + +impl Thread { + unsafe fn init() -> Box { + Box::new(core::mem::uninitialized()) + } + fn new(entry: extern fn(usize) -> !, arg0: usize) -> Box { + let mut thread = unsafe { Thread::init() }; + let rsp = thread.stack.as_ptr() as usize + STACK_SIZE - core::mem::size_of::(); + // push a Context at stack top + let init_context = ContextData::new(entry, arg0); + unsafe { (rsp as *mut ContextData).write(init_context); } + thread.rsp = rsp; + thread + } +} + +/// Implement `switch_to` for a thread +impl Context for Thread { + /// Switch to another thread. + unsafe fn switch_to(&mut self, target: &mut Context) { + let (to, _): (*mut Thread, usize) = core::mem::transmute(target); + inner(self, to); + + #[naked] + #[inline(never)] + unsafe extern "C" fn inner(_from: *mut Thread, _to: *mut Thread) { + asm!( + " + // push rip (by caller) + + // Save self callee-save registers + push rbx + push rbp + push r12 + push r13 + push r14 + push r15 + push rdi + + // Switch stacks + mov [rdi], rsp // *rdi = from_rsp + mov rsp, [rsi] // *rsi = to_rsp + + // Restore target callee-save registers + pop rdi + pop r15 + pop r14 + pop r13 + pop r12 + pop rbp + pop rbx + + // pop rip + ret" + : : : : "intel" "volatile" ) + } + } +} + +/// Define global `Processor` for each core. +static PROCESSORS: [Processor; MAX_CPU_NUM] = [Processor::new()]; + +/// Now we only have one core. +fn cpu_id() -> usize { 0 } + +/// Implement dependency for `rcore_thread::std_thread` +#[no_mangle] +pub fn processor() -> &'static Processor { + &PROCESSORS[cpu_id()] +} + +/// Implement dependency for `rcore_thread::std_thread` +#[no_mangle] +pub fn new_kernel_context(entry: extern fn(usize) -> !, arg0: usize) -> Box { + Thread::new(entry, arg0) +} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + let location = info.location().unwrap(); + let message = info.message().unwrap(); + serial_println!("\nPANIC @ {}\n\t{}", location, message); + + unsafe { exit_qemu(); } + loop {} +} + +#[global_allocator] +static HEAP_ALLOCATOR: LockedHeap = LockedHeap::empty(); + +static mut HEAP: [u8; HEAP_SIZE] = [0; HEAP_SIZE]; + +#[lang = "oom"] +fn oom(_: Layout) -> ! { + panic!("out of memory"); +} \ No newline at end of file diff --git a/crate/thread/example/x86_64-blog_os.json b/crate/thread/example/x86_64-blog_os.json new file mode 100644 index 0000000..7d2110d --- /dev/null +++ b/crate/thread/example/x86_64-blog_os.json @@ -0,0 +1,15 @@ +{ + "llvm-target": "x86_64-unknown-none", + "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", + "arch": "x86_64", + "target-endian": "little", + "target-pointer-width": "64", + "target-c-int-width": "32", + "os": "none", + "executables": true, + "linker-flavor": "ld.lld", + "linker": "rust-lld", + "panic-strategy": "abort", + "disable-redzone": true, + "features": "-mmx,-sse,+soft-float" +} diff --git a/crate/process/src/interrupt.rs b/crate/thread/src/interrupt.rs similarity index 96% rename from crate/process/src/interrupt.rs rename to crate/thread/src/interrupt.rs index 6e238be..e23eb12 100644 --- a/crate/process/src/interrupt.rs +++ b/crate/thread/src/interrupt.rs @@ -1,3 +1,5 @@ +//! Enable and disable interrupt for each architecture. + #[inline(always)] #[cfg(target_arch = "x86_64")] pub unsafe fn disable_and_store() -> usize { diff --git a/crate/process/src/lib.rs b/crate/thread/src/lib.rs similarity index 77% rename from crate/process/src/lib.rs rename to crate/thread/src/lib.rs index 764cdb6..af97063 100644 --- a/crate/process/src/lib.rs +++ b/crate/thread/src/lib.rs @@ -9,12 +9,12 @@ extern crate alloc; -mod process_manager; +mod thread_pool; mod processor; pub mod scheduler; -pub mod thread; -mod event_hub; +pub mod std_thread; +mod timer; mod interrupt; -pub use crate::process_manager::*; +pub use crate::thread_pool::*; pub use crate::processor::Processor; diff --git a/crate/process/src/processor.rs b/crate/thread/src/processor.rs similarity index 89% rename from crate/process/src/processor.rs rename to crate/thread/src/processor.rs index e316324..27a3ca2 100644 --- a/crate/process/src/processor.rs +++ b/crate/thread/src/processor.rs @@ -2,10 +2,10 @@ use alloc::boxed::Box; use alloc::sync::Arc; use log::*; use core::cell::UnsafeCell; -use crate::process_manager::*; +use crate::thread_pool::*; use crate::interrupt; -/// Process executor +/// Thread executor /// /// Per-CPU struct. Defined at global. /// Only accessed by associated CPU with interrupt disabled. @@ -18,9 +18,9 @@ unsafe impl Sync for Processor {} struct ProcessorInner { id: usize, - proc: Option<(Pid, Box)>, + proc: Option<(Tid, Box)>, loop_context: Box, - manager: Arc, + manager: Arc, } impl Processor { @@ -28,7 +28,7 @@ impl Processor { Processor { inner: UnsafeCell::new(None) } } - pub unsafe fn init(&self, id: usize, context: Box, manager: Arc) { + pub unsafe fn init(&self, id: usize, context: Box, manager: Arc) { *self.inner.get() = Some(ProcessorInner { id, proc: None, @@ -76,7 +76,7 @@ impl Processor { } } - pub fn pid(&self) -> Pid { + pub fn tid(&self) -> Tid { self.inner().proc.as_ref().unwrap().0 } @@ -84,13 +84,13 @@ impl Processor { &*self.inner().proc.as_ref().unwrap().1 } - pub fn manager(&self) -> &ProcessManager { + pub fn manager(&self) -> &ThreadPool { &*self.inner().manager } pub fn tick(&self) { let flags = unsafe { interrupt::disable_and_store() }; - let need_reschedule = self.manager().tick(self.pid()); + let need_reschedule = self.manager().tick(self.tid()); unsafe { interrupt::restore(flags); } if need_reschedule { diff --git a/crate/process/src/scheduler.rs b/crate/thread/src/scheduler.rs similarity index 100% rename from crate/process/src/scheduler.rs rename to crate/thread/src/scheduler.rs diff --git a/crate/process/src/thread.rs b/crate/thread/src/std_thread.rs similarity index 98% rename from crate/process/src/thread.rs rename to crate/thread/src/std_thread.rs index 7657492..e59a559 100644 --- a/crate/process/src/thread.rs +++ b/crate/thread/src/std_thread.rs @@ -1,4 +1,4 @@ -//! Thread std-like interface +//! `std::thread`-like interface //! //! Based on Processor. Used in kernel. //! @@ -11,7 +11,7 @@ use core::marker::PhantomData; use core::time::Duration; use log::*; use crate::processor::*; -use crate::process_manager::*; +use crate::thread_pool::*; #[linkage = "weak"] #[no_mangle] @@ -30,7 +30,7 @@ fn new_kernel_context(_entry: extern fn(usize) -> !, _arg: usize) -> Box Thread { - Thread { pid: processor().pid() } + Thread { pid: processor().tid() } } /// Puts the current thread to sleep for the specified amount of time. @@ -160,7 +160,7 @@ impl JoinHandle { } } /// Force construct a JoinHandle struct - pub unsafe fn _of(pid: Pid) -> JoinHandle { + pub unsafe fn _of(pid: Tid) -> JoinHandle { JoinHandle { thread: Thread { pid }, mark: PhantomData, diff --git a/crate/thread/src/thread_pool.rs b/crate/thread/src/thread_pool.rs new file mode 100644 index 0000000..8d16de6 --- /dev/null +++ b/crate/thread/src/thread_pool.rs @@ -0,0 +1,219 @@ +use alloc::boxed::Box; +use alloc::vec::Vec; +use spin::Mutex; +use log::*; +use crate::scheduler::Scheduler; +use crate::timer::Timer; + +struct Thread { + status: Status, + status_after_stop: Status, + context: Option>, + parent: Tid, + children: Vec, +} + +pub type Tid = usize; +type ExitCode = usize; + +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum Status { + Ready, + Running(usize), + Sleeping, + Waiting(Tid), + /// aka ZOMBIE. Its context was dropped. + Exited(ExitCode), +} + +#[derive(Eq, PartialEq)] +enum Event { + Wakeup(Tid), +} + +pub trait Context { + unsafe fn switch_to(&mut self, target: &mut Context); +} + +pub struct ThreadPool { + threads: Vec>>, + scheduler: Mutex>, + timer: Mutex>, +} + +impl ThreadPool { + pub fn new(scheduler: Box, max_proc_num: usize) -> Self { + ThreadPool { + threads: new_vec_default(max_proc_num), + scheduler: Mutex::new(scheduler), + timer: Mutex::new(Timer::new()), + } + } + + fn alloc_tid(&self) -> Tid { + for (i, proc) in self.threads.iter().enumerate() { + if proc.lock().is_none() { + return i; + } + } + panic!("Process number exceeded"); + } + + /// Add a new process + pub fn add(&self, context: Box, parent: Tid) -> Tid { + let tid = self.alloc_tid(); + *(&self.threads[tid]).lock() = Some(Thread { + status: Status::Ready, + status_after_stop: Status::Ready, + context: Some(context), + parent, + children: Vec::new(), + }); + self.scheduler.lock().insert(tid); + self.threads[parent].lock().as_mut().expect("invalid parent proc") + .children.push(tid); + tid + } + + /// Make process `tid` time slice -= 1. + /// Return true if time slice == 0. + /// Called by timer interrupt handler. + pub fn tick(&self, tid: Tid) -> bool { + let mut timer = self.timer.lock(); + timer.tick(); + while let Some(event) = timer.pop() { + match event { + Event::Wakeup(tid) => self.set_status(tid, Status::Ready), + } + } + self.scheduler.lock().tick(tid) + } + + /// Set the priority of process `tid` + pub fn set_priority(&self, tid: Tid, priority: u8) { + self.scheduler.lock().set_priority(tid, priority); + } + + /// 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) -> (Tid, Box) { + let mut scheduler = self.scheduler.lock(); + let tid = scheduler.select() + .expect("failed to select a runnable process"); + scheduler.remove(tid); + let mut proc_lock = self.threads[tid].lock(); + let mut proc = proc_lock.as_mut().expect("process not exist"); + proc.status = Status::Running(cpu_id); + (tid, proc.context.take().expect("context not exist")) + } + + /// Called by Processor to finish running a process + /// and give its context back. + pub fn stop(&self, tid: Tid, context: Box) { + let mut proc_lock = self.threads[tid].lock(); + let mut proc = proc_lock.as_mut().expect("process not exist"); + proc.status = proc.status_after_stop.clone(); + proc.status_after_stop = Status::Ready; + proc.context = Some(context); + match proc.status { + Status::Ready => self.scheduler.lock().insert(tid), + Status::Exited(_) => self.exit_handler(tid, proc), + _ => {} + } + } + + /// Switch the status of a process. + /// Insert/Remove it to/from scheduler if necessary. + fn set_status(&self, tid: Tid, status: Status) { + let mut proc_lock = self.threads[tid].lock(); + let mut proc = proc_lock.as_mut().expect("process not exist"); + trace!("process {} {:?} -> {:?}", tid, proc.status, status); + match (&proc.status, &status) { + (Status::Ready, Status::Ready) => return, + (Status::Ready, _) => self.scheduler.lock().remove(tid), + (Status::Exited(_), _) => panic!("can not set status for a exited process"), + (Status::Sleeping, Status::Exited(_)) => self.timer.lock().stop(Event::Wakeup(tid)), + (_, Status::Ready) => self.scheduler.lock().insert(tid), + _ => {} + } + match proc.status { + Status::Running(_) => proc.status_after_stop = status, + _ => proc.status = status, + } + match proc.status { + Status::Exited(_) => self.exit_handler(tid, proc), + _ => {} + } + } + + pub fn get_status(&self, tid: Tid) -> Option { + self.threads[tid].lock().as_ref().map(|p| p.status.clone()) + } + + /// Remove an exited proc `tid`. + /// Its all children will be set parent to 0. + pub fn remove(&self, tid: Tid) { + let mut proc_lock = self.threads[tid].lock(); + let proc = proc_lock.as_ref().expect("process not exist"); + match proc.status { + Status::Exited(_) => {} + _ => panic!("can not remove non-exited process"), + } + // orphan procs + for child in proc.children.iter() { + (&self.threads[*child]).lock().as_mut().expect("process not exist").parent = 0; + } + // remove self from parent's children list + self.threads[proc.parent].lock().as_mut().expect("process not exist") + .children.retain(|&i| i != tid); + // release the tid + *proc_lock = None; + } + + /// Sleep `tid` for `time` ticks. + /// `time` == 0 means sleep forever + pub fn sleep(&self, tid: Tid, time: usize) { + self.set_status(tid, Status::Sleeping); + if time != 0 { + self.timer.lock().start(time, Event::Wakeup(tid)); + } + } + + pub fn wakeup(&self, tid: Tid) { + self.set_status(tid, Status::Ready); + } + + pub fn wait(&self, tid: Tid, target: Tid) { + self.set_status(tid, Status::Waiting(target)); + } + pub fn wait_child(&self, tid: Tid) { + self.set_status(tid, Status::Waiting(0)); + } + + pub fn get_children(&self, tid: Tid) -> Vec { + self.threads[tid].lock().as_ref().expect("process not exist").children.clone() + } + + pub fn exit(&self, tid: Tid, code: ExitCode) { + // NOTE: if `tid` is running, status change will be deferred. + self.set_status(tid, Status::Exited(code)); + } + /// Called when a process exit + fn exit_handler(&self, tid: Tid, proc: &mut Thread) { + // wakeup parent if waiting + let parent = proc.parent; + match self.get_status(parent).expect("process not exist") { + Status::Waiting(target) if target == tid || target == 0 => self.wakeup(parent), + _ => {} + } + // drop its context + proc.context = None; + } +} + +fn new_vec_default(size: usize) -> Vec { + let mut vec = Vec::new(); + vec.resize_default(size); + vec +} diff --git a/crate/thread/src/timer.rs b/crate/thread/src/timer.rs new file mode 100644 index 0000000..9854f14 --- /dev/null +++ b/crate/thread/src/timer.rs @@ -0,0 +1,65 @@ +//! A simple timer + +use alloc::collections::VecDeque; + +type Time = usize; + +struct Event { + time: Time, + data: T, +} + +/// A simple timer using ordered dequeue +pub struct Timer { + tick: Time, + timers: VecDeque>, +} + +impl Timer { + /// Create a new timer. + pub fn new() -> Self { + Timer { + tick: 0, + timers: VecDeque::new(), + } + } + /// Called on each tick. + pub fn tick(&mut self) { + self.tick += 1; + } + /// Pop an expired timer after `tick`. + /// + /// This must be called after calling `tick`, + /// and should be called multiple times until return `None`. + pub fn pop(&mut self) -> Option { + match self.timers.front() { + None => return None, + Some(timer) if timer.time != self.tick => return None, + _ => {} + }; + self.timers.pop_front().map(|t| t.data) + } + /// Start a timer with given time interval + pub fn start(&mut self, time_after: Time, data: T) { + //debug!("{:?} {:?}", self.tick, time_after); + let time = self.tick + time_after; + let event = Event { time, data }; + let mut it = self.timers.iter(); + let mut i : usize = 0; + loop { + match it.next() { + None => break, + Some(e) if e.time >= time => break, + _ => {} + } + i += 1; + } + self.timers.insert(i, event); + } + /// Stop a timer + pub fn stop(&mut self, data: T) { + if let Some(i) = self.timers.iter().position(|t| t.data == data) { + self.timers.remove(i); + } + } +} \ No newline at end of file diff --git a/docs/2_OSLab/g2/context.md b/docs/2_OSLab/g2/context.md index 1372c65..6805901 100644 --- a/docs/2_OSLab/g2/context.md +++ b/docs/2_OSLab/g2/context.md @@ -1,6 +1,6 @@ # 上下文切换 -平台无关的代码位于 [kernel/src/process/context.rs](../../../kernel/src/process/context.rs) 中,而平台相关(aarch64)的代码位于 [kernel/src/arch/aarch64/interrupt/context.rs](../../../kernel/src/arch/aarch64/interrupt/context.rs) 中。 +平台无关的代码位于 [kernel/src/process/context.rs](../../../kernel/src/process/structs.rs) 中,而平台相关(aarch64)的代码位于 [kernel/src/arch/aarch64/interrupt/context.rs](../../../kernel/src/arch/aarch64/interrupt/context.rs) 中。 ## 相关数据结构 @@ -56,7 +56,7 @@ } ``` - 每个进程控制块 `Process` ([kernel/src/process/context.rs](../../../kernel/src/process/context.rs#L13)) 都会维护一个平台相关的 `Context` 对象,在 AArch64 中包含下列信息: + 每个进程控制块 `Process` ([kernel/src/process/context.rs](../../../kernel/src/process/structs.rs#L13)) 都会维护一个平台相关的 `Context` 对象,在 AArch64 中包含下列信息: 1. `stack_top`:内核栈顶地址 2. `ttbr`:页表基址 @@ -64,7 +64,7 @@ ## 切换流程 -在 [kernel/src/process/context.rs](../../../kernel/src/process/context.rs#L22) 里,`switch_to()` 是平台无关的切换函数,最终会调用 [kernel/src/arch/aarch64/interrupt/context.rs](../../../kernel/src/arch/aarch64/interrupt/context.rs#L129) 里平台相关的切换函数 `Context::switch()`: +在 [kernel/src/process/context.rs](../../../kernel/src/process/structs.rs#L22) 里,`switch_to()` 是平台无关的切换函数,最终会调用 [kernel/src/arch/aarch64/interrupt/context.rs](../../../kernel/src/arch/aarch64/interrupt/context.rs#L129) 里平台相关的切换函数 `Context::switch()`: ```rust pub unsafe fn switch(&mut self, target: &mut Self) { @@ -190,7 +190,7 @@ ret 2. 创建新的**用户线程**:解析 ELF 文件。 3. 从一个线程 **fork** 出一个新线程:通过 `fork` 系统调用。 -三种线程的平台无关创建流程实现在 [kernel/src/process/context.rs](../../../kernel/src/process/context.rs#L40) 里,最终会分别调用 [kernel/src/arch/aarch64/interrupt/context.rs](../../../kernel/src/arch/aarch64/interrupt/context.rs#L146) 里的 `new_kernel_thread()`、`new_user_thread()` 和 `new_fork()` 这三个函数创建平台相关的 `Context` 结构。 +三种线程的平台无关创建流程实现在 [kernel/src/process/context.rs](../../../kernel/src/process/structs.rs#L40) 里,最终会分别调用 [kernel/src/arch/aarch64/interrupt/context.rs](../../../kernel/src/arch/aarch64/interrupt/context.rs#L146) 里的 `new_kernel_thread()`、`new_user_thread()` 和 `new_fork()` 这三个函数创建平台相关的 `Context` 结构。 在这三个函数里,会构造 `ContextData` 与 `TrapFrame` 结构,构成一个 `InitStack`,并向新线程的内核栈压入 `InitStack` 结构,最后将新内核栈顶地址、页表基址等信息构成 `Context` 结构返回。这两个结构的构造方式如下: diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 99030d5..645dc41 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -256,7 +256,7 @@ dependencies = [ "pc-keyboard 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rcore-memory 0.1.0", - "rcore-process 0.1.0", + "rcore-thread 0.1.0", "riscv 0.3.0 (git+https://github.com/riscv-and-rust-and-decaf/riscv)", "simple-filesystem 0.1.0 (git+https://github.com/wangrunji0408/SimpleFileSystem-Rust)", "smoltcp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -275,7 +275,7 @@ dependencies = [ ] [[package]] -name = "rcore-process" +name = "rcore-thread" version = "0.1.0" dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 76d496b..0bb1355 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -54,7 +54,7 @@ lazy_static = { version = "1.2", features = ["spin_no_std"] } smoltcp = { version = "0.5.0", default-features = false, features = ["alloc", "log", "proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp"] } bit-allocator = { path = "../crate/bit-allocator" } rcore-memory = { path = "../crate/memory" } -rcore-process = { path = "../crate/process" } +rcore-thread = { path = "../crate/thread" } simple-filesystem = { git = "https://github.com/wangrunji0408/SimpleFileSystem-Rust" } [target.'cfg(target_arch = "x86_64")'.dependencies] diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 53a0129..3ea683e 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -13,7 +13,7 @@ extern crate alloc; pub use crate::process::{processor, new_kernel_context}; -use rcore_process::thread; +use rcore_thread::std_thread as thread; use linked_list_allocator::LockedHeap; #[macro_use] // print! diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index d5479b9..c7488c9 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -1,21 +1,22 @@ -pub use self::context::Process; -pub use rcore_process::*; +pub use self::structs::*; +pub use rcore_thread::*; use crate::consts::{MAX_CPU_NUM, MAX_PROCESS_NUM}; use crate::arch::cpu; use alloc::{boxed::Box, sync::Arc}; +use spin::MutexGuard; use log::*; -pub mod context; +pub mod structs; mod abi; pub fn init() { // NOTE: max_time_slice <= 5 to ensure 'priority' test pass let scheduler = Box::new(scheduler::RRScheduler::new(5)); - let manager = Arc::new(ProcessManager::new(scheduler, MAX_PROCESS_NUM)); + let manager = Arc::new(ThreadPool::new(scheduler, MAX_PROCESS_NUM)); unsafe { for cpu_id in 0..MAX_CPU_NUM { - PROCESSORS[cpu_id].init(cpu_id, Process::new_init(), manager.clone()); + PROCESSORS[cpu_id].init(cpu_id, Thread::new_init(), manager.clone()); } } @@ -26,7 +27,7 @@ pub fn init() { use core::str::FromStr; let cores = usize::from_str(env!("SMP")).unwrap(); for i in 0..cores { - manager.add(Process::new_kernel(idle, i), 0); + manager.add(Thread::new_kernel(idle, i), 0); } crate::shell::run_user_shell(); @@ -35,12 +36,17 @@ pub fn init() { static PROCESSORS: [Processor; MAX_CPU_NUM] = [Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new()]; -/// Get current thread struct +/// Get current process +pub fn process() -> MutexGuard<'static, Process> { + current_thread().proc.lock() +} + +/// Get current thread /// /// FIXME: It's obviously unsafe to get &mut ! -pub fn process() -> &'static mut Process { +pub fn current_thread() -> &'static mut Thread { use core::mem::transmute; - let (process, _): (&mut Process, *const ()) = unsafe { + let (process, _): (&mut Thread, *const ()) = unsafe { transmute(processor().context()) }; process @@ -56,5 +62,5 @@ pub fn processor() -> &'static Processor { #[no_mangle] pub fn new_kernel_context(entry: extern fn(usize) -> !, arg: usize) -> Box { - Process::new_kernel(entry, arg) + Thread::new_kernel(entry, arg) } diff --git a/kernel/src/process/context.rs b/kernel/src/process/structs.rs similarity index 75% rename from kernel/src/process/context.rs rename to kernel/src/process/structs.rs index ac7e0a6..731a4b6 100644 --- a/kernel/src/process/context.rs +++ b/kernel/src/process/structs.rs @@ -3,56 +3,66 @@ use alloc::{boxed::Box, collections::BTreeMap, string::String, sync::Arc, vec::V use log::*; use simple_filesystem::{file::File, INode}; use spin::Mutex; -use rcore_process::Context; use xmas_elf::{ElfFile, header, program::{Flags, Type}}; -use crate::arch::interrupt::{Context as ArchContext, TrapFrame}; +use crate::arch::interrupt::{Context, TrapFrame}; use crate::memory::{ByFrame, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet}; use super::abi::ProcInitInfo; // TODO: avoid pub +pub struct Thread { + pub context: Context, + pub kstack: KernelStack, + pub proc: Arc>, +} + pub struct Process { - pub arch: ArchContext, pub memory_set: MemorySet, - pub kstack: KernelStack, pub files: BTreeMap>>, // FIXME: => Box pub cwd: String, } -impl Context for Process { - unsafe fn switch_to(&mut self, target: &mut Context) { +/// Let `rcore_thread` can switch between our `Thread` +impl rcore_thread::Context for Thread { + unsafe fn switch_to(&mut self, target: &mut rcore_thread::Context) { use core::mem::transmute; - let (target, _): (&mut Process, *const ()) = transmute(target); - self.arch.switch(&mut target.arch); + let (target, _): (&mut Thread, *const ()) = transmute(target); + self.context.switch(&mut target.context); } } -impl Process { - pub unsafe fn new_init() -> Box { - Box::new(Process { - arch: ArchContext::null(), - memory_set: MemorySet::new(), +impl Thread { + /// Make a struct for the init thread + pub unsafe fn new_init() -> Box { + Box::new(Thread { + context: Context::null(), kstack: KernelStack::new(), - files: BTreeMap::default(), - cwd: String::new(), + proc: Arc::new(Mutex::new(Process { + memory_set: MemorySet::new(), + files: BTreeMap::default(), + cwd: String::new(), + })), }) } - pub fn new_kernel(entry: extern fn(usize) -> !, arg: usize) -> Box { + /// Make a new kernel thread starting from `entry` with `arg` + pub fn new_kernel(entry: extern fn(usize) -> !, arg: usize) -> Box { let memory_set = MemorySet::new(); let kstack = KernelStack::new(); - Box::new(Process { - arch: unsafe { ArchContext::new_kernel_thread(entry, arg, kstack.top(), memory_set.token()) }, - memory_set, + Box::new(Thread { + context: unsafe { Context::new_kernel_thread(entry, arg, kstack.top(), memory_set.token()) }, kstack, - files: BTreeMap::default(), - cwd: String::new(), + proc: Arc::new(Mutex::new(Process { + memory_set, + files: BTreeMap::default(), + cwd: String::new(), + })), }) } - /// Make a new user thread from ELF data - pub fn new_user<'a, Iter>(data: &[u8], args: Iter) -> Box + /// Make a new user process from ELF `data` + pub fn new_user<'a, Iter>(data: &[u8], args: Iter) -> Box where Iter: Iterator { // Parse elf @@ -105,23 +115,25 @@ impl Process { files.insert(1, Arc::new(Mutex::new(File::new(crate::fs::STDOUT.clone(), false, true)))); files.insert(2, Arc::new(Mutex::new(File::new(crate::fs::STDOUT.clone(), false, true)))); - Box::new(Process { - arch: unsafe { - ArchContext::new_user_thread( + Box::new(Thread { + context: unsafe { + Context::new_user_thread( entry_addr, ustack_top, kstack.top(), is32, memory_set.token()) }, - memory_set, kstack, - files, - cwd: String::new(), + proc: Arc::new(Mutex::new(Process { + memory_set, + files, + cwd: String::new(), + })), }) } - /// Fork - pub fn fork(&self, tf: &TrapFrame) -> Box { + /// Fork a new process from current one + pub fn fork(&self, tf: &TrapFrame) -> Box { info!("COME into fork!"); // Clone memory set, make a new page table - let memory_set = self.memory_set.clone(); + let memory_set = self.proc.lock().memory_set.clone(); info!("finish mmset clone in fork!"); // MMU: copy data to the new space @@ -137,12 +149,14 @@ impl Process { info!("temporary copy data!"); let kstack = KernelStack::new(); - Box::new(Process { - arch: unsafe { ArchContext::new_fork(tf, kstack.top(), memory_set.token()) }, - memory_set, + Box::new(Thread { + context: unsafe { Context::new_fork(tf, kstack.top(), memory_set.token()) }, kstack, - files: self.files.clone(), - cwd: String::new(), + proc: Arc::new(Mutex::new(Process { + memory_set, + files: self.proc.lock().files.clone(), + cwd: String::new(), + })), }) } } diff --git a/kernel/src/shell.rs b/kernel/src/shell.rs index 4fa2057..e2ed691 100644 --- a/kernel/src/shell.rs +++ b/kernel/src/shell.rs @@ -3,15 +3,16 @@ use alloc::string::String; use crate::fs::{ROOT_INODE, INodeExt}; use crate::process::*; +use crate::thread; pub fn run_user_shell() { if let Ok(inode) = ROOT_INODE.lookup("sh") { println!("Going to user mode shell."); println!("Use 'ls' to list available programs."); let data = inode.read_as_vec().unwrap(); - processor().manager().add(Process::new_user(data.as_slice(), "sh".split(' ')), 0); + processor().manager().add(Thread::new_user(data.as_slice(), "sh".split(' ')), 0); } else { - processor().manager().add(Process::new_kernel(shell, 0), 0); + processor().manager().add(Thread::new_kernel(shell, 0), 0); } } @@ -28,7 +29,7 @@ pub extern fn shell(_arg: usize) -> ! { let name = cmd.split(' ').next().unwrap(); if let Ok(file) = ROOT_INODE.lookup(name) { let data = file.read_as_vec().unwrap(); - let pid = processor().manager().add(Process::new_user(data.as_slice(), cmd.split(' ')), thread::current().id()); + let pid = processor().manager().add(Thread::new_user(data.as_slice(), cmd.split(' ')), thread::current().id()); unsafe { thread::JoinHandle::<()>::_of(pid) }.join().unwrap(); } else { println!("Program not exist"); diff --git a/kernel/src/syscall.rs b/kernel/src/syscall.rs index bbcb8fa..5a7ef14 100644 --- a/kernel/src/syscall.rs +++ b/kernel/src/syscall.rs @@ -3,7 +3,7 @@ use simple_filesystem::{INode, file::File, FileInfo, FileType, FsError}; use core::{slice, str}; use alloc::{sync::Arc, vec::Vec, string::String}; -use spin::Mutex; +use spin::{Mutex, MutexGuard}; use log::*; use bitflags::bitflags; use crate::arch::interrupt::TrapFrame; @@ -98,7 +98,8 @@ fn sys_read(fd: usize, base: *mut u8, len: usize) -> SysResult { // TODO: check ptr info!("read: fd: {}, base: {:?}, len: {:#x}", fd, base, len); let slice = unsafe { slice::from_raw_parts_mut(base, len) }; - let len = get_file(fd)?.lock().read(slice)?; + let proc = process(); + let len = get_file(&proc, fd)?.lock().read(slice)?; Ok(len as isize) } @@ -106,7 +107,8 @@ fn sys_write(fd: usize, base: *const u8, len: usize) -> SysResult { // TODO: check ptr info!("write: fd: {}, base: {:?}, len: {:#x}", fd, base, len); let slice = unsafe { slice::from_raw_parts(base, len) }; - let len = get_file(fd)?.lock().write(slice)?; + let proc = process(); + let len = get_file(&proc, fd)?.lock().write(slice)?; Ok(len as isize) } @@ -140,7 +142,8 @@ fn sys_close(fd: usize) -> SysResult { fn sys_fstat(fd: usize, stat_ptr: *mut Stat) -> SysResult { // TODO: check ptr info!("fstat: {}", fd); - let file = get_file(fd)?; + let proc = process(); + let file = get_file(&proc, fd)?; let stat = Stat::from(file.lock().info()?); unsafe { stat_ptr.write(stat); } Ok(0) @@ -152,7 +155,8 @@ fn sys_fstat(fd: usize, stat_ptr: *mut Stat) -> SysResult { fn sys_getdirentry(fd: usize, dentry_ptr: *mut DirEntry) -> SysResult { // TODO: check ptr info!("getdirentry: {}", fd); - let file = get_file(fd)?; + let proc = process(); + let file = get_file(&proc, fd)?; let dentry = unsafe { &mut *dentry_ptr }; if !dentry.check() { return Err(SysError::Inval); @@ -168,7 +172,8 @@ fn sys_getdirentry(fd: usize, dentry_ptr: *mut DirEntry) -> SysResult { fn sys_dup2(fd1: usize, fd2: usize) -> SysResult { info!("dup2: {} {}", fd1, fd2); - let file = get_file(fd1)?; + let proc = process(); + let file = get_file(&proc, fd1)?; if process().files.contains_key(&fd2) { return Err(SysError::Inval); } @@ -178,7 +183,7 @@ fn sys_dup2(fd1: usize, fd2: usize) -> SysResult { /// Fork the current process. Return the child's PID. fn sys_fork(tf: &TrapFrame) -> SysResult { - let context = process().fork(tf); + let context = current_thread().fork(tf); let pid = processor().manager().add(context, thread::current().id()); info!("fork: {} -> {}", thread::current().id(), pid); Ok(pid as isize) @@ -244,19 +249,19 @@ fn sys_exec(name: *const u8, argc: usize, argv: *const *const u8, tf: &mut TrapF unsafe { buf.set_len(size); } inode.read_at(0, buf.as_mut_slice())?; - // Make new Context + // Make new Thread let iter = args.iter().map(|s| s.as_str()); - let mut context = Process::new_user(buf.as_slice(), iter); + let mut thread = Thread::new_user(buf.as_slice(), iter); // Activate new page table - unsafe { context.memory_set.activate(); } + unsafe { thread.proc.lock().memory_set.activate(); } // Modify the TrapFrame - *tf = unsafe { context.arch.get_init_tf() }; + *tf = unsafe { thread.context.get_init_tf() }; // Swap Context but keep KStack - ::core::mem::swap(&mut process().kstack, &mut context.kstack); - ::core::mem::swap(process(), &mut *context); + ::core::mem::swap(&mut current_thread().kstack, &mut thread.kstack); + ::core::mem::swap(current_thread(), &mut *thread); Ok(0) } @@ -315,8 +320,8 @@ fn sys_putc(c: char) -> SysResult { Ok(0) } -fn get_file(fd: usize) -> Result<&'static Arc>, SysError> { - process().files.get(&fd).ok_or(SysError::Inval) +fn get_file<'a>(proc: &'a MutexGuard<'static, Process>, fd: usize) -> Result<&'a Arc>, SysError> { + proc.files.get(&fd).ok_or(SysError::Inval) } pub type SysResult = Result; diff --git a/kernel/src/trap.rs b/kernel/src/trap.rs index c5f1e08..61e2495 100644 --- a/kernel/src/trap.rs +++ b/kernel/src/trap.rs @@ -14,7 +14,7 @@ pub fn timer() { pub fn error(tf: &TrapFrame) -> ! { error!("{:#x?}", tf); - let pid = processor().pid(); + let pid = processor().tid(); error!("On CPU{} Process {}", cpu::id(), pid); processor().manager().exit(pid, 0x100);