1
0
mirror of https://github.com/rcore-os/rCore.git synced 2025-01-19 01:07:05 +04:00

Implement tid/pid/ppid separation

This commit is contained in:
Jiajie Chen 2019-03-10 15:23:15 +08:00
parent 82457be2ec
commit 8cb11b7aa8
13 changed files with 266 additions and 266 deletions

View File

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

View File

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

View File

@ -11,19 +11,19 @@ mod rr;
mod stride;
mod work_stealing;
type Pid = usize;
type Tid = usize;
/// The scheduler for a ThreadPool
pub trait Scheduler: 'static {
/// 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.
fn pop(&self, cpu_id: usize) -> Option<Pid>;
fn pop(&self, cpu_id: usize) -> Option<Tid>;
/// Got a tick from CPU.
/// Return true if need reschedule.
fn tick(&self, current_pid: Pid) -> bool;
fn tick(&self, current_tid: Tid) -> bool;
/// 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) {

View File

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

View File

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

View File

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

View File

@ -92,17 +92,16 @@ pub fn spawn<F, T>(f: F) -> JoinHandle<T>
// 在Processor中创建新的线程
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()`的实现
// 了解是如何获取f返回值的
return JoinHandle {
thread: Thread { pid },
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() {
trace!("yield:");
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> {
thread: Thread,
mark: PhantomData<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.
pub fn join(self) -> Result<T, ()> {
loop {
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();
}
unimplemented!();
}
/// 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");
// }
//}
}

View File

@ -1,6 +1,6 @@
use alloc::boxed::Box;
use alloc::vec::Vec;
use spin::Mutex;
use spin::{Mutex, MutexGuard};
use log::*;
use crate::scheduler::Scheduler;
use crate::timer::Timer;
@ -9,8 +9,6 @@ struct Thread {
status: Status,
status_after_stop: Status,
context: Option<Box<Context>>,
parent: Tid,
children: Vec<Tid>,
}
pub type Tid = usize;
@ -21,7 +19,6 @@ pub enum Status {
Ready,
Running(usize),
Sleeping,
Waiting(Tid),
/// aka ZOMBIE. Its context was dropped.
Exited(ExitCode),
}
@ -32,7 +29,11 @@ enum Event {
}
pub trait Context {
/// Switch to target 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 {
@ -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() {
if proc.lock().is_none() {
return i;
let thread = proc.lock();
if thread.is_none() {
return (i, thread);
}
}
panic!("Process number exceeded");
}
/// Add a new process
pub fn add(&self, context: Box<Context>, parent: Tid) -> Tid {
let tid = self.alloc_tid();
*(&self.threads[tid]).lock() = Some(Thread {
/// Add a new thread
/// Calls action with tid and thread context
pub fn add(&self, mut context: Box<Context>) -> Tid {
let (tid, mut thread) = self.alloc_tid();
context.set_tid(tid);
*thread = Some(Thread {
status: Status::Ready,
status_after_stop: Status::Ready,
context: Some(context),
parent,
children: Vec::new(),
});
self.scheduler.push(tid);
self.threads[parent].lock().as_mut().expect("invalid parent proc")
.children.push(tid);
tid
}
@ -162,7 +162,6 @@ impl ThreadPool {
}
/// 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");
@ -170,13 +169,6 @@ impl ThreadPool {
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;
}
@ -194,32 +186,12 @@ impl ThreadPool {
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) {
// 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;
}

View File

@ -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 log::*;
use rcore_fs::vfs::INode;
use spin::Mutex;
use spin::{Mutex, RwLock};
use xmas_elf::{ElfFile, header, program::{Flags, Type}};
use smoltcp::socket::SocketHandle;
use smoltcp::wire::IpEndpoint;
use rcore_memory::PAGE_SIZE;
use rcore_thread::Tid;
use crate::arch::interrupt::{Context, TrapFrame};
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 memory_set: MemorySet,
pub files: BTreeMap<usize, FileLike>,
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>>,
}
/// 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`
impl rcore_thread::Context for Thread {
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);
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 {
@ -97,6 +171,11 @@ impl Thread {
files: BTreeMap::default(),
cwd: String::from("/"),
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(),
cwd: String::from("/"),
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,
cwd: String::from("/"),
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 files = self.proc.lock().files.clone();
let cwd = self.proc.lock().cwd.clone();
let ppid = self.proc.lock().pid.clone();
debug!("fork: finish clone MemorySet");
// MMU: copy data to the new space
@ -244,6 +334,11 @@ impl Thread {
files,
cwd,
futexes: BTreeMap::default(),
pid: Pid::uninitialized(),
ppid,
exit_cond: Condvar::new(),
threads: Vec::new(),
exit_code: None
})),
})
}

