diff --git a/Cargo.lock b/Cargo.lock
index db7f9e16953b2ff6607fa1305c97fe0827466f6c..48faff9c2ab4cb8e2c45ada61d76c6f2dd0eec30 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -55,7 +55,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "bitflags"
-version = "1.0.4"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -175,7 +175,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 name = "kernel"
 version = "0.1.54"
 dependencies = [
- "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "clippy 0.0.209 (registry+https://github.com/rust-lang/crates.io-index)",
  "goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)",
  "linked_list_allocator 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -268,7 +268,7 @@ name = "raw-cpuid"
 version = "4.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -495,7 +495,7 @@ dependencies = [
 "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
 "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
 "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
-"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
+"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
 "checksum cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1efca0b863ca03ed4c109fb1c55e0bc4bbeb221d3e103d86251046b06a526bd0"
 "checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83"
 "checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
diff --git a/src/arch/x86_64/interrupt/exception.rs b/src/arch/x86_64/interrupt/exception.rs
index c98e579433a63195c83e16d152fbfb4744d7beb5..0aba0049be056c82aa4caa23f28bda6302fcfaf1 100644
--- a/src/arch/x86_64/interrupt/exception.rs
+++ b/src/arch/x86_64/interrupt/exception.rs
@@ -26,7 +26,7 @@ interrupt_stack!(debug, stack, {
     let had_singlestep = stack.iret.rflags & (1 << 8) == 1 << 8;
     stack.set_singlestep(false);
 
-    if ptrace::breakpoint_callback(syscall::PTRACE_SINGLESTEP).is_some() {
+    if ptrace::breakpoint_callback(PTRACE_STOP_SINGLESTEP, None).is_some() {
         handled = true;
     } else {
         // There was no breakpoint, restore original value
diff --git a/src/arch/x86_64/interrupt/syscall.rs b/src/arch/x86_64/interrupt/syscall.rs
index 6b9dfe615db217d6f51180a3dc9f23d84f1998fd..b01c1a5bb0bb92d37abf704338507cc98ff1b40a 100644
--- a/src/arch/x86_64/interrupt/syscall.rs
+++ b/src/arch/x86_64/interrupt/syscall.rs
@@ -1,5 +1,6 @@
 use crate::arch::macros::InterruptStack;
 use crate::arch::{gdt, pti};
+use crate::syscall::flag::{PTRACE_STOP_PRE_SYSCALL, PTRACE_STOP_POST_SYSCALL, PTRACE_FLAG_SYSEMU};
 use crate::{ptrace, syscall};
 use x86::shared::msr;
 
@@ -21,18 +22,14 @@ macro_rules! with_interrupt_stack {
         unsafe fn $wrapped(stack: *mut InterruptStack) {
             let _guard = ptrace::set_process_regs(stack);
 
-            let is_sysemu = ptrace::breakpoint_callback(syscall::flag::PTRACE_SYSCALL)
-                .map(|fl| fl & syscall::flag::PTRACE_SYSEMU == syscall::flag::PTRACE_SYSEMU);
-            if !is_sysemu.unwrap_or(false) {
+            ptrace::breakpoint_callback(PTRACE_STOP_PRE_SYSCALL, None);
+            let not_sysemu = ptrace::next_breakpoint().map(|b| b & PTRACE_FLAG_SYSEMU != PTRACE_FLAG_SYSEMU);
+            if not_sysemu.unwrap_or(true) {
                 // If not on a sysemu breakpoint
                 let $stack = &mut *stack;
                 $stack.scratch.rax = $code;
 
-                if is_sysemu.is_some() {
-                    // Only callback if there was a pre-syscall
-                    // callback too.
-                    ptrace::breakpoint_callback(::syscall::PTRACE_SYSCALL);
-                }
+                ptrace::breakpoint_callback(PTRACE_STOP_POST_SYSCALL, None);
             }
         }
     }
diff --git a/src/context/signal.rs b/src/context/signal.rs
index d5d2ff18cb3e48918ca16cb2532148fa6856b648..d89d31d4fe2c04fe56ff974e37071b2b15262d3a 100644
--- a/src/context/signal.rs
+++ b/src/context/signal.rs
@@ -1,11 +1,12 @@
 use alloc::sync::Arc;
 use core::mem;
+use syscall::data::PtraceEvent;
+use syscall::flag::{PTRACE_STOP_SIGNAL, SIG_DFL, SIG_IGN, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU};
+use syscall::ptrace_event;
 
 use crate::context::{contexts, switch, Status, WaitpidKey};
 use crate::start::usermode;
-use crate::{ptrace, syscall};
-use crate::syscall::flag::{PTRACE_EVENT_SIGNAL, PTRACE_SIGNAL, SIG_DFL, SIG_IGN, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU};
-use crate::syscall::data::{PtraceEvent, PtraceEventData};
+use crate::ptrace;
 
 pub fn is_user_handled(handler: Option<extern "C" fn(usize)>) -> bool {
     let handler = handler.map(|ptr| ptr as usize).unwrap_or(0);
@@ -21,12 +22,10 @@ pub extern "C" fn signal_handler(sig: usize) {
         actions[sig]
     };
 
-    ptrace::send_event(PtraceEvent {
-        tag: PTRACE_EVENT_SIGNAL,
-        data: PtraceEventData { signal: sig }
-    });
-
     let handler = action.sa_handler.map(|ptr| ptr as usize).unwrap_or(0);
+
+    ptrace::breakpoint_callback(PTRACE_STOP_SIGNAL, Some(ptrace_event!(PTRACE_STOP_SIGNAL, sig, handler)));
+
     if handler == SIG_DFL {
         match sig {
             SIGCHLD => {
@@ -92,7 +91,7 @@ pub extern "C" fn signal_handler(sig: usize) {
             },
             _ => {
                 // println!("Exit {}", sig);
-                syscall::exit(sig);
+                crate::syscall::exit(sig);
             }
         }
     } else if handler == SIG_IGN {
@@ -100,8 +99,6 @@ pub extern "C" fn signal_handler(sig: usize) {
     } else {
         // println!("Call {:X}", handler);
 
-        ptrace::breakpoint_callback(PTRACE_SIGNAL);
-
         unsafe {
             let mut sp = crate::USER_SIGSTACK_OFFSET + crate::USER_SIGSTACK_SIZE - 256;
 
@@ -114,5 +111,5 @@ pub extern "C" fn signal_handler(sig: usize) {
         }
     }
 
-    syscall::sigreturn().unwrap();
+    crate::syscall::sigreturn().unwrap();
 }
diff --git a/src/ptrace.rs b/src/ptrace.rs
index 3f3390f492b7a6ee1b4bdb32737a3723f35c44dc..528f7bb14fa66757cc20ec8087639537c08b6fbc 100644
--- a/src/ptrace.rs
+++ b/src/ptrace.rs
@@ -1,3 +1,7 @@
+//! The backend of the "proc:" scheme. Most internal breakpoint
+//! handling should go here, unless they closely depend on the design
+//! of the scheme.
+
 use crate::{
     arch::{
         macros::InterruptStack,
@@ -33,7 +37,8 @@ use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
 use syscall::{
     data::PtraceEvent,
     error::*,
-    flag::*
+    flag::*,
+    ptrace_event
 };
 
 //  ____                _
@@ -44,10 +49,11 @@ use syscall::{
 
 #[derive(Debug)]
 struct Session {
-    file_id: usize,
-    events: VecDeque<PtraceEvent>,
     breakpoint: Option<Breakpoint>,
-    tracer: Arc<WaitCondition>
+    events: VecDeque<PtraceEvent>,
+    file_id: usize,
+    tracee: Arc<WaitCondition>,
+    tracer: Arc<WaitCondition>,
 }
 
 type SessionMap = BTreeMap<ContextId, Session>;
@@ -73,10 +79,11 @@ pub fn try_new_session(pid: ContextId, file_id: usize) -> bool {
         Entry::Occupied(_) => false,
         Entry::Vacant(vacant) => {
             vacant.insert(Session {
-                file_id,
-                events: VecDeque::new(),
                 breakpoint: None,
-                tracer: Arc::new(WaitCondition::new())
+                events: VecDeque::new(),
+                file_id,
+                tracee: Arc::new(WaitCondition::new()),
+                tracer: Arc::new(WaitCondition::new()),
             });
             true
         }
@@ -107,9 +114,7 @@ pub fn session_fevent_flags(pid: ContextId) -> Option<usize> {
 pub fn close_session(pid: ContextId) {
     if let Some(session) = sessions_mut().remove(&pid) {
         session.tracer.notify();
-        if let Some(breakpoint) = session.breakpoint {
-            breakpoint.tracee.notify();
-        }
+        session.tracee.notify();
     }
 }
 
@@ -164,39 +169,31 @@ pub fn recv_events(pid: ContextId, out: &mut [PtraceEvent]) -> Option<usize> {
 
 #[derive(Debug)]
 struct Breakpoint {
-    tracee: Arc<WaitCondition>,
     reached: bool,
-    flags: u8
+    flags: u64
 }
 
-fn inner_cont(pid: ContextId) -> Option<Breakpoint> {
-    // Remove the breakpoint to both save space and also make sure any
-    // yet unreached but obsolete breakpoints don't stop the program.
+/// Continue the process with the specified ID
+pub fn cont(pid: ContextId) {
     let mut sessions = sessions_mut();
-    let session = sessions.get_mut(&pid)?;
-    let breakpoint = session.breakpoint.take()?;
-
-    breakpoint.tracee.notify();
+    let session = match sessions.get_mut(&pid) {
+        Some(session) => session,
+        None => return
+    };
 
-    Some(breakpoint)
-}
+    // Remove the breakpoint to make sure any yet unreached but
+    // obsolete breakpoints don't stop the program.
+    session.breakpoint = None;
 
-/// Continue the process with the specified ID
-pub fn cont(pid: ContextId) {
-    inner_cont(pid);
+    session.tracee.notify();
 }
 
 /// Create a new breakpoint for the specified tracee, optionally with
 /// a sysemu flag. Panics if the session is invalid.
-pub fn set_breakpoint(pid: ContextId, flags: u8) {
-    let tracee = inner_cont(pid)
-        .map(|b| b.tracee)
-        .unwrap_or_else(|| Arc::new(WaitCondition::new()));
-
+pub fn set_breakpoint(pid: ContextId, flags: u64) {
     let mut sessions = sessions_mut();
     let session = sessions.get_mut(&pid).expect("proc (set_breakpoint): invalid session");
     session.breakpoint = Some(Breakpoint {
-        tracee,
         reached: false,
         flags
     });
@@ -244,7 +241,7 @@ pub fn wait(pid: ContextId) -> Result<Option<PtraceEvent>> {
 
 /// Notify the tracer and await green flag to continue.
 /// Note: Don't call while holding any locks, this will switch contexts
-pub fn breakpoint_callback(match_flags: u8) -> Option<u8> {
+pub fn breakpoint_callback(match_flags: u64, event: Option<PtraceEvent>) -> Option<u64> {
     // Can't hold any locks when executing wait()
     let (tracee, flags) = {
         let contexts = context::contexts();
@@ -258,10 +255,12 @@ pub fn breakpoint_callback(match_flags: u8) -> Option<u8> {
         // TODO: How should singlesteps interact with syscalls? How
         // does Linux handle this?
 
-        if breakpoint.flags & PTRACE_OPERATIONMASK != match_flags & PTRACE_OPERATIONMASK {
+        if breakpoint.flags & match_flags != match_flags {
             return None;
         }
 
+        session.events.push_back(event.unwrap_or(ptrace_event!(match_flags)));
+
         // In case no tracer is waiting, make sure the next one gets
         // the memo
         breakpoint.reached = true;
@@ -270,7 +269,7 @@ pub fn breakpoint_callback(match_flags: u8) -> Option<u8> {
         proc_trigger_event(session.file_id, EVENT_WRITE);
 
         (
-            Arc::clone(&breakpoint.tracee),
+            Arc::clone(&session.tracee),
             breakpoint.flags
         )
     };
@@ -280,6 +279,21 @@ pub fn breakpoint_callback(match_flags: u8) -> Option<u8> {
     Some(flags)
 }
 
+/// Obtain the next breakpoint flags for the current process. This is
+/// used for detecting whether or not the tracer decided to use sysemu
+/// mode.
+pub fn next_breakpoint() -> Option<u64> {
+    let contexts = context::contexts();
+    let context = contexts.current()?;
+    let context = context.read();
+
+    let sessions = sessions();
+    let session = sessions.get(&context.id)?;
+    let breakpoint = session.breakpoint.as_ref()?;
+
+    Some(breakpoint.flags)
+}
+
 /// Call when a context is closed to alert any tracers
 pub fn close_tracee(pid: ContextId) -> Option<()> {
     let mut sessions = sessions_mut();
diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs
index 5a04f9d55479a2b881ae11307eefb059c93d5ff4..66e51ad7612c66c962a61dc50f85872273df6eb9 100644
--- a/src/scheme/proc.rs
+++ b/src/scheme/proc.rs
@@ -1,9 +1,16 @@
 use crate::{
     arch::paging::VirtualAddress,
-    context::{self, ContextId, Status},
+    context::{self, Context, ContextId, Status},
     ptrace,
     scheme::{ATOMIC_SCHEMEID_INIT, AtomicSchemeId, SchemeId},
-    syscall::validate
+    syscall::{
+        data::{FloatRegisters, IntRegisters, PtraceEvent},
+        error::*,
+        flag::*,
+        scheme::Scheme,
+        self,
+        validate,
+    },
 };
 
 use alloc::{
@@ -17,12 +24,6 @@ use core::{
     sync::atomic::{AtomicUsize, Ordering}
 };
 use spin::{Mutex, RwLock};
-use syscall::{
-    data::{FloatRegisters, IntRegisters, PtraceEvent},
-    error::*,
-    flag::*,
-    scheme::Scheme
-};
 
 #[derive(Clone, Copy)]
 enum RegsKind {
@@ -38,6 +39,67 @@ enum Operation {
     }
 }
 
+fn with_context<F, T>(pid: ContextId, callback: F) -> Result<T>
+    where F: FnOnce(&Context) -> Result<T>
+{
+    let contexts = context::contexts();
+    let context = contexts.get(pid).ok_or(Error::new(ESRCH))?;
+    let context = context.read();
+    if let Status::Exited(_) = context.status {
+        return Err(Error::new(ESRCH));
+    }
+    callback(&context)
+}
+fn with_context_mut<F, T>(pid: ContextId, callback: F) -> Result<T>
+    where F: FnOnce(&mut Context) -> Result<T>
+{
+    let contexts = context::contexts();
+    let context = contexts.get(pid).ok_or(Error::new(ESRCH))?;
+    let mut context = context.write();
+    if let Status::Exited(_) = context.status {
+        return Err(Error::new(ESRCH));
+    }
+    callback(&mut context)
+}
+fn try_stop_context<F, T>(pid: ContextId, restart_after: bool, mut callback: F) -> Result<T>
+    where F: FnMut(&mut Context) -> Result<T>
+{
+    let mut first = true;
+    let mut was_stopped = false; // will never be read
+
+    loop {
+        if !first {
+            // We've tried this before, so lets wait before retrying
+            unsafe { context::switch(); }
+        }
+        first = false;
+
+        let contexts = context::contexts();
+        let context = contexts.get(pid).ok_or(Error::new(ESRCH))?;
+        let mut context = context.write();
+        if let Status::Exited(_) = context.status {
+            return Err(Error::new(ESRCH));
+        }
+
+        // Stop the process until we've done our thing
+        if first {
+            was_stopped = context.ptrace_stop;
+        }
+        context.ptrace_stop = true;
+
+        if context.running {
+            // Process still running, wait until it has stopped
+            continue;
+        }
+
+        let ret = callback(&mut context);
+
+        context.ptrace_stop = restart_after && was_stopped;
+
+        break ret;
+    }
+}
+
 #[derive(Clone, Copy)]
 struct Handle {
     flags: usize,
@@ -140,8 +202,10 @@ impl Scheme for ProcScheme {
                 return Err(Error::new(EBUSY));
             }
 
-            let mut target = target.write();
-            target.ptrace_stop = true;
+            if flags & O_TRUNC == O_TRUNC {
+                let mut target = target.write();
+                target.ptrace_stop = true;
+            }
         }
 
         self.handles.write().insert(id, Arc::new(Mutex::new(Handle {
@@ -228,42 +292,28 @@ impl Scheme for ProcScheme {
                     float: FloatRegisters,
                     int: IntRegisters
                 }
-                let mut first = true;
-                let (output, size) = loop {
-                    if !first {
-                        // We've tried this before, so lets wait before retrying
-                        unsafe { context::switch(); }
-                    }
-                    first = false;
 
-                    let contexts = context::contexts();
-                    let context = contexts.get(handle.pid).ok_or(Error::new(ESRCH))?;
-                    let context = context.read();
-
-                    break match kind {
-                        RegsKind::Float => {
-                            // NOTE: The kernel will never touch floats
+                let (output, size) = match kind {
+                    RegsKind::Float => with_context(handle.pid, |context| {
+                        // NOTE: The kernel will never touch floats
 
-                            // In the rare case of not having floating
-                            // point registers uninitiated, return
-                            // empty everything.
-                            let fx = context.arch.get_fx_regs().unwrap_or_default();
-                            (Output { float: fx }, mem::size_of::<FloatRegisters>())
+                        // In the rare case of not having floating
+                        // point registers uninitiated, return
+                        // empty everything.
+                        let fx = context.arch.get_fx_regs().unwrap_or_default();
+                        Ok((Output { float: fx }, mem::size_of::<FloatRegisters>()))
+                    })?,
+                    RegsKind::Int => try_stop_context(handle.pid, true, |context| match unsafe { ptrace::regs_for(&context) } {
+                        None => {
+                            println!("{}:{}: Couldn't read registers from stopped process", file!(), line!());
+                            Err(Error::new(ENOTRECOVERABLE))
                         },
-                        RegsKind::Int => match unsafe { ptrace::regs_for(&context) } {
-                            None => {
-                                // Another CPU is running this process, wait until it's stopped.
-                                continue;
-                            },
-                            Some(stack) => {
-                                let mut regs = IntRegisters::default();
-
-                                stack.save(&mut regs);
-
-                                (Output { int: regs }, mem::size_of::<IntRegisters>())
-                            }
+                        Some(stack) => {
+                            let mut regs = IntRegisters::default();
+                            stack.save(&mut regs);
+                            Ok((Output { int: regs }, mem::size_of::<IntRegisters>()))
                         }
-                    };
+                    })?
                 };
 
                 let bytes = unsafe {
@@ -300,7 +350,6 @@ impl Scheme for ProcScheme {
         let pid = handle.pid;
         let flags = handle.flags;
 
-        let mut first = true;
         match handle.operation {
             Operation::Memory(ref mut offset) => {
                 let contexts = context::contexts();
@@ -315,26 +364,16 @@ impl Scheme for ProcScheme {
                 *offset = VirtualAddress::new(offset.get() + buf.len());
                 Ok(buf.len())
             },
-            Operation::Regs(kind) => loop {
-                if !first {
-                    // We've tried this before, so lets wait before retrying
-                    unsafe { context::switch(); }
-                }
-                first = false;
-
-                let contexts = context::contexts();
-                let context = contexts.get(handle.pid).ok_or(Error::new(ESRCH))?;
-                let mut context = context.write();
-
-                break match kind {
-                    RegsKind::Float => {
-                        if buf.len() < mem::size_of::<FloatRegisters>() {
-                            return Ok(0);
-                        }
-                        let regs = unsafe {
-                            *(buf as *const _ as *const FloatRegisters)
-                        };
+            Operation::Regs(kind) => match kind {
+                RegsKind::Float => {
+                    if buf.len() < mem::size_of::<FloatRegisters>() {
+                        return Ok(0);
+                    }
+                    let regs = unsafe {
+                        *(buf as *const _ as *const FloatRegisters)
+                    };
 
+                    with_context_mut(pid, |context| {
                         // NOTE: The kernel will never touch floats
 
                         // Ignore the rare case of floating point
@@ -342,82 +381,73 @@ impl Scheme for ProcScheme {
                         let _ = context.arch.set_fx_regs(regs);
 
                         Ok(mem::size_of::<FloatRegisters>())
-                    },
-                    RegsKind::Int => match unsafe { ptrace::regs_for_mut(&mut context) } {
+                    })
+                },
+                RegsKind::Int => {
+                    if buf.len() < mem::size_of::<IntRegisters>() {
+                        return Ok(0);
+                    }
+                    let regs = unsafe {
+                        *(buf as *const _ as *const IntRegisters)
+                    };
+
+                    try_stop_context(handle.pid, true, |context| match unsafe { ptrace::regs_for_mut(context) } {
                         None => {
-                            // Another CPU is running this process, wait until it's stopped.
-                            continue;
+                            println!("{}:{}: Couldn't read registers from stopped process", file!(), line!());
+                            Err(Error::new(ENOTRECOVERABLE))
                         },
                         Some(stack) => {
-                            if buf.len() < mem::size_of::<IntRegisters>() {
-                                return Ok(0);
-                            }
-                            let regs = unsafe {
-                                *(buf as *const _ as *const IntRegisters)
-                            };
-
                             stack.load(&regs);
 
                             Ok(mem::size_of::<IntRegisters>())
                         }
-                    }
-                };
+                    })
+                }
             },
             Operation::Trace { ref mut new_child } => {
-                if buf.len() < 1 {
+                if buf.len() < mem::size_of::<u64>() {
                     return Ok(0);
                 }
-                let op = buf[0];
 
-                let mut blocking = flags & O_NONBLOCK != O_NONBLOCK;
-                let mut singlestep = false;
+                let mut bytes = [0; mem::size_of::<u64>()];
+                let len = bytes.len();
+                bytes.copy_from_slice(&buf[0..len]);
+                let op = u64::from_ne_bytes(bytes);
 
-                match op & PTRACE_OPERATIONMASK {
-                    PTRACE_CONT => { ptrace::cont(pid); },
-                    PTRACE_SYSCALL | PTRACE_SINGLESTEP | PTRACE_SIGNAL => { // <- not a bitwise OR
-                        singlestep = op & PTRACE_OPERATIONMASK == PTRACE_SINGLESTEP;
-                        ptrace::set_breakpoint(pid, op);
-                    },
-                    PTRACE_WAIT => blocking = true,
-                    _ => return Err(Error::new(EINVAL))
+                if op & PTRACE_FLAG_WAIT != PTRACE_FLAG_WAIT || op & PTRACE_STOP_MASK != 0 {
+                    ptrace::cont(pid);
+                }
+                if op & PTRACE_STOP_MASK != 0 {
+                    ptrace::set_breakpoint(pid, op);
                 }
 
-                let mut first = true;
-                loop {
-                    if !first {
-                        // We've tried this before, so lets wait before retrying
-                        unsafe { context::switch(); }
-                    }
-                    first = false;
-
-                    let contexts = context::contexts();
-                    let context = contexts.get(pid).ok_or(Error::new(ESRCH))?;
-                    let mut context = context.write();
-                    if let Status::Exited(_) = context.status {
-                        return Err(Error::new(ESRCH));
-                    }
-
-                    if singlestep {
-                        match unsafe { ptrace::regs_for_mut(&mut context) } {
-                            None => continue,
-                            Some(stack) => stack.set_singlestep(true)
+                if op & PTRACE_STOP_SINGLESTEP == PTRACE_STOP_SINGLESTEP {
+                    try_stop_context(pid, false, |context| {
+                        match unsafe { ptrace::regs_for_mut(context) } {
+                            // If another CPU is running this process,
+                            // await for it to be stopped and in such
+                            // a way the registers can be read!
+                            None => {
+                                println!("{}:{}: Couldn't read registers from stopped process", file!(), line!());
+                                Err(Error::new(ENOTRECOVERABLE))
+                            },
+                            Some(stack) => {
+                                stack.set_singlestep(true);
+                                Ok(())
+                            }
                         }
-                    }
-
-                    context.ptrace_stop = false;
-                    break;
+                    })?;
                 }
 
-                if blocking {
+                if op & PTRACE_FLAG_WAIT == PTRACE_FLAG_WAIT || flags & O_NONBLOCK != O_NONBLOCK {
                     if let Some(event) = ptrace::wait(pid)? {
-                        if event.tag == PTRACE_EVENT_CLONE {
-                            *new_child = Some(ContextId::from(unsafe { event.data.clone }));
+                        if event.cause == PTRACE_EVENT_CLONE {
+                            *new_child = Some(ContextId::from(event.a));
                         }
-                        return Ok(0);
                     }
                 }
 
-                Ok(1)
+                Ok(mem::size_of::<u64>())
             }
         }
     }
@@ -467,12 +497,16 @@ impl Scheme for ProcScheme {
 
         if let Operation::Trace { .. } = handle.operation {
             ptrace::close_session(handle.pid);
-        }
 
-        let contexts = context::contexts();
-        if let Some(context) = contexts.get(handle.pid) {
-            let mut context = context.write();
-            context.ptrace_stop = false;
+            if handle.flags & O_EXCL == O_EXCL {
+                syscall::kill(handle.pid, SIGKILL)?;
+            } else {
+                let contexts = context::contexts();
+                if let Some(context) = contexts.get(handle.pid) {
+                    let mut context = context.write();
+                    context.ptrace_stop = false;
+                }
+            }
         }
         Ok(0)
     }
diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs
index f76f96b67670f1d087e2c99ddf8ec0da8ca6c977..33ac677acccb1f3c07d683b1330003e80f57a649 100644
--- a/src/syscall/mod.rs
+++ b/src/syscall/mod.rs
@@ -4,7 +4,7 @@
 
 extern crate syscall;
 
-pub use self::syscall::{data, error, flag, io, number, scheme};
+pub use self::syscall::{data, error, flag, io, number, ptrace_event, scheme};
 
 pub use self::driver::*;
 pub use self::fs::*;
diff --git a/src/syscall/process.rs b/src/syscall/process.rs
index e683b4cfc644beeaff9d50765ad20fd31fcbbbd7..9c9aa2685c17153490fb9579a6cbbcd61c8cec9b 100644
--- a/src/syscall/process.rs
+++ b/src/syscall/process.rs
@@ -18,17 +18,17 @@ use crate::paging::entry::EntryFlags;
 use crate::paging::mapper::MapperFlushAll;
 use crate::paging::temporary_page::TemporaryPage;
 use crate::paging::{ActivePageTable, InactivePageTable, Page, VirtualAddress, PAGE_SIZE};
-use crate::ptrace;
+use crate::{ptrace, syscall};
 use crate::scheme::FileHandle;
 use crate::start::usermode;
-use crate::syscall::data::{PtraceEvent, PtraceEventData, SigAction, Stat};
+use crate::syscall::data::{PtraceEvent, SigAction, Stat};
 use crate::syscall::error::*;
 use crate::syscall::flag::{CLONE_VFORK, CLONE_VM, CLONE_FS, CLONE_FILES, CLONE_SIGHAND, CLONE_STACK,
                            PROT_EXEC, PROT_READ, PROT_WRITE, PTRACE_EVENT_CLONE,
                            SIG_DFL, SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK, SIGCONT, SIGTERM,
                            WCONTINUED, WNOHANG, WUNTRACED, wifcontinued, wifstopped};
+use crate::syscall::ptrace_event;
 use crate::syscall::validate::{validate_slice, validate_slice_mut};
-use crate::syscall;
 
 pub fn brk(address: usize) -> Result<usize> {
     let contexts = context::contexts();
@@ -585,14 +585,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
         }
     }
 
-    let ptrace_event = PtraceEvent {
-        tag: PTRACE_EVENT_CLONE,
-        data: PtraceEventData {
-            clone: pid.into()
-        }
-    };
-
-    if ptrace::send_event(ptrace_event).is_some() {
+    if ptrace::send_event(ptrace_event!(PTRACE_EVENT_CLONE, pid.into())).is_some() {
         // Freeze the clone, allow ptrace to put breakpoints
         // to it before it starts
         let contexts = context::contexts();
diff --git a/syscall b/syscall
index 9e9f47d2a570c55dd96cd80c83bc818d63cab8af..52441c28b1daa6f9febf1bc6588b625b167bd2c3 160000
--- a/syscall
+++ b/syscall
@@ -1 +1 @@
-Subproject commit 9e9f47d2a570c55dd96cd80c83bc818d63cab8af
+Subproject commit 52441c28b1daa6f9febf1bc6588b625b167bd2c3