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))
     }