View File

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

View File

@ -14,7 +14,7 @@ impl Condvar {
}
pub fn _wait(&self) {
self.wait_queue.lock().push_back(Arc::new(thread::current()));
self.add_to_wait_queue();
thread::park();
}
@ -26,6 +26,10 @@ impl Condvar {
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>
where S: MutexSupport
{

View File

@ -29,9 +29,12 @@ mod misc;
/// System call dispatcher
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();
debug!("{}:{} syscall id {} begin", pid, tid, id);
debug!("{}:{}:{} syscall id {} begin", cid, pid, tid, id);
let ret = match id {
// file
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
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),
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
062 => sys_kill(args[0]),
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),
217 => sys_getdents64(args[0], args[1] as *mut LinuxDirent64, args[2]),
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
// 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");
Ok(thread::current().id())
}
231 => {
warn!("sys_exit_group is unimplemented");
sys_exit(args[0] as isize);
}
280 => {
warn!("sys_utimensat is unimplemented");
Ok(0)
@ -206,7 +206,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
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 {
Ok(code) => code as isize,
Err(err) => -(err as isize),
@ -313,6 +313,14 @@ impl fmt::Display for SysError {
ENOLCK => "No record locks available",
ENOSYS => "Function not implemented",
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",
},
)

View File

@ -1,11 +1,13 @@
//! Syscalls for process
use super::*;
use crate::process::{PROCESSES, CHILD_PROCESSES};
use crate::sync::Condvar;
/// Fork the current process. Return the child's PID.
pub fn sys_fork(tf: &TrapFrame) -> SysResult {
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);
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);
// 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);
unsafe {
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.
pub fn sys_wait4(pid: isize, wstatus: *mut i32) -> SysResult {
info!("wait4: pid: {}, code: {:?}", pid, wstatus);
let cur_pid = process().pid.get();
if !wstatus.is_null() {
process().memory_set.check_mut_ptr(wstatus)?;
}
@ -57,13 +60,13 @@ pub fn sys_wait4(pid: isize, wstatus: *mut i32) -> SysResult {
};
loop {
use alloc::vec;
let all_child: Vec<_> = CHILD_PROCESSES.read().get(&cur_pid).unwrap().clone();
let wait_procs = match target {
WaitFor::AnyChild => processor().manager().get_children(thread::current().id()),
WaitFor::AnyChild => all_child,
WaitFor::Pid(pid) => {
// check if pid is a child
if processor().manager().get_children(thread::current().id()).iter()
.find(|&&p| p == pid).is_some() {
vec![pid]
if let Some(proc) = all_child.iter().find(|p| p.lock().pid.get() == pid) {
vec![proc.clone()]
} else {
vec![]
}
@ -73,26 +76,25 @@ pub fn sys_wait4(pid: isize, wstatus: *mut i32) -> SysResult {
return Err(SysError::ECHILD);
}
for pid in wait_procs {
match processor().manager().get_status(pid) {
Some(Status::Exited(exit_code)) => {
if !wstatus.is_null() {
unsafe { wstatus.write(exit_code as i32); }
}
processor().manager().remove(pid);
info!("wait: {} -> {}", thread::current().id(), pid);
return Ok(pid);
}
None => return Err(SysError::ECHILD),
_ => {}
for proc_lock in wait_procs.iter() {
let proc = proc_lock.lock();
if let Some(exit_code) = proc.exit_code {
// recycle process
let pid = proc.pid.get();
drop(proc);
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);
}
}
info!("wait: {} -> {:?}, sleep", thread::current().id(), target);
match target {
WaitFor::AnyChild => processor().manager().wait_child(thread::current().id()),
WaitFor::Pid(pid) => processor().manager().wait(thread::current().id(), pid),
for proc in wait_procs.iter() {
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
pub fn sys_getpid() -> SysResult {
info!("getpid");
Ok(thread::current().id())
Ok(process().pid.get())
}
/// Get the current thread id
@ -175,15 +177,21 @@ pub fn sys_gettid() -> SysResult {
/// Get the parent process id
pub fn sys_getppid() -> SysResult {
let pid = thread::current().id();
let ppid = processor().manager().get_parent(pid);
Ok(ppid)
Ok(process().ppid.get())
}
/// Exit the current thread
pub fn sys_exit(exit_code: isize) -> ! {
let pid = thread::current().id();
info!("exit: {}, code: {}", pid, exit_code);
pub fn sys_exit(exit_code: usize) -> ! {
let tid = thread::current().id();
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
// 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();
}
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();
unreachable!();
}