Implement tid/pid/ppid separation

master
Jiajie Chen 6 years ago
parent 82457be2ec
commit 8cb11b7aa8

@ -23,6 +23,8 @@ pub struct MemoryArea {
name: &'static str, name: &'static str,
} }
unsafe impl Send for MemoryArea { }
impl MemoryArea { impl MemoryArea {
/* /*
** @brief get slice of the content in the memory area ** @brief get slice of the content in the memory area

@ -59,9 +59,9 @@ impl Processor {
unsafe { unsafe {
inner.loop_context.switch_to(&mut *inner.proc.as_mut().unwrap().1); inner.loop_context.switch_to(&mut *inner.proc.as_mut().unwrap().1);
} }
let (pid, context) = inner.proc.take().unwrap(); let (tid, context) = inner.proc.take().unwrap();
trace!("CPU{} stop running thread {}", inner.id, pid); trace!("CPU{} stop running thread {}", inner.id, tid);
inner.manager.stop(pid, context); inner.manager.stop(tid, context);
} else { } else {
trace!("CPU{} idle", inner.id); trace!("CPU{} idle", inner.id);
unsafe { interrupt::enable_and_wfi(); } unsafe { interrupt::enable_and_wfi(); }

@ -11,19 +11,19 @@ mod rr;
mod stride; mod stride;
mod work_stealing; mod work_stealing;
type Pid = usize; type Tid = usize;
/// The scheduler for a ThreadPool /// The scheduler for a ThreadPool
pub trait Scheduler: 'static { pub trait Scheduler: 'static {
/// Push a thread to the back of ready queue. /// Push a thread to the back of ready queue.
fn push(&self, pid: Pid); fn push(&self, tid: Tid);
/// Select a thread to run, pop it from the queue. /// Select a thread to run, pop it from the queue.
fn pop(&self, cpu_id: usize) -> Option<Pid>; fn pop(&self, cpu_id: usize) -> Option<Tid>;
/// Got a tick from CPU. /// Got a tick from CPU.
/// Return true if need reschedule. /// Return true if need reschedule.
fn tick(&self, current_pid: Pid) -> bool; fn tick(&self, current_tid: Tid) -> bool;
/// Set priority of a thread. /// Set priority of a thread.
fn set_priority(&self, pid: Pid, priority: u8); fn set_priority(&self, tid: Tid, priority: u8);
} }
fn expand<T: Default + Clone>(vec: &mut Vec<T>, id: usize) { fn expand<T: Default + Clone>(vec: &mut Vec<T>, id: usize) {

@ -13,21 +13,21 @@ struct RRSchedulerInner {
struct RRProcInfo { struct RRProcInfo {
present: bool, present: bool,
rest_slice: usize, rest_slice: usize,
prev: Pid, prev: Tid,
next: Pid, next: Tid,
} }
impl Scheduler for RRScheduler { impl Scheduler for RRScheduler {
fn push(&self, pid: usize) { fn push(&self, tid: usize) {
self.inner.lock().push(pid); self.inner.lock().push(tid);
} }
fn pop(&self, _cpu_id: usize) -> Option<usize> { fn pop(&self, _cpu_id: usize) -> Option<usize> {
self.inner.lock().pop() self.inner.lock().pop()
} }
fn tick(&self, current_pid: usize) -> bool { fn tick(&self, current_tid: usize) -> bool {
self.inner.lock().tick(current_pid) self.inner.lock().tick(current_tid)
} }
fn set_priority(&self, _pid: usize, _priority: u8) {} fn set_priority(&self, _tid: usize, _priority: u8) {}
} }
impl RRScheduler { impl RRScheduler {
@ -41,35 +41,35 @@ impl RRScheduler {
} }
impl RRSchedulerInner { impl RRSchedulerInner {
fn push(&mut self, pid: Pid) { fn push(&mut self, tid: Tid) {
let pid = pid + 1; let tid = tid + 1;
expand(&mut self.infos, pid); expand(&mut self.infos, tid);
{ {
let info = &mut self.infos[pid]; let info = &mut self.infos[tid];
assert!(!info.present); assert!(!info.present);
info.present = true; info.present = true;
if info.rest_slice == 0 { if info.rest_slice == 0 {
info.rest_slice = self.max_time_slice; info.rest_slice = self.max_time_slice;
} }
} }
self._list_add_before(pid, 0); self._list_add_before(tid, 0);
trace!("rr push {}", pid - 1); trace!("rr push {}", tid - 1);
} }
fn pop(&mut self) -> Option<Pid> { fn pop(&mut self) -> Option<Tid> {
let ret = match self.infos[0].next { let ret = match self.infos[0].next {
0 => None, 0 => None,
pid => { tid => {
self.infos[pid].present = false; self.infos[tid].present = false;
self._list_remove(pid); self._list_remove(tid);
Some(pid - 1) Some(tid - 1)
}, },
}; };
trace!("rr pop {:?}", ret); trace!("rr pop {:?}", ret);
ret ret
} }
fn tick(&mut self, current: Pid) -> bool { fn tick(&mut self, current: Tid) -> bool {
let current = current + 1; let current = current + 1;
expand(&mut self.infos, current); expand(&mut self.infos, current);
assert!(!self.infos[current].present); assert!(!self.infos[current].present);
@ -85,18 +85,18 @@ impl RRSchedulerInner {
} }
impl RRSchedulerInner { impl RRSchedulerInner {
fn _list_add_before(&mut self, i: Pid, at: Pid) { fn _list_add_before(&mut self, i: Tid, at: Tid) {
let prev = self.infos[at].prev; let prev = self.infos[at].prev;
self.infos[i].next = at; self.infos[i].next = at;
self.infos[i].prev = prev; self.infos[i].prev = prev;
self.infos[prev].next = i; self.infos[prev].next = i;
self.infos[at].prev = i; self.infos[at].prev = i;
} }
fn _list_add_after(&mut self, i: Pid, at: Pid) { fn _list_add_after(&mut self, i: Tid, at: Tid) {
let next = self.infos[at].next; let next = self.infos[at].next;
self._list_add_before(i, next); self._list_add_before(i, next);
} }
fn _list_remove(&mut self, i: Pid) { fn _list_remove(&mut self, i: Tid) {
let next = self.infos[i].next; let next = self.infos[i].next;
let prev = self.infos[i].prev; let prev = self.infos[i].prev;
self.infos[next].prev = prev; self.infos[next].prev = prev;

@ -7,7 +7,7 @@ pub struct StrideScheduler {
pub struct StrideSchedulerInner { pub struct StrideSchedulerInner {
max_time_slice: usize, max_time_slice: usize,
infos: Vec<StrideProcInfo>, infos: Vec<StrideProcInfo>,
queue: BinaryHeap<(Stride, Pid)>, // It's max heap, so pass < 0 queue: BinaryHeap<(Stride, Tid)>, // It's max heap, so pass < 0
} }
#[derive(Debug, Default, Copy, Clone)] #[derive(Debug, Default, Copy, Clone)]
@ -35,17 +35,17 @@ impl StrideProcInfo {
type Stride = i32; type Stride = i32;
impl Scheduler for StrideScheduler { impl Scheduler for StrideScheduler {
fn push(&self, pid: usize) { fn push(&self, tid: usize) {
self.inner.lock().push(pid); self.inner.lock().push(tid);
} }
fn pop(&self, _cpu_id: usize) -> Option<usize> { fn pop(&self, _cpu_id: usize) -> Option<usize> {
self.inner.lock().pop() self.inner.lock().pop()
} }
fn tick(&self, current_pid: usize) -> bool { fn tick(&self, current_tid: usize) -> bool {
self.inner.lock().tick(current_pid) self.inner.lock().tick(current_tid)
} }
fn set_priority(&self, pid: usize, priority: u8) { fn set_priority(&self, tid: usize, priority: u8) {
self.inner.lock().set_priority(pid, priority); self.inner.lock().set_priority(tid, priority);
} }
} }
@ -61,31 +61,31 @@ impl StrideScheduler {
} }
impl StrideSchedulerInner { impl StrideSchedulerInner {
fn push(&mut self, pid: Pid) { fn push(&mut self, tid: Tid) {
expand(&mut self.infos, pid); expand(&mut self.infos, tid);
let info = &mut self.infos[pid]; let info = &mut self.infos[tid];
assert!(!info.present); assert!(!info.present);
info.present = true; info.present = true;
if info.rest_slice == 0 { if info.rest_slice == 0 {
info.rest_slice = self.max_time_slice; info.rest_slice = self.max_time_slice;
} }
self.queue.push((-info.stride, pid)); self.queue.push((-info.stride, tid));
trace!("stride push {}", pid); trace!("stride push {}", tid);
} }
fn pop(&mut self) -> Option<Pid> { fn pop(&mut self) -> Option<Tid> {
let ret = self.queue.pop().map(|(_, pid)| pid); let ret = self.queue.pop().map(|(_, tid)| tid);
if let Some(pid) = ret { if let Some(tid) = ret {
let old_stride = self.infos[pid].stride; let old_stride = self.infos[tid].stride;
self.infos[pid].pass(); self.infos[tid].pass();
let stride = self.infos[pid].stride; let stride = self.infos[tid].stride;
trace!("stride {} {:#x} -> {:#x}", pid, old_stride, stride); trace!("stride {} {:#x} -> {:#x}", tid, old_stride, stride);
} }
trace!("stride pop {:?}", ret); trace!("stride pop {:?}", ret);
ret ret
} }
fn tick(&mut self, current: Pid) -> bool { fn tick(&mut self, current: Tid) -> bool {
expand(&mut self.infos, current); expand(&mut self.infos, current);
assert!(!self.infos[current].present); assert!(!self.infos[current].present);
@ -98,8 +98,8 @@ impl StrideSchedulerInner {
*rest == 0 *rest == 0
} }
fn set_priority(&mut self, pid: Pid, priority: u8) { fn set_priority(&mut self, tid: Tid, priority: u8) {
self.infos[pid].priority = priority; self.infos[tid].priority = priority;
trace!("stride {} priority = {}", pid, priority); trace!("stride {} priority = {}", tid, priority);
} }
} }

@ -3,9 +3,9 @@ use deque::{self, Stealer, Worker, Stolen};
pub struct WorkStealingScheduler { pub struct WorkStealingScheduler {
/// The ready queue of each processors /// The ready queue of each processors
workers: Vec<Worker<Pid>>, workers: Vec<Worker<Tid>>,
/// Stealers to all processors' queue /// Stealers to all processors' queue
stealers: Vec<Stealer<Pid>>, stealers: Vec<Stealer<Tid>>,
} }
impl WorkStealingScheduler { impl WorkStealingScheduler {
@ -16,17 +16,17 @@ impl WorkStealingScheduler {
} }
impl Scheduler for WorkStealingScheduler { impl Scheduler for WorkStealingScheduler {
fn push(&self, pid: usize) { fn push(&self, tid: usize) {
// TODO: push to random queue? // TODO: push to random queue?
// now just push to cpu0 // now just push to cpu0
self.workers[0].push(pid); self.workers[0].push(tid);
trace!("work-stealing: cpu0 push thread {}", pid); trace!("work-stealing: cpu0 push thread {}", tid);
} }
fn pop(&self, cpu_id: usize) -> Option<usize> { fn pop(&self, cpu_id: usize) -> Option<usize> {
if let Some(pid) = self.workers[cpu_id].pop() { if let Some(tid) = self.workers[cpu_id].pop() {
trace!("work-stealing: cpu{} pop thread {}", cpu_id, pid); trace!("work-stealing: cpu{} pop thread {}", cpu_id, tid);
return Some(pid); return Some(tid);
} }
let n = self.workers.len(); let n = self.workers.len();
for i in 1..n { for i in 1..n {
@ -38,9 +38,9 @@ impl Scheduler for WorkStealingScheduler {
match self.stealers[other_id].steal() { match self.stealers[other_id].steal() {
Stolen::Abort => {} // retry Stolen::Abort => {} // retry
Stolen::Empty => break, Stolen::Empty => break,
Stolen::Data(pid) => { Stolen::Data(tid) => {
trace!("work-stealing: cpu{} steal thread {} from cpu{}", cpu_id, pid, other_id); trace!("work-stealing: cpu{} steal thread {} from cpu{}", cpu_id, tid, other_id);
return Some(pid); return Some(tid);
} }
} }
} }
@ -48,9 +48,9 @@ impl Scheduler for WorkStealingScheduler {
None None
} }
fn tick(&self, _current_pid: usize) -> bool { fn tick(&self, _current_tid: usize) -> bool {
true true
} }
fn set_priority(&self, _pid: usize, _priority: u8) {} fn set_priority(&self, _tid: usize, _priority: u8) {}
} }

@ -92,17 +92,16 @@ pub fn spawn<F, T>(f: F) -> JoinHandle<T>
// 在Processor中创建新的线程 // 在Processor中创建新的线程
let context = new_kernel_context(kernel_thread_entry::<F, T>, f as usize); let context = new_kernel_context(kernel_thread_entry::<F, T>, f as usize);
let pid = processor().manager().add(context, 0); let tid = processor().manager().add(context);
// 接下来看看`JoinHandle::join()`的实现 // 接下来看看`JoinHandle::join()`的实现
// 了解是如何获取f返回值的 // 了解是如何获取f返回值的
return JoinHandle { return JoinHandle {
thread: Thread { pid },
mark: PhantomData, mark: PhantomData,
}; };
} }
/// Cooperatively gives up a timeslice to the OS scheduler. /// Cooperatively gives up a time slice to the OS scheduler.
pub fn yield_now() { pub fn yield_now() {
trace!("yield:"); trace!("yield:");
processor().yield_now(); processor().yield_now();
@ -131,119 +130,14 @@ impl Thread {
} }
} }
/// An owned permission to join on a thread (block on its termination). /// An owned permission to join on a process (block on its termination).
pub struct JoinHandle<T> { pub struct JoinHandle<T> {
thread: Thread,
mark: PhantomData<T>, mark: PhantomData<T>,
} }
impl<T> JoinHandle<T> { impl<T> JoinHandle<T> {
/// Extracts a handle to the underlying thread.
pub fn thread(&self) -> &Thread {
&self.thread
}
/// 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, ()> {
loop { unimplemented!();
trace!("{} join", self.thread.pid);
match processor().manager().get_status(self.thread.pid) {
Some(Status::Exited(exit_code)) => {
processor().manager().remove(self.thread.pid);
// Find return value on the heap from the exit code.
return Ok(unsafe { *Box::from_raw(exit_code as *mut T) });
}
None => return Err(()),
_ => {}
}
processor().manager().wait(current().id(), self.thread.pid);
processor().yield_now();
}
}
/// Force construct a JoinHandle struct
pub unsafe fn _of(pid: Tid) -> JoinHandle<T> {
JoinHandle {
thread: Thread { pid },
mark: PhantomData,
}
} }
} }
//pub struct LocalKey<T: 'static> {
// init: fn() -> T,
//}
//
//impl<T: 'static> LocalKey<T> {
// pub fn with<F, R>(&'static self, f: F) -> R
// where F: FnOnce(&T) -> R
// {
// let map = unsafe { Self::get_map() };
// let key = self as *const _ as usize;
// if !map.contains_key(&key) {
// map.insert(key, Box::new((self.init)()));
// }
// let value = map.get(&key).unwrap().downcast_ref::<T>().expect("type error");
// f(value)
// }
// pub const fn new(init: fn() -> T) -> Self {
// LocalKey { init }
// }
// /// Get `BTreeMap<usize, Box<Any>>` at the current kernel stack bottom
// /// The stack must be aligned with 0x8000
// unsafe fn get_map() -> &'static mut BTreeMap<usize, Box<Any>> {
// const STACK_SIZE: usize = 0x8000;
// let stack_var = 0usize;
// let ptr = (&stack_var as *const _ as usize) / STACK_SIZE * STACK_SIZE;
// let map = unsafe { &mut *(ptr as *mut Option<BTreeMap<usize, Box<Any>>>) };
// if map.is_none() {
// *map = Some(BTreeMap::new());
// }
// map.as_mut().unwrap()
// }
//}
//
//pub mod test {
// use thread;
// use core::cell::RefCell;
// use core::time::Duration;
//
// pub fn unpack() {
// let parked_thread = thread::spawn(|| {
// println!("Parking thread");
// thread::park();
// println!("Thread unparked");
// 5
// });
//
// // Let some time pass for the thread to be spawned.
// thread::sleep(Duration::from_secs(2));
//
// println!("Unpark the thread");
// parked_thread.thread().unpark();
//
// let ret = parked_thread.join().unwrap();
// assert_eq!(ret, 5);
// }
//
// pub fn local_key() {
// static FOO: thread::LocalKey<RefCell<usize>> = thread::LocalKey::new(|| RefCell::new(1));
//
// FOO.with(|f| {
// assert_eq!(*f.borrow(), 1);
// *f.borrow_mut() = 2;
// });
//
// // each thread starts out with the initial value of 1
// thread::spawn(move || {
// FOO.with(|f| {
// assert_eq!(*f.borrow(), 1);
// *f.borrow_mut() = 3;
// });
// }).join();
//
// // we retain our original value of 2 despite the child thread
// FOO.with(|f| {
// assert_eq!(*f.borrow(), 2);
// });
// println!("local key success");
// }
//}

@ -1,6 +1,6 @@
use alloc::boxed::Box; use alloc::boxed::Box;
use alloc::vec::Vec; use alloc::vec::Vec;
use spin::Mutex; use spin::{Mutex, MutexGuard};
use log::*; use log::*;
use crate::scheduler::Scheduler; use crate::scheduler::Scheduler;
use crate::timer::Timer; use crate::timer::Timer;
@ -9,8 +9,6 @@ struct Thread {
status: Status, status: Status,
status_after_stop: Status, status_after_stop: Status,
context: Option<Box<Context>>, context: Option<Box<Context>>,
parent: Tid,
children: Vec<Tid>,
} }
pub type Tid = usize; pub type Tid = usize;
@ -21,7 +19,6 @@ pub enum Status {
Ready, Ready,
Running(usize), Running(usize),
Sleeping, Sleeping,
Waiting(Tid),
/// aka ZOMBIE. Its context was dropped. /// aka ZOMBIE. Its context was dropped.
Exited(ExitCode), Exited(ExitCode),
} }
@ -32,7 +29,11 @@ enum Event {
} }
pub trait Context { pub trait Context {
/// Switch to target context
unsafe fn switch_to(&mut self, target: &mut Context); unsafe fn switch_to(&mut self, target: &mut Context);
/// A tid is allocated for this context
fn set_tid(&mut self, tid: Tid);
} }
pub struct ThreadPool { pub struct ThreadPool {
@ -50,28 +51,27 @@ impl ThreadPool {
} }
} }
fn alloc_tid(&self) -> Tid { fn alloc_tid(&self) -> (Tid, MutexGuard<Option<Thread>>) {
for (i, proc) in self.threads.iter().enumerate() { for (i, proc) in self.threads.iter().enumerate() {
if proc.lock().is_none() { let thread = proc.lock();
return i; if thread.is_none() {
return (i, thread);
} }
} }
panic!("Process number exceeded"); panic!("Process number exceeded");
} }
/// Add a new process /// Add a new thread
pub fn add(&self, context: Box<Context>, parent: Tid) -> Tid { /// Calls action with tid and thread context
let tid = self.alloc_tid(); pub fn add(&self, mut context: Box<Context>) -> Tid {
*(&self.threads[tid]).lock() = Some(Thread { let (tid, mut thread) = self.alloc_tid();
context.set_tid(tid);
*thread = Some(Thread {
status: Status::Ready, status: Status::Ready,
status_after_stop: Status::Ready, status_after_stop: Status::Ready,
context: Some(context), context: Some(context),
parent,
children: Vec::new(),
}); });
self.scheduler.push(tid); self.scheduler.push(tid);
self.threads[parent].lock().as_mut().expect("invalid parent proc")
.children.push(tid);
tid tid
} }
@ -162,7 +162,6 @@ impl ThreadPool {
} }
/// Remove an exited proc `tid`. /// Remove an exited proc `tid`.
/// Its all children will be set parent to 0.
pub fn remove(&self, tid: Tid) { pub fn remove(&self, tid: Tid) {
let mut proc_lock = self.threads[tid].lock(); let mut proc_lock = self.threads[tid].lock();
let proc = proc_lock.as_ref().expect("process not exist"); let proc = proc_lock.as_ref().expect("process not exist");
@ -170,13 +169,6 @@ impl ThreadPool {
Status::Exited(_) => {} Status::Exited(_) => {}
_ => panic!("can not remove non-exited process"), _ => 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 // release the tid
*proc_lock = None; *proc_lock = None;
} }
@ -194,32 +186,12 @@ impl ThreadPool {
self.set_status(tid, Status::Ready); 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<Tid> {
self.threads[tid].lock().as_ref().expect("process not exist").children.clone()
}
pub fn get_parent(&self, tid: Tid) -> Tid {
self.threads[tid].lock().as_ref().expect("process not exist").parent
}
pub fn exit(&self, tid: Tid, code: ExitCode) { pub fn exit(&self, tid: Tid, code: ExitCode) {
// NOTE: if `tid` is running, status change will be deferred. // NOTE: if `tid` is running, status change will be deferred.
self.set_status(tid, Status::Exited(code)); self.set_status(tid, Status::Exited(code));
} }
/// Called when a process exit /// Called when a process exit
fn exit_handler(&self, tid: Tid, proc: &mut Thread) { 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 // drop its context
proc.context = None; proc.context = None;
} }

@ -1,13 +1,13 @@
use alloc::{boxed::Box, collections::BTreeMap, string::String, sync::Arc, vec::Vec}; use alloc::{boxed::Box, collections::BTreeMap, collections::btree_map::Entry, string::String, sync::Arc, vec::Vec, sync::Weak};
use core::fmt; use core::fmt;
use log::*; use log::*;
use rcore_fs::vfs::INode; use spin::{Mutex, RwLock};
use spin::Mutex;
use xmas_elf::{ElfFile, header, program::{Flags, Type}}; use xmas_elf::{ElfFile, header, program::{Flags, Type}};
use smoltcp::socket::SocketHandle; use smoltcp::socket::SocketHandle;
use smoltcp::wire::IpEndpoint; use smoltcp::wire::IpEndpoint;
use rcore_memory::PAGE_SIZE; use rcore_memory::PAGE_SIZE;
use rcore_thread::Tid;
use crate::arch::interrupt::{Context, TrapFrame}; use crate::arch::interrupt::{Context, TrapFrame};
use crate::memory::{ByFrame, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet}; use crate::memory::{ByFrame, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet};
@ -69,13 +69,67 @@ impl fmt::Debug for FileLike {
} }
} }
/// Pid type
/// For strong type separation
#[derive(Clone, PartialEq)]
pub struct Pid(Option<usize>);
impl Pid {
pub fn uninitialized() -> Self {
Pid(None)
}
pub fn no_one() -> Self {
Pid(Some(0))
}
/// Return if it was uninitialized before this call
/// When returning true, it usually means this is the first thread
pub fn set_if_uninitialized(&mut self, tid: Tid) -> bool {
if self.0 == None {
self.0 = Some(tid as usize);
true
} else {
false
}
}
pub fn get(&self) -> usize {
self.0.unwrap()
}
}
impl fmt::Display for Pid {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.0 {
Some(pid) => write!(f, "{}", pid),
None => write!(f, "None"),
}
}
}
pub struct Process { pub struct Process {
pub memory_set: MemorySet, pub memory_set: MemorySet,
pub files: BTreeMap<usize, FileLike>, pub files: BTreeMap<usize, FileLike>,
pub cwd: String, pub cwd: String,
pub pid: Pid, // i.e. tgid, usually the tid of first thread
pub ppid: Pid, // the pid of the parent process
pub threads: Vec<Tid>, // threads in the same process
pub exit_cond: Condvar, // notified when the whole process is going to terminate
pub exit_code: Option<usize>, // only available when last thread exits
futexes: BTreeMap<usize, Arc<Condvar>>, futexes: BTreeMap<usize, Arc<Condvar>>,
} }
/// Records the mapping between pid and Process struct.
lazy_static! {
pub static ref PROCESSES: RwLock<BTreeMap<usize, Weak<Mutex<Process>>>> = RwLock::new(BTreeMap::new());
}
/// Records the list of child processes
lazy_static! {
pub static ref CHILD_PROCESSES: RwLock<BTreeMap<usize, Vec<Arc<Mutex<Process>>>>> = RwLock::new(BTreeMap::new());
}
/// Let `rcore_thread` can switch between our `Thread` /// Let `rcore_thread` can switch between our `Thread`
impl rcore_thread::Context for Thread { impl rcore_thread::Context for Thread {
unsafe fn switch_to(&mut self, target: &mut rcore_thread::Context) { unsafe fn switch_to(&mut self, target: &mut rcore_thread::Context) {
@ -83,6 +137,26 @@ impl rcore_thread::Context for Thread {
let (target, _): (&mut Thread, *const ()) = transmute(target); let (target, _): (&mut Thread, *const ()) = transmute(target);
self.context.switch(&mut target.context); self.context.switch(&mut target.context);
} }
fn set_tid(&mut self, tid: Tid) {
// set pid=tid if unspecified
let mut proc = self.proc.lock();
if proc.pid.set_if_uninitialized(tid) {
// first thread in the process
// link to its ppid
match CHILD_PROCESSES.write().entry(proc.ppid.get()) {
Entry::Vacant(entry) => {
entry.insert(vec![self.proc.clone()]);
}
Entry::Occupied(mut entry) => {
entry.get_mut().push(self.proc.clone());
}
}
}
// add it to threads
proc.threads.push(tid);
PROCESSES.write().insert(proc.pid.get(), Arc::downgrade(&self.proc));
}
} }
impl Thread { impl Thread {
@ -97,6 +171,11 @@ impl Thread {
files: BTreeMap::default(), files: BTreeMap::default(),
cwd: String::from("/"), cwd: String::from("/"),
futexes: BTreeMap::default(), futexes: BTreeMap::default(),
pid: Pid::uninitialized(),
ppid: Pid::no_one(),
exit_cond: Condvar::new(),
threads: Vec::new(),
exit_code: None
})), })),
}) })
} }
@ -114,6 +193,11 @@ impl Thread {
files: BTreeMap::default(), files: BTreeMap::default(),
cwd: String::from("/"), cwd: String::from("/"),
futexes: BTreeMap::default(), futexes: BTreeMap::default(),
pid: Pid::uninitialized(),
ppid: Pid::no_one(),
exit_cond: Condvar::new(),
threads: Vec::new(),
exit_code: None
})), })),
}) })
} }
@ -201,6 +285,11 @@ impl Thread {
files, files,
cwd: String::from("/"), cwd: String::from("/"),
futexes: BTreeMap::default(), futexes: BTreeMap::default(),
pid: Pid::uninitialized(),
ppid: Pid::no_one(),
exit_cond: Condvar::new(),
threads: Vec::new(),
exit_code: None
})), })),
}) })
} }
@ -211,6 +300,7 @@ impl Thread {
let memory_set = self.proc.lock().memory_set.clone(); let memory_set = self.proc.lock().memory_set.clone();
let files = self.proc.lock().files.clone(); let files = self.proc.lock().files.clone();
let cwd = self.proc.lock().cwd.clone(); let cwd = self.proc.lock().cwd.clone();
let ppid = self.proc.lock().pid.clone();
debug!("fork: finish clone MemorySet"); debug!("fork: finish clone MemorySet");
// MMU: copy data to the new space // MMU: copy data to the new space
@ -244,6 +334,11 @@ impl Thread {
files, files,
cwd, cwd,
futexes: BTreeMap::default(), futexes: BTreeMap::default(),
pid: Pid::uninitialized(),
ppid,
exit_cond: Condvar::new(),
threads: Vec::new(),
exit_code: None
})), })),
}) })
} }

@ -13,9 +13,9 @@ pub fn run_user_shell() {
println!("Going to user mode shell."); println!("Going to user mode shell.");
println!("Use 'ls' to list available programs."); println!("Use 'ls' to list available programs.");
let data = inode.read_as_vec().unwrap(); let data = inode.read_as_vec().unwrap();
processor().manager().add(Thread::new_user(data.as_slice(), "sh".split(' ')), 0); processor().manager().add(Thread::new_user(data.as_slice(), "sh".split(' ')));
} else { } else {
processor().manager().add(Thread::new_kernel(shell, 0), 0); processor().manager().add(Thread::new_kernel(shell, 0));
} }
} }
@ -33,8 +33,8 @@ pub extern fn shell(_arg: usize) -> ! {
let name = cmd.trim().split(' ').next().unwrap(); let name = cmd.trim().split(' ').next().unwrap();
if let Ok(file) = ROOT_INODE.lookup(name) { if let Ok(file) = ROOT_INODE.lookup(name) {
let data = file.read_as_vec().unwrap(); let data = file.read_as_vec().unwrap();
let pid = processor().manager().add(Thread::new_user(data.as_slice(), cmd.split(' ')), thread::current().id()); let pid = processor().manager().add(Thread::new_user(data.as_slice(), cmd.split(' ')));
unsafe { thread::JoinHandle::<()>::_of(pid) }.join().unwrap(); //unsafe { thread::JoinHandle::<()>::_of(pid) }.join().unwrap();
} else { } else {
println!("Program not exist"); println!("Program not exist");
} }

@ -14,7 +14,7 @@ impl Condvar {
} }
pub fn _wait(&self) { pub fn _wait(&self) {
self.wait_queue.lock().push_back(Arc::new(thread::current())); self.add_to_wait_queue();
thread::park(); thread::park();
} }
@ -26,6 +26,10 @@ impl Condvar {
thread::park(); thread::park();
} }
pub fn add_to_wait_queue(&self) {
self.wait_queue.lock().push_back(Arc::new(thread::current()));
}
pub fn wait<'a, T, S>(&self, guard: MutexGuard<'a, T, S>) -> MutexGuard<'a, T, S> pub fn wait<'a, T, S>(&self, guard: MutexGuard<'a, T, S>) -> MutexGuard<'a, T, S>
where S: MutexSupport where S: MutexSupport
{ {

@ -29,9 +29,12 @@ mod misc;
/// System call dispatcher /// System call dispatcher
pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
let pid = cpu::id(); let cid = cpu::id();
let pid = {
process().pid.clone()
};
let tid = processor().tid(); let tid = processor().tid();
debug!("{}:{} syscall id {} begin", pid, tid, id); debug!("{}:{}:{} syscall id {} begin", cid, pid, tid, id);
let ret = match id { let ret = match id {
// file // file
000 => sys_read(args[0], args[1] as *mut u8, args[2]), 000 => sys_read(args[0], args[1] as *mut u8, args[2]),
@ -77,7 +80,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
// use fork for vfork // use fork for vfork
058 => sys_fork(tf), 058 => sys_fork(tf),
059 => sys_exec(args[0] as *const u8, args[1] as *const *const u8, args[2] as *const *const u8, tf), 059 => sys_exec(args[0] as *const u8, args[1] as *const *const u8, args[2] as *const *const u8, tf),
060 => sys_exit(args[0] as isize), 060 => sys_exit(args[0] as usize),
061 => sys_wait4(args[0] as isize, args[1] as *mut i32), // TODO: wait4 061 => sys_wait4(args[0] as isize, args[1] as *mut i32), // TODO: wait4
062 => sys_kill(args[0]), 062 => sys_kill(args[0]),
063 => sys_uname(args[0] as *mut u8), 063 => sys_uname(args[0] as *mut u8),
@ -109,6 +112,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
204 => sys_sched_getaffinity(args[0], args[1], args[2] as *mut u32), 204 => sys_sched_getaffinity(args[0], args[1], args[2] as *mut u32),
217 => sys_getdents64(args[0], args[1] as *mut LinuxDirent64, args[2]), 217 => sys_getdents64(args[0], args[1] as *mut LinuxDirent64, args[2]),
228 => sys_clock_gettime(args[0], args[1] as *mut TimeSpec), 228 => sys_clock_gettime(args[0], args[1] as *mut TimeSpec),
231 => sys_exit_group(args[0]),
288 => sys_accept(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), // use accept for accept4 288 => sys_accept(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), // use accept for accept4
// 293 => sys_pipe(), // 293 => sys_pipe(),
@ -185,10 +189,6 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
warn!("sys_set_tid_address is unimplemented"); warn!("sys_set_tid_address is unimplemented");
Ok(thread::current().id()) Ok(thread::current().id())
} }
231 => {
warn!("sys_exit_group is unimplemented");
sys_exit(args[0] as isize);
}
280 => { 280 => {
warn!("sys_utimensat is unimplemented"); warn!("sys_utimensat is unimplemented");
Ok(0) Ok(0)
@ -206,7 +206,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
crate::trap::error(tf); crate::trap::error(tf);
} }
}; };
debug!("{}:{} syscall id {} ret with {:x?}", pid, tid, id, ret); debug!("{}:{}:{} syscall id {} ret with {:x?}", cid, pid, tid, id, ret);
match ret { match ret {
Ok(code) => code as isize, Ok(code) => code as isize,
Err(err) => -(err as isize), Err(err) => -(err as isize),
@ -313,6 +313,14 @@ impl fmt::Display for SysError {
ENOLCK => "No record locks available", ENOLCK => "No record locks available",
ENOSYS => "Function not implemented", ENOSYS => "Function not implemented",
ENOTEMPTY => "Directory not empty", ENOTEMPTY => "Directory not empty",
ENOTSOCK => "Socket operation on non-socket",
ENOPROTOOPT => "Protocol not available",
EPFNOSUPPORT => "Protocol family not supported",
EAFNOSUPPORT => "Address family not supported by protocol",
ENOBUFS => "No buffer space available",
EISCONN => "Transport endpoint is already connected",
ENOTCONN => "Transport endpoint is not connected",
ECONNREFUSED => "Connection refused",
_ => "Unknown error", _ => "Unknown error",
}, },
) )

@ -1,11 +1,13 @@
//! Syscalls for process //! Syscalls for process
use super::*; use super::*;
use crate::process::{PROCESSES, CHILD_PROCESSES};
use crate::sync::Condvar;
/// Fork the current process. Return the child's PID. /// Fork the current process. Return the child's PID.
pub fn sys_fork(tf: &TrapFrame) -> SysResult { pub fn sys_fork(tf: &TrapFrame) -> SysResult {
let new_thread = current_thread().fork(tf); let new_thread = current_thread().fork(tf);
let pid = processor().manager().add(new_thread, thread::current().id()); let pid = processor().manager().add(new_thread);
info!("fork: {} -> {}", thread::current().id(), pid); info!("fork: {} -> {}", thread::current().id(), pid);
Ok(pid) Ok(pid)
} }
@ -29,7 +31,7 @@ pub fn sys_clone(flags: usize, newsp: usize, parent_tid: *mut u32, child_tid: *m
} }
let new_thread = current_thread().clone(tf, newsp, newtls, child_tid as usize); let new_thread = current_thread().clone(tf, newsp, newtls, child_tid as usize);
// FIXME: parent pid // FIXME: parent pid
let tid = processor().manager().add(new_thread, thread::current().id()); let tid = processor().manager().add(new_thread);
info!("clone: {} -> {}", thread::current().id(), tid); info!("clone: {} -> {}", thread::current().id(), tid);
unsafe { unsafe {
parent_tid.write(tid as u32); parent_tid.write(tid as u32);
@ -42,6 +44,7 @@ pub fn sys_clone(flags: usize, newsp: usize, parent_tid: *mut u32, child_tid: *m
/// 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.
pub fn sys_wait4(pid: isize, wstatus: *mut i32) -> SysResult { pub fn sys_wait4(pid: isize, wstatus: *mut i32) -> SysResult {
info!("wait4: pid: {}, code: {:?}", pid, wstatus); info!("wait4: pid: {}, code: {:?}", pid, wstatus);
let cur_pid = process().pid.get();
if !wstatus.is_null() { if !wstatus.is_null() {
process().memory_set.check_mut_ptr(wstatus)?; process().memory_set.check_mut_ptr(wstatus)?;
} }
@ -57,13 +60,13 @@ pub fn sys_wait4(pid: isize, wstatus: *mut i32) -> SysResult {
}; };
loop { loop {
use alloc::vec; use alloc::vec;
let all_child: Vec<_> = CHILD_PROCESSES.read().get(&cur_pid).unwrap().clone();
let wait_procs = match target { let wait_procs = match target {
WaitFor::AnyChild => processor().manager().get_children(thread::current().id()), WaitFor::AnyChild => all_child,
WaitFor::Pid(pid) => { WaitFor::Pid(pid) => {
// check if pid is a child // check if pid is a child
if processor().manager().get_children(thread::current().id()).iter() if let Some(proc) = all_child.iter().find(|p| p.lock().pid.get() == pid) {
.find(|&&p| p == pid).is_some() { vec![proc.clone()]
vec![pid]
} else { } else {
vec![] vec![]
} }
@ -73,26 +76,25 @@ pub fn sys_wait4(pid: isize, wstatus: *mut i32) -> SysResult {
return Err(SysError::ECHILD); return Err(SysError::ECHILD);
} }
for pid in wait_procs { for proc_lock in wait_procs.iter() {
match processor().manager().get_status(pid) { let proc = proc_lock.lock();
Some(Status::Exited(exit_code)) => { if let Some(exit_code) = proc.exit_code {
if !wstatus.is_null() { // recycle process
unsafe { wstatus.write(exit_code as i32); } let pid = proc.pid.get();
} drop(proc);
processor().manager().remove(pid);
info!("wait: {} -> {}", thread::current().id(), pid); let mut child_processes = CHILD_PROCESSES.write();
child_processes.get_mut(&cur_pid).unwrap().retain(|p| p.lock().pid.get() != pid);
child_processes.remove(&pid);
return Ok(pid); return Ok(pid);
} }
None => return Err(SysError::ECHILD),
_ => {}
}
} }
info!("wait: {} -> {:?}, sleep", thread::current().id(), target); info!("wait: {} -> {:?}, sleep", thread::current().id(), target);
match target {
WaitFor::AnyChild => processor().manager().wait_child(thread::current().id()), for proc in wait_procs.iter() {
WaitFor::Pid(pid) => processor().manager().wait(thread::current().id(), pid), proc.lock().exit_cond.add_to_wait_queue();
} }
processor().yield_now(); thread::park();
} }
} }
@ -163,7 +165,7 @@ pub fn sys_kill(pid: usize) -> SysResult {
/// Get the current process id /// Get the current process id
pub fn sys_getpid() -> SysResult { pub fn sys_getpid() -> SysResult {
info!("getpid"); info!("getpid");
Ok(thread::current().id()) Ok(process().pid.get())
} }
/// Get the current thread id /// Get the current thread id
@ -175,15 +177,21 @@ pub fn sys_gettid() -> SysResult {
/// Get the parent process id /// Get the parent process id
pub fn sys_getppid() -> SysResult { pub fn sys_getppid() -> SysResult {
let pid = thread::current().id(); Ok(process().ppid.get())
let ppid = processor().manager().get_parent(pid);
Ok(ppid)
} }
/// Exit the current thread /// Exit the current thread
pub fn sys_exit(exit_code: isize) -> ! { pub fn sys_exit(exit_code: usize) -> ! {
let pid = thread::current().id(); let tid = thread::current().id();
info!("exit: {}, code: {}", pid, exit_code); info!("exit: {}, code: {}", tid, exit_code);
let mut proc = process();
proc.threads.retain(|&id| id != tid);
if proc.threads.len() == 0 {
// last thread
proc.exit_code = Some(exit_code);
proc.exit_cond.notify_all();
}
drop(proc);
// perform futex wake 1 // perform futex wake 1
// ref: http://man7.org/linux/man-pages/man2/set_tid_address.2.html // ref: http://man7.org/linux/man-pages/man2/set_tid_address.2.html
@ -196,7 +204,24 @@ pub fn sys_exit(exit_code: isize) -> ! {
queue.notify_one(); queue.notify_one();
} }
processor().manager().exit(pid, exit_code as usize); processor().manager().exit(tid, exit_code as usize);
processor().yield_now();
unreachable!();
}
/// Exit the current thread group (i.e. progress)
pub fn sys_exit_group(exit_code: usize) -> ! {
let mut proc = process();
info!("exit_group: {}, code: {}", proc.pid, exit_code);
// quit all threads
for tid in proc.threads.iter() {
processor().manager().exit(*tid, exit_code);
}
proc.exit_code = Some(exit_code);
proc.exit_cond.notify_all();
drop(proc);
processor().yield_now(); processor().yield_now();
unreachable!(); unreachable!();
} }

Loading…
Cancel
Save