diff --git a/scheme/pipe.rs b/scheme/pipe.rs index a17be8f37714678e55986e7c30f0ce603adf869c..fcf8a083de106298079d661296344299c87067b6 100644 --- a/scheme/pipe.rs +++ b/scheme/pipe.rs @@ -1,9 +1,9 @@ use alloc::arc::{Arc, Weak}; -use collections::BTreeMap; +use collections::{BTreeMap, VecDeque}; use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; -use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard}; +use spin::{Mutex, Once, RwLock, RwLockReadGuard, RwLockWriteGuard}; -use sync::WaitQueue; +use sync::WaitCondition; use syscall::error::{Error, Result, EBADF, EPIPE}; use syscall::scheme::Scheme; @@ -30,8 +30,8 @@ fn pipes_mut() -> RwLockWriteGuard<'static, (BTreeMap<usize, PipeRead>, BTreeMap pub fn pipe(_flags: usize) -> (usize, usize) { let mut pipes = pipes_mut(); let read_id = PIPE_NEXT_ID.fetch_add(1, Ordering::SeqCst); - let read = PipeRead::new(); let write_id = PIPE_NEXT_ID.fetch_add(1, Ordering::SeqCst); + let read = PipeRead::new(); let write = PipeWrite::new(&read); pipes.0.insert(read_id, read); pipes.1.insert(write_id, write); @@ -104,21 +104,43 @@ impl Scheme for PipeScheme { /// Read side of a pipe #[derive(Clone)] pub struct PipeRead { - vec: Arc<WaitQueue<u8>> + condition: Arc<WaitCondition>, + vec: Arc<Mutex<VecDeque<u8>>> } impl PipeRead { pub fn new() -> Self { PipeRead { - vec: Arc::new(WaitQueue::new()) + condition: Arc::new(WaitCondition::new()), + vec: Arc::new(Mutex::new(VecDeque::new())), } } fn read(&self, buf: &mut [u8]) -> Result<usize> { - if buf.is_empty() || (Arc::weak_count(&self.vec) == 0 && self.vec.is_empty()) { - Ok(0) - } else { - Ok(self.vec.receive_into(buf)) + loop { + { + let mut vec = self.vec.lock(); + + let mut i = 0; + while i < buf.len() { + if let Some(b) = vec.pop_front() { + buf[i] = b; + i += 1; + } else { + break; + } + } + + if i > 0 { + return Ok(i); + } + } + + if Arc::weak_count(&self.vec) == 0 { + return Ok(0); + } else { + self.condition.wait(); + } } } } @@ -126,24 +148,37 @@ impl PipeRead { /// Read side of a pipe #[derive(Clone)] pub struct PipeWrite { - vec: Weak<WaitQueue<u8>>, + condition: Arc<WaitCondition>, + vec: Weak<Mutex<VecDeque<u8>>> } impl PipeWrite { pub fn new(read: &PipeRead) -> Self { PipeWrite { + condition: read.condition.clone(), vec: Arc::downgrade(&read.vec), } } fn write(&self, buf: &[u8]) -> Result<usize> { - match self.vec.upgrade() { - Some(vec) => { - vec.send_from(buf); + if let Some(vec_lock) = self.vec.upgrade() { + let mut vec = vec_lock.lock(); + + for &b in buf.iter() { + vec.push_back(b); + } + + self.condition.notify(); - Ok(buf.len()) - }, - None => Err(Error::new(EPIPE)) + Ok(buf.len()) + } else { + Err(Error::new(EPIPE)) } } } + +impl Drop for PipeWrite { + fn drop(&mut self) { + self.condition.notify(); + } +} diff --git a/syscall/process.rs b/syscall/process.rs index 721211cb5b68de12cefbcd47fce9fa287932d47b..5763c891568c1f9828d0e7e5928663af902b0b9e 100644 --- a/syscall/process.rs +++ b/syscall/process.rs @@ -4,7 +4,7 @@ use alloc::boxed::Box; use collections::{BTreeMap, Vec}; use core::{mem, str}; use core::ops::DerefMut; -use spin::{Mutex, RwLock}; +use spin::Mutex; use arch; use arch::externs::memcpy; @@ -596,26 +596,56 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> { unsafe { usermode(entry, sp); } } -fn terminate(context_lock: Arc<RwLock<context::Context>>, status: usize) { - let mut close_files = Vec::new(); +pub fn exit(status: usize) -> ! { { + let context_lock = { + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::new(ESRCH)).expect("exit failed to find context"); + context_lock.clone() + }; + + let mut close_files = Vec::new(); + { + let mut context = context_lock.write(); + if Arc::strong_count(&context.files) == 1 { + mem::swap(context.files.lock().deref_mut(), &mut close_files); + } + context.files = Arc::new(Mutex::new(Vec::new())); + } + + /// Files must be closed while context is valid so that messages can be passed + for (fd, file_option) in close_files.drain(..).enumerate() { + if let Some(file) = file_option { + context::event::unregister(fd, file.scheme, file.number); + + let scheme_option = { + let schemes = scheme::schemes(); + schemes.get(file.scheme).map(|scheme| scheme.clone()) + }; + if let Some(scheme) = scheme_option { + let _ = scheme.close(file.number); + } + } + } + let (vfork, ppid) = { let mut context = context_lock.write(); + context.image.clear(); drop(context.heap.take()); drop(context.stack.take()); context.grants = Arc::new(Mutex::new(Vec::new())); - if Arc::strong_count(&context.files) == 1 { - mem::swap(context.files.lock().deref_mut(), &mut close_files); - } - context.files = Arc::new(Mutex::new(Vec::new())); - context.status = context::Status::Exited(status); let vfork = context.vfork; context.vfork = false; + + context.status = context::Status::Exited(status); + context.waitpid.notify(); + (vfork, context.ppid) }; + if vfork { let contexts = context::contexts(); if let Some(parent_lock) = contexts.get(ppid) { @@ -629,31 +659,6 @@ fn terminate(context_lock: Arc<RwLock<context::Context>>, status: usize) { } } - for (fd, file_option) in close_files.drain(..).enumerate() { - if let Some(file) = file_option { - context::event::unregister(fd, file.scheme, file.number); - - let scheme_option = { - let schemes = scheme::schemes(); - schemes.get(file.scheme).map(|scheme| scheme.clone()) - }; - if let Some(scheme) = scheme_option { - let _ = scheme.close(file.number); - } - } - } -} - -pub fn exit(status: usize) -> ! { - { - let context_lock = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH)).expect("exit failed to find context"); - context_lock.clone() - }; - terminate(context_lock, status); - } - unsafe { context::switch(); } unreachable!(); @@ -702,45 +707,45 @@ pub fn iopl(_level: usize) -> Result<usize> { pub fn kill(pid: usize, sig: usize) -> Result<usize> { use syscall::flag::*; - let context_lock = { + let _context_lock = { let contexts = context::contexts(); let context_lock = contexts.get(pid).ok_or(Error::new(ESRCH))?; context_lock.clone() }; - let term = |context_lock| { - terminate(context_lock, !sig); + let term = || { + println!("Terminate {}", pid); }; - let core = |context_lock| { - terminate(context_lock, !sig); + let core = || { + println!("Core {}", pid); }; let stop = || { - + println!("Stop {}", pid); }; let cont = || { - + println!("Continue {}", pid); }; match sig { 0 => (), - SIGHUP => term(context_lock), - SIGINT => term(context_lock), - SIGQUIT => core(context_lock), - SIGILL => core(context_lock), - SIGTRAP => core(context_lock), - SIGABRT => core(context_lock), - SIGBUS => core(context_lock), - SIGFPE => core(context_lock), - SIGKILL => term(context_lock), - SIGUSR1 => term(context_lock), - SIGSEGV => core(context_lock), - SIGPIPE => term(context_lock), - SIGALRM => term(context_lock), - SIGTERM => term(context_lock), - SIGSTKFLT => term(context_lock), + SIGHUP => term(), + SIGINT => term(), + SIGQUIT => core(), + SIGILL => core(), + SIGTRAP => core(), + SIGABRT => core(), + SIGBUS => core(), + SIGFPE => core(), + SIGKILL => term(), + SIGUSR1 => term(), + SIGSEGV => core(), + SIGPIPE => term(), + SIGALRM => term(), + SIGTERM => term(), + SIGSTKFLT => term(), SIGCHLD => (), SIGCONT => cont(), SIGSTOP => stop(), @@ -748,14 +753,14 @@ pub fn kill(pid: usize, sig: usize) -> Result<usize> { SIGTTIN => stop(), SIGTTOU => stop(), SIGURG => (), - SIGXCPU => core(context_lock), - SIGXFSZ => core(context_lock), - SIGVTALRM => term(context_lock), - SIGPROF => term(context_lock), + SIGXCPU => core(), + SIGXFSZ => core(), + SIGVTALRM => term(), + SIGPROF => term(), SIGWINCH => (), - SIGIO => term(context_lock), - SIGPWR => term(context_lock), - SIGSYS => core(context_lock), + SIGIO => term(), + SIGPWR => term(), + SIGSYS => core(), _ => return Err(Error::new(EINVAL)) }