diff --git a/Cargo.lock b/Cargo.lock
index db7f9e16953b2ff6607fa1305c97fe0827466f6c..a9cc12c25891d2fec784955eab8d6c95df786af0 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)",
@@ -278,6 +278,9 @@ dependencies = [
 [[package]]
 name = "redox_syscall"
 version = "0.1.56"
+dependencies = [
+ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
 
 [[package]]
 name = "regex"
@@ -495,7 +498,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..e76f39359e4e6186220516e9c7332c1d25353ad5 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
@@ -49,8 +49,15 @@ interrupt_stack!(non_maskable, stack, {
 
 interrupt_stack!(breakpoint, stack, {
     println!("Breakpoint trap");
-    stack.dump();
-    ksignal(SIGTRAP);
+
+    let guard = ptrace::set_process_regs(stack);
+
+    if ptrace::breakpoint_callback(PTRACE_STOP_BREAKPOINT, None).is_none() {
+        drop(guard);
+
+        stack.dump();
+        ksignal(SIGTRAP);
+    }
 });
 
 interrupt_stack!(overflow, stack, {
diff --git a/src/arch/x86_64/interrupt/syscall.rs b/src/arch/x86_64/interrupt/syscall.rs
index 6b9dfe615db217d6f51180a3dc9f23d84f1998fd..dd6b812f52636f44182a898629c0df188054d34d 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_FLAG_IGNORE, PTRACE_STOP_PRE_SYSCALL, PTRACE_STOP_POST_SYSCALL};
 use crate::{ptrace, syscall};
 use x86::shared::msr;
 
@@ -21,19 +22,16 @@ 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) {
-                // If not on a sysemu breakpoint
+            let thumbs_up = ptrace::breakpoint_callback(PTRACE_STOP_PRE_SYSCALL, None)
+                .and_then(|_| ptrace::next_breakpoint().map(|f| !f.contains(PTRACE_FLAG_IGNORE)));
+
+            if thumbs_up.unwrap_or(true) {
+                // If syscall not ignored
                 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/context.rs b/src/context/context.rs
index 0a0f1869b9c6ad635e9d2ba16a2284ff31550993..216726e512a8e7f07bc57d193410d8b98710ea3e 100644
--- a/src/context/context.rs
+++ b/src/context/context.rs
@@ -16,7 +16,7 @@ use crate::ipi::{ipi, IpiKind, IpiTarget};
 use crate::scheme::{SchemeNamespace, FileHandle};
 use crate::sync::WaitMap;
 use crate::syscall::data::SigAction;
-use crate::syscall::flag::SIG_DFL;
+use crate::syscall::flag::{SIG_DFL, SigActionFlags};
 
 /// Unique identifier for a context (i.e. `pid`).
 use ::core::sync::atomic::AtomicUsize;
@@ -222,7 +222,7 @@ impl Context {
                 SigAction {
                     sa_handler: unsafe { mem::transmute(SIG_DFL) },
                     sa_mask: [0; 2],
-                    sa_flags: 0,
+                    sa_flags: SigActionFlags::empty(),
                 },
                 0
             ); 128])),
diff --git a/src/context/signal.rs b/src/context/signal.rs
index d5d2ff18cb3e48918ca16cb2532148fa6856b648..942fb28c11ed80dc738e2b5098dc9b47c86d44c7 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_FLAG_IGNORE, PTRACE_STOP_SIGNAL, SIG_DFL, SIG_IGN, SIGCHLD, SIGCONT, SIGKILL, 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,17 @@ 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);
+
+    let thumbs_down = ptrace::breakpoint_callback(PTRACE_STOP_SIGNAL, Some(ptrace_event!(PTRACE_STOP_SIGNAL, sig, handler)))
+        .and_then(|_| ptrace::next_breakpoint().map(|f| f.contains(PTRACE_FLAG_IGNORE)));
+
+    if sig != SIGKILL && thumbs_down.unwrap_or(false) {
+        // If signal can be and was ignored
+        crate::syscall::sigreturn().unwrap();
+        unreachable!();
+    }
+
     if handler == SIG_DFL {
         match sig {
             SIGCHLD => {
@@ -92,7 +98,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 +106,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 +118,5 @@ pub extern "C" fn signal_handler(sig: usize) {
         }
     }
 
-    syscall::sigreturn().unwrap();
+    crate::syscall::sigreturn().unwrap();
 }
diff --git a/src/event.rs b/src/event.rs
index 7a7d25e0623c6711ea2f1aa69085a9b2f7c6139e..4eba3be241bda239159d48e7b729ae8fd8880939 100644
--- a/src/event.rs
+++ b/src/event.rs
@@ -8,6 +8,7 @@ use crate::scheme::{self, SchemeId};
 use crate::sync::WaitQueue;
 use crate::syscall::data::Event;
 use crate::syscall::error::{Error, Result, EBADF, EINTR, ESRCH};
+use crate::syscall::flag::EventFlags;
 
 int_like!(EventQueueId, AtomicEventQueueId, usize, AtomicUsize);
 
@@ -53,7 +54,7 @@ impl EventQueue {
             );
 
             let flags = sync(RegKey { scheme, number })?;
-            if flags > 0 {
+            if !flags.is_empty() {
                 trigger(scheme, number, flags);
             }
         }
@@ -100,10 +101,10 @@ pub struct RegKey {
 pub struct QueueKey {
     pub queue: EventQueueId,
     pub id: usize,
-    pub data: usize
+    pub data: usize,
 }
 
-type Registry = BTreeMap<RegKey, BTreeMap<QueueKey, usize>>;
+type Registry = BTreeMap<RegKey, BTreeMap<QueueKey, EventFlags>>;
 
 static REGISTRY: Once<RwLock<Registry>> = Once::new();
 
@@ -122,28 +123,28 @@ pub fn registry_mut() -> RwLockWriteGuard<'static, Registry> {
     REGISTRY.call_once(init_registry).write()
 }
 
-pub fn register(reg_key: RegKey, queue_key: QueueKey, flags: usize) {
+pub fn register(reg_key: RegKey, queue_key: QueueKey, flags: EventFlags) {
     let mut registry = registry_mut();
 
     let entry = registry.entry(reg_key).or_insert_with(|| {
         BTreeMap::new()
     });
 
-    if flags == 0 {
+    if flags.is_empty() {
         entry.remove(&queue_key);
     } else {
         entry.insert(queue_key, flags);
     }
 }
 
-pub fn sync(reg_key: RegKey) -> Result<usize> {
-    let mut flags = 0;
+pub fn sync(reg_key: RegKey) -> Result<EventFlags> {
+    let mut flags = EventFlags::empty();
 
     {
         let registry = registry();
 
         if let Some(queue_list) = registry.get(&reg_key) {
-            for (_queue_key, queue_flags) in queue_list.iter() {
+            for (_queue_key, &queue_flags) in queue_list.iter() {
                 flags |= queue_flags;
             }
         }
@@ -169,13 +170,13 @@ pub fn unregister_file(scheme: SchemeId, number: usize) {
 //
 // }
 
-pub fn trigger(scheme: SchemeId, number: usize, flags: usize) {
+pub fn trigger(scheme: SchemeId, number: usize, flags: EventFlags) {
     let registry = registry();
 
     if let Some(queue_list) = registry.get(&RegKey { scheme, number }) {
-        for (queue_key, queue_flags) in queue_list.iter() {
+        for (queue_key, &queue_flags) in queue_list.iter() {
             let common_flags = flags & queue_flags;
-            if common_flags != 0 {
+            if !common_flags.is_empty() {
                 let queues = queues();
                 if let Some(queue) = queues.get(&queue_key.queue) {
                     queue.queue.send(Event {
diff --git a/src/ptrace.rs b/src/ptrace.rs
index 3f3390f492b7a6ee1b4bdb32737a3723f35c44dc..c296922a6ab9e2c2927bccc69d36844236b1204f 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,
@@ -12,7 +16,13 @@ use crate::{
     context::{self, signal, Context, ContextId, Status},
     event,
     scheme::proc,
-    sync::WaitCondition
+    sync::WaitCondition,
+    syscall::{
+        data::PtraceEvent,
+        error::*,
+        flag::*,
+        ptrace_event
+    },
 };
 
 use alloc::{
@@ -30,11 +40,6 @@ use core::{
     sync::atomic::Ordering
 };
 use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
-use syscall::{
-    data::PtraceEvent,
-    error::*,
-    flag::*
-};
 
 //  ____                _
 // / ___|  ___  ___ ___(_) ___  _ __  ___
@@ -44,10 +49,25 @@ 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>,
+}
+impl Session {
+    fn send_event(&mut self, event: PtraceEvent) {
+        self.events.push_back(event);
+
+        // Notify nonblocking tracers
+        if self.events.len() == 1 {
+            // If the list of events was previously empty, alert now
+            proc_trigger_event(self.file_id, EVENT_READ);
+        }
+
+        // Alert blocking tracers
+        self.tracer.notify();
+    }
 }
 
 type SessionMap = BTreeMap<ContextId, Session>;
@@ -73,10 +93,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
         }
@@ -89,16 +110,13 @@ pub fn is_traced(pid: ContextId) -> bool {
 }
 
 /// Used for getting the flags in fevent
-pub fn session_fevent_flags(pid: ContextId) -> Option<usize> {
+pub fn session_fevent_flags(pid: ContextId) -> Option<EventFlags> {
     let sessions = sessions();
     let session = sessions.get(&pid)?;
-    let mut flags = 0;
+    let mut flags = EventFlags::empty();
     if !session.events.is_empty() {
         flags |= EVENT_READ;
     }
-    if session.breakpoint.as_ref().map(|b| b.reached).unwrap_or(true) {
-        flags |= EVENT_WRITE;
-    }
     Some(flags)
 }
 
@@ -107,14 +125,12 @@ 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();
     }
 }
 
 /// Trigger a notification to the event: scheme
-fn proc_trigger_event(file_id: usize, flags: usize) {
+fn proc_trigger_event(file_id: usize, flags: EventFlags) {
     event::trigger(proc::PROC_SCHEME_ID.load(Ordering::SeqCst), file_id, flags);
 }
 
@@ -128,17 +144,13 @@ pub fn send_event(event: PtraceEvent) -> Option<()> {
 
     let mut sessions = sessions_mut();
     let session = sessions.get_mut(&context.id)?;
+    let breakpoint = session.breakpoint.as_ref()?;
 
-    session.events.push_back(event);
-
-    // Notify nonblocking tracers
-    if session.events.len() == 1 {
-        // If the list of events was previously empty, alert now
-        proc_trigger_event(session.file_id, EVENT_READ);
+    if event.cause & breakpoint.flags != event.cause {
+        return None;
     }
 
-    // Alert blocking tracers
-    session.tracer.notify();
+    session.send_event(event);
 
     Some(())
 }
@@ -164,39 +176,31 @@ pub fn recv_events(pid: ContextId, out: &mut [PtraceEvent]) -> Option<usize> {
 
 #[derive(Debug)]
 struct Breakpoint {
-    tracee: Arc<WaitCondition>,
     reached: bool,
-    flags: u8
+    flags: PtraceFlags
 }
 
-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: PtraceFlags) {
     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
     });
@@ -207,31 +211,22 @@ pub fn set_breakpoint(pid: ContextId, flags: u8) {
 ///
 /// Note: Don't call while holding any locks, this will switch
 /// contexts
-pub fn wait(pid: ContextId) -> Result<Option<PtraceEvent>> {
+pub fn wait(pid: ContextId) -> Result<()> {
     let tracer: Arc<WaitCondition> = {
         let sessions = sessions();
         match sessions.get(&pid) {
             Some(session) if session.breakpoint.as_ref().map(|b| !b.reached).unwrap_or(true) => {
-                if let Some(event) = session.events.front() {
-                    return Ok(Some(event.clone()));
+                if !session.events.is_empty() {
+                    return Ok(());
                 }
                 Arc::clone(&session.tracer)
             },
-            _ => return Ok(None)
+            _ => return Ok(())
         }
     };
 
     while !tracer.wait() {}
 
-    {
-        let sessions = sessions();
-        if let Some(session) = sessions.get(&pid) {
-            if let Some(event) = session.events.front() {
-                return Ok(Some(event.clone()));
-            }
-        }
-    }
-
     let contexts = context::contexts();
     let context = contexts.get(pid).ok_or(Error::new(ESRCH))?;
     let context = context.read();
@@ -239,12 +234,12 @@ pub fn wait(pid: ContextId) -> Result<Option<PtraceEvent>> {
         return Err(Error::new(ESRCH));
     }
 
-    Ok(None)
+    Ok(())
 }
 
 /// 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: PtraceFlags, event: Option<PtraceEvent>) -> Option<PtraceFlags> {
     // Can't hold any locks when executing wait()
     let (tracee, flags) = {
         let contexts = context::contexts();
@@ -255,10 +250,7 @@ pub fn breakpoint_callback(match_flags: u8) -> Option<u8> {
         let session = sessions.get_mut(&context.id)?;
         let breakpoint = session.breakpoint.as_mut()?;
 
-        // 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;
         }
 
@@ -266,12 +258,12 @@ pub fn breakpoint_callback(match_flags: u8) -> Option<u8> {
         // the memo
         breakpoint.reached = true;
 
-        session.tracer.notify();
-        proc_trigger_event(session.file_id, EVENT_WRITE);
+        let flags = breakpoint.flags;
+        session.send_event(event.unwrap_or(ptrace_event!(match_flags)));
 
         (
-            Arc::clone(&breakpoint.tracee),
-            breakpoint.flags
+            Arc::clone(&session.tracee),
+            flags
         )
     };
 
@@ -280,13 +272,32 @@ 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<PtraceFlags> {
+    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();
     let session = sessions.get_mut(&pid)?;
 
+    // Cause tracers to wake up. Any action will cause ESRCH which can
+    // be used to detect exit.
     session.breakpoint = None;
     session.tracer.notify();
+    proc_trigger_event(session.file_id, EVENT_READ);
+
     Some(())
 }
 
diff --git a/src/scheme/debug.rs b/src/scheme/debug.rs
index 4ec00e5ad7bc6c3ae5accef1a4c4ba29409a0290..abcb60c03df42930a361495c5b74a460d33a6438 100644
--- a/src/scheme/debug.rs
+++ b/src/scheme/debug.rs
@@ -5,7 +5,7 @@ use crate::arch::debug::Writer;
 use crate::event;
 use crate::scheme::*;
 use crate::sync::WaitQueue;
-use crate::syscall::flag::{EVENT_READ, F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK};
+use crate::syscall::flag::{EventFlags, EVENT_READ, F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK};
 use crate::syscall::scheme::Scheme;
 
 pub static DEBUG_SCHEME_ID: AtomicSchemeId = ATOMIC_SCHEMEID_INIT;
@@ -102,13 +102,13 @@ impl Scheme for DebugScheme {
         }
     }
 
-    fn fevent(&self, id: usize, _flags: usize) -> Result<usize> {
+    fn fevent(&self, id: usize, _flags: EventFlags) -> Result<EventFlags> {
         let _flags = {
             let handles = handles();
             *handles.get(&id).ok_or(Error::new(EBADF))?
         };
 
-        Ok(0)
+        Ok(EventFlags::empty())
     }
 
     fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
diff --git a/src/scheme/irq.rs b/src/scheme/irq.rs
index eb51768b167fd563e704e6f09a18c8315f6f2cf7..f7a4e3739b2ab370dfdf799a13c61ff2293507c7 100644
--- a/src/scheme/irq.rs
+++ b/src/scheme/irq.rs
@@ -6,7 +6,7 @@ use crate::event;
 use crate::interrupt::irq::acknowledge;
 use crate::scheme::{AtomicSchemeId, ATOMIC_SCHEMEID_INIT, SchemeId};
 use crate::syscall::error::*;
-use crate::syscall::flag::EVENT_READ;
+use crate::syscall::flag::{EventFlags, EVENT_READ};
 use crate::syscall::scheme::Scheme;
 
 pub static IRQ_SCHEME_ID: AtomicSchemeId = ATOMIC_SCHEMEID_INIT;
@@ -87,8 +87,8 @@ impl Scheme for IrqScheme {
         Ok(0)
     }
 
-    fn fevent(&self, _id: usize, _flags: usize) -> Result<usize> {
-        Ok(0)
+    fn fevent(&self, _id: usize, _flags: EventFlags) -> Result<EventFlags> {
+        Ok(EventFlags::empty())
     }
 
     fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
diff --git a/src/scheme/itimer.rs b/src/scheme/itimer.rs
index 3a91c3a2c4bc2443f57be769d30ff0d5be3babfd..92ca1ab02a3c1fcb1b3e0bf602c7a9ea6fc6ac64 100644
--- a/src/scheme/itimer.rs
+++ b/src/scheme/itimer.rs
@@ -5,7 +5,7 @@ use spin::RwLock;
 
 use crate::syscall::data::ITimerSpec;
 use crate::syscall::error::*;
-use crate::syscall::flag::{CLOCK_REALTIME, CLOCK_MONOTONIC};
+use crate::syscall::flag::{CLOCK_REALTIME, CLOCK_MONOTONIC, EventFlags};
 use crate::syscall::scheme::Scheme;
 
 pub struct ITimerScheme {
@@ -79,9 +79,9 @@ impl Scheme for ITimerScheme {
         Ok(0)
     }
 
-    fn fevent(&self, id: usize, _flags: usize) ->  Result<usize> {
+    fn fevent(&self, id: usize, _flags: EventFlags) ->  Result<EventFlags> {
         let handles = self.handles.read();
-        handles.get(&id).ok_or(Error::new(EBADF)).and(Ok(0))
+        handles.get(&id).ok_or(Error::new(EBADF)).and(Ok(EventFlags::empty()))
     }
 
     fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
diff --git a/src/scheme/memory.rs b/src/scheme/memory.rs
index fd14ab31592157f2f7449b62afbb8e380bb2186f..f9f7496fc47f90c773cfdbd6596334a77eb4c37c 100644
--- a/src/scheme/memory.rs
+++ b/src/scheme/memory.rs
@@ -47,13 +47,13 @@ impl Scheme for MemoryScheme {
             let mut to_address = crate::USER_GRANT_OFFSET;
 
             let mut entry_flags = EntryFlags::PRESENT | EntryFlags::USER_ACCESSIBLE;
-            if map.flags & PROT_EXEC == 0 {
+            if !map.flags.contains(PROT_EXEC) {
                 entry_flags |= EntryFlags::NO_EXECUTE;
             }
-            if map.flags & PROT_READ > 0 {
+            if map.flags.contains(PROT_READ) {
                 //TODO: PROT_READ
             }
-            if map.flags & PROT_WRITE > 0 {
+            if map.flags.contains(PROT_WRITE) {
                 entry_flags |= EntryFlags::WRITABLE;
             }
 
diff --git a/src/scheme/pipe.rs b/src/scheme/pipe.rs
index 7c02c077f8f9074edd2292270fa6c1b1689864be..bfc523219e6b51e8bb8eb8133a2d86884bfd0a19 100644
--- a/src/scheme/pipe.rs
+++ b/src/scheme/pipe.rs
@@ -7,7 +7,7 @@ use crate::event;
 use crate::scheme::{AtomicSchemeId, ATOMIC_SCHEMEID_INIT, SchemeId};
 use crate::sync::WaitCondition;
 use crate::syscall::error::{Error, Result, EAGAIN, EBADF, EINTR, EINVAL, EPIPE, ESPIPE};
-use crate::syscall::flag::{EVENT_READ, EVENT_WRITE, F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK, MODE_FIFO};
+use crate::syscall::flag::{EventFlags, EVENT_READ, EVENT_WRITE, F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK, MODE_FIFO};
 use crate::syscall::scheme::Scheme;
 use crate::syscall::data::Stat;
 
@@ -87,14 +87,14 @@ impl Scheme for PipeScheme {
         Err(Error::new(EBADF))
     }
 
-    fn fevent(&self, id: usize, flags: usize) -> Result<usize> {
+    fn fevent(&self, id: usize, flags: EventFlags) -> Result<EventFlags> {
         let pipes = pipes();
 
         if let Some(pipe) = pipes.0.get(&id) {
             if flags == EVENT_READ {
                 // TODO: Return correct flags
                 if pipe.vec.lock().is_empty() {
-                    return Ok(0);
+                    return Ok(EventFlags::empty());
                 } else {
                     return Ok(EVENT_READ);
                 }
diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs
index 5a04f9d55479a2b881ae11307eefb059c93d5ff4..b91831a415ac39e41e18cab9ec3efc66ffa69caf 100644
--- a/src/scheme/proc.rs
+++ b/src/scheme/proc.rs
@@ -1,62 +1,131 @@
 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::{
     collections::BTreeMap,
-    sync::Arc
+    sync::Arc,
+    vec::Vec
 };
 use core::{
     cmp,
     mem,
     slice,
-    sync::atomic::{AtomicUsize, Ordering}
+    sync::atomic::{AtomicUsize, Ordering},
 };
 use spin::{Mutex, RwLock};
-use syscall::{
-    data::{FloatRegisters, IntRegisters, PtraceEvent},
-    error::*,
-    flag::*,
-    scheme::Scheme
-};
 
 #[derive(Clone, Copy)]
 enum RegsKind {
     Float,
     Int
 }
-#[derive(Clone, Copy)]
+#[derive(Clone)]
 enum Operation {
     Memory(VirtualAddress),
     Regs(RegsKind),
     Trace {
-        new_child: Option<ContextId>
+        clones: Vec<ContextId>
+    }
+}
+
+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,
+struct Info {
     pid: ContextId,
+    flags: usize,
+}
+struct Handle {
+    info: Info,
     operation: Operation
 }
 impl Handle {
-    fn continue_ignored_child(&mut self) -> Option<()> {
-        let pid = match self.operation {
-            Operation::Trace { ref mut new_child } => new_child.take()?,
+    fn continue_ignored_children(&mut self) -> Option<()> {
+        let clones = match self.operation {
+            Operation::Trace { ref mut clones } => clones,
             _ => return None
         };
-        if ptrace::is_traced(pid) {
-            return None;
-        }
         let contexts = context::contexts();
-        let context = contexts.get(pid)?;
-        let mut context = context.write();
-        context.ptrace_stop = false;
+        for pid in clones.drain(..) {
+            if ptrace::is_traced(pid) {
+                continue;
+            }
+            if let Some(context) = contexts.get(pid) {
+                let mut context = context.write();
+                context.ptrace_stop = false;
+            }
+        }
         Some(())
     }
 }
@@ -92,7 +161,7 @@ impl Scheme for ProcScheme {
             Some("regs/float") => Operation::Regs(RegsKind::Float),
             Some("regs/int") => Operation::Regs(RegsKind::Int),
             Some("trace") => Operation::Trace {
-                new_child: None
+                clones: Vec::new()
             },
             _ => return Err(Error::new(EINVAL))
         };
@@ -140,14 +209,18 @@ 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 {
-            flags,
-            pid,
-            operation
+            info: Info {
+                flags,
+                pid,
+            },
+            operation,
         })));
         Ok(id)
     }
@@ -160,14 +233,14 @@ impl Scheme for ProcScheme {
     /// let regs = syscall::dup(trace, "regs/int")?;
     /// ```
     fn dup(&self, old_id: usize, buf: &[u8]) -> Result<usize> {
-        let handle = {
+        let info = {
             let handles = self.handles.read();
             let handle = handles.get(&old_id).ok_or(Error::new(EBADF))?;
             let handle = handle.lock();
-            *handle
+            handle.info
         };
 
-        let mut path = format!("{}/", handle.pid.into()).into_bytes();
+        let mut path = format!("{}/", info.pid.into()).into_bytes();
         path.extend_from_slice(buf);
 
         let (uid, gid) = {
@@ -177,7 +250,7 @@ impl Scheme for ProcScheme {
             (context.euid, context.egid)
         };
 
-        self.open(&path, handle.flags, uid, gid)
+        self.open(&path, info.flags, uid, gid)
     }
 
     fn seek(&self, id: usize, pos: usize, whence: usize) -> Result<usize> {
@@ -205,14 +278,13 @@ impl Scheme for ProcScheme {
             let handles = self.handles.read();
             Arc::clone(handles.get(&id).ok_or(Error::new(EBADF))?)
         };
-        // TODO: Make sure handle can't deadlock
         let mut handle = handle.lock();
-        let pid = handle.pid;
+        let info = handle.info;
 
         match handle.operation {
             Operation::Memory(ref mut offset) => {
                 let contexts = context::contexts();
-                let context = contexts.get(pid).ok_or(Error::new(ESRCH))?;
+                let context = contexts.get(info.pid).ok_or(Error::new(ESRCH))?;
                 let context = context.read();
 
                 ptrace::with_context_memory(&context, *offset, buf.len(), |ptr| {
@@ -228,42 +300,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(info.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(info.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 {
@@ -274,13 +332,20 @@ impl Scheme for ProcScheme {
 
                 Ok(len)
             },
-            Operation::Trace { .. } => {
-                let read = ptrace::recv_events(handle.pid, unsafe {
+            Operation::Trace { ref mut clones } => {
+                let slice = unsafe {
                     slice::from_raw_parts_mut(
                         buf.as_mut_ptr() as *mut PtraceEvent,
                         buf.len() / mem::size_of::<PtraceEvent>()
                     )
-                }).unwrap_or(0);
+                };
+                let read = ptrace::recv_events(info.pid, slice).unwrap_or(0);
+
+                for event in &slice[..read] {
+                    if event.cause == PTRACE_EVENT_CLONE {
+                        clones.push(ContextId::from(event.a));
+                    }
+                }
 
                 Ok(read * mem::size_of::<PtraceEvent>())
             }
@@ -294,17 +359,13 @@ impl Scheme for ProcScheme {
             Arc::clone(handles.get(&id).ok_or(Error::new(EBADF))?)
         };
         let mut handle = handle.lock();
-        handle.continue_ignored_child();
+        let info = handle.info;
+        handle.continue_ignored_children();
 
-        // Some operations borrow Operation:: mutably
-        let pid = handle.pid;
-        let flags = handle.flags;
-
-        let mut first = true;
         match handle.operation {
             Operation::Memory(ref mut offset) => {
                 let contexts = context::contexts();
-                let context = contexts.get(pid).ok_or(Error::new(ESRCH))?;
+                let context = contexts.get(info.pid).ok_or(Error::new(ESRCH))?;
                 let context = context.read();
 
                 ptrace::with_context_memory(&context, *offset, buf.len(), |ptr| {
@@ -315,26 +376,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(info.pid, |context| {
                         // NOTE: The kernel will never touch floats
 
                         // Ignore the rare case of floating point
@@ -342,82 +393,78 @@ 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(info.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 {
+            Operation::Trace { .. } => {
+                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);
+                let op = PtraceFlags::from_bits(op).ok_or(Error::new(EINVAL))?;
 
-                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.contains(PTRACE_FLAG_WAIT) || op.intersects(PTRACE_STOP_MASK) {
+                    ptrace::cont(info.pid);
+                }
+                if op.intersects(PTRACE_STOP_MASK) {
+                    ptrace::set_breakpoint(info.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.contains(PTRACE_STOP_SINGLESTEP) {
+                    // try_stop_context with `false` will
+                    // automatically disable ptrace_stop
+                    try_stop_context(info.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;
+                    })?;
+                } else {
+                    // disable ptrace stop
+                    with_context_mut(info.pid, |context| {
+                        context.ptrace_stop = false;
+                        Ok(())
+                    })?;
                 }
 
-                if blocking {
-                    if let Some(event) = ptrace::wait(pid)? {
-                        if event.tag == PTRACE_EVENT_CLONE {
-                            *new_child = Some(ContextId::from(unsafe { event.data.clone }));
-                        }
-                        return Ok(0);
-                    }
+                if op.contains(PTRACE_FLAG_WAIT) || info.flags & O_NONBLOCK != O_NONBLOCK {
+                    ptrace::wait(info.pid)?;
                 }
 
-                Ok(1)
+                Ok(mem::size_of::<u64>())
             }
         }
     }
@@ -428,18 +475,18 @@ impl Scheme for ProcScheme {
         let mut handle = handle.lock();
 
         match cmd {
-            F_SETFL => { handle.flags = arg; Ok(0) },
-            F_GETFL => return Ok(handle.flags),
+            F_SETFL => { handle.info.flags = arg; Ok(0) },
+            F_GETFL => return Ok(handle.info.flags),
             _ => return Err(Error::new(EINVAL))
         }
     }
 
-    fn fevent(&self, id: usize, _flags: usize) -> Result<usize> {
+    fn fevent(&self, id: usize, _flags: EventFlags) -> Result<EventFlags> {
         let handles = self.handles.read();
         let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
         let handle = handle.lock();
 
-        Ok(ptrace::session_fevent_flags(handle.pid).expect("proc (fevent): invalid session"))
+        Ok(ptrace::session_fevent_flags(handle.info.pid).expect("proc (fevent): invalid session"))
     }
 
     fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
@@ -447,7 +494,7 @@ impl Scheme for ProcScheme {
         let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
         let handle = handle.lock();
 
-        let path = format!("proc:{}/{}", handle.pid.into(), match handle.operation {
+        let path = format!("proc:{}/{}", handle.info.pid.into(), match handle.operation {
             Operation::Memory(_) => "mem",
             Operation::Regs(RegsKind::Float) => "regs/float",
             Operation::Regs(RegsKind::Int) => "regs/int",
@@ -463,16 +510,20 @@ impl Scheme for ProcScheme {
     fn close(&self, id: usize) -> Result<usize> {
         let handle = self.handles.write().remove(&id).ok_or(Error::new(EBADF))?;
         let mut handle = handle.lock();
-        handle.continue_ignored_child();
+        handle.continue_ignored_children();
 
         if let Operation::Trace { .. } = handle.operation {
-            ptrace::close_session(handle.pid);
-        }
+            ptrace::close_session(handle.info.pid);
 
-        let contexts = context::contexts();
-        if let Some(context) = contexts.get(handle.pid) {
-            let mut context = context.write();
-            context.ptrace_stop = false;
+            if handle.info.flags & O_EXCL == O_EXCL {
+                syscall::kill(handle.info.pid, SIGKILL)?;
+            } else {
+                let contexts = context::contexts();
+                if let Some(context) = contexts.get(handle.info.pid) {
+                    let mut context = context.write();
+                    context.ptrace_stop = false;
+                }
+            }
         }
         Ok(0)
     }
diff --git a/src/scheme/root.rs b/src/scheme/root.rs
index 13f9089110e63ecc444caba7245772fb7e98b9f8..c4315cd4104e8bc2b8ac95c616bcf3e7c9315d0d 100644
--- a/src/scheme/root.rs
+++ b/src/scheme/root.rs
@@ -9,7 +9,7 @@ use spin::{Mutex, RwLock};
 use crate::context;
 use crate::syscall::data::Stat;
 use crate::syscall::error::*;
-use crate::syscall::flag::{O_CREAT, MODE_FILE, MODE_DIR, SEEK_SET, SEEK_CUR, SEEK_END};
+use crate::syscall::flag::{EventFlags, O_CREAT, MODE_FILE, MODE_DIR, SEEK_SET, SEEK_CUR, SEEK_END};
 use crate::syscall::scheme::Scheme;
 use crate::scheme::{self, SchemeNamespace, SchemeId};
 use crate::scheme::user::{UserInner, UserScheme};
@@ -226,7 +226,7 @@ impl Scheme for RootScheme {
         }
     }
 
-    fn fevent(&self, file: usize, flags: usize) -> Result<usize> {
+    fn fevent(&self, file: usize, flags: EventFlags) -> Result<EventFlags> {
         let handle = {
             let handles = self.handles.read();
             let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
diff --git a/src/scheme/time.rs b/src/scheme/time.rs
index 8b340fb4749700e5db0e0fb085cd3211c7da22aa..718d14dc710b5bfed8c9a421b159a4c960d86263 100644
--- a/src/scheme/time.rs
+++ b/src/scheme/time.rs
@@ -7,7 +7,7 @@ use crate::context::timeout;
 use crate::scheme::SchemeId;
 use crate::syscall::data::TimeSpec;
 use crate::syscall::error::*;
-use crate::syscall::flag::{CLOCK_REALTIME, CLOCK_MONOTONIC};
+use crate::syscall::flag::{CLOCK_REALTIME, CLOCK_MONOTONIC, EventFlags};
 use crate::syscall::scheme::Scheme;
 use crate::time;
 
@@ -90,9 +90,9 @@ impl Scheme for TimeScheme {
         Ok(0)
     }
 
-    fn fevent(&self, id: usize, _flags: usize) ->  Result<usize> {
+    fn fevent(&self, id: usize, _flags: EventFlags) -> Result<EventFlags> {
         let handles = self.handles.read();
-        handles.get(&id).ok_or(Error::new(EBADF)).and(Ok(0))
+        handles.get(&id).ok_or(Error::new(EBADF)).and(Ok(EventFlags::empty()))
     }
 
     fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
diff --git a/src/scheme/user.rs b/src/scheme/user.rs
index 11a86200261d6f17c159f8db4405f66d619eaf80..91f2d6fcffee63c876e9fe71d6ef1594ac337f1e 100644
--- a/src/scheme/user.rs
+++ b/src/scheme/user.rs
@@ -16,7 +16,7 @@ use crate::scheme::{AtomicSchemeId, ATOMIC_SCHEMEID_INIT, SchemeId};
 use crate::sync::{WaitQueue, WaitMap};
 use crate::syscall::data::{Map, Packet, Stat, StatVfs, TimeSpec};
 use crate::syscall::error::*;
-use crate::syscall::flag::{EVENT_READ, O_NONBLOCK, PROT_EXEC, PROT_READ, PROT_WRITE};
+use crate::syscall::flag::{EventFlags, EVENT_READ, O_NONBLOCK, MapFlags, PROT_EXEC, PROT_READ, PROT_WRITE};
 use crate::syscall::number::*;
 use crate::syscall::scheme::Scheme;
 
@@ -108,7 +108,7 @@ impl UserInner {
         UserInner::capture_inner(&self.context, buf.as_mut_ptr() as usize, buf.len(), PROT_WRITE, None)
     }
 
-    fn capture_inner(context_weak: &Weak<RwLock<Context>>, address: usize, size: usize, flags: usize, desc_opt: Option<FileDescriptor>) -> Result<usize> {
+    fn capture_inner(context_weak: &Weak<RwLock<Context>>, address: usize, size: usize, flags: MapFlags, desc_opt: Option<FileDescriptor>) -> Result<usize> {
         //TODO: Abstract with other grant creation
         if size == 0 {
             Ok(0)
@@ -127,13 +127,13 @@ impl UserInner {
             let mut to_address = crate::USER_GRANT_OFFSET;
 
             let mut entry_flags = EntryFlags::PRESENT | EntryFlags::USER_ACCESSIBLE;
-            if flags & PROT_EXEC == 0 {
+            if !flags.contains(PROT_EXEC) {
                 entry_flags |= EntryFlags::NO_EXECUTE;
             }
-            if flags & PROT_READ > 0 {
+            if flags.contains(PROT_READ) {
                 //TODO: PROT_READ
             }
-            if flags & PROT_WRITE > 0 {
+            if flags.contains(PROT_WRITE) {
                 entry_flags |= EntryFlags::WRITABLE;
             }
 
@@ -232,7 +232,7 @@ impl UserInner {
             let mut packet = unsafe { *(buf.as_ptr() as *const Packet).offset(i as isize) };
             if packet.id == 0 {
                 match packet.a {
-                    SYS_FEVENT => event::trigger(self.scheme_id.load(Ordering::SeqCst), packet.b, packet.c),
+                    SYS_FEVENT => event::trigger(self.scheme_id.load(Ordering::SeqCst), packet.b, EventFlags::from_bits_truncate(packet.c)),
                     _ => println!("Unknown scheme -> kernel message {}", packet.a)
                 }
             } else {
@@ -257,8 +257,8 @@ impl UserInner {
         Ok(i * packet_size)
     }
 
-    pub fn fevent(&self, _flags: usize) -> Result<usize> {
-        Ok(0)
+    pub fn fevent(&self, _flags: EventFlags) -> Result<EventFlags> {
+        Ok(EventFlags::empty())
     }
 
     pub fn fsync(&self) -> Result<usize> {
@@ -356,9 +356,9 @@ impl Scheme for UserScheme {
         inner.call(SYS_FCNTL, file, cmd, arg)
     }
 
-    fn fevent(&self, file: usize, flags: usize) -> Result<usize> {
+    fn fevent(&self, file: usize, flags: EventFlags) -> Result<EventFlags> {
         let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
-        inner.call(SYS_FEVENT, file, flags, 0)
+        inner.call(SYS_FEVENT, file, flags.bits(), 0).map(EventFlags::from_bits_truncate)
     }
 
     fn fmap(&self, file: usize, map: &Map) -> Result<usize> {
diff --git a/src/syscall/debug.rs b/src/syscall/debug.rs
index 94f4552867d76bf43c456411a667824351b229aa..270453ce15d67542d799588639517eb4773643c1 100644
--- a/src/syscall/debug.rs
+++ b/src/syscall/debug.rs
@@ -175,8 +175,8 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -
             validate_slice_mut(c as *mut TimeSpec, 1)
         ),
         SYS_CLONE => format!(
-            "clone({})",
-            b
+            "clone({:?})",
+            CloneFlags::from_bits(b)
         ),
         SYS_EXIT => format!(
             "exit({})",
@@ -256,10 +256,10 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -
             validate_slice(b as *const [usize; 2], c)
         ),
         SYS_MPROTECT => format!(
-            "mprotect({:#X}, {}, {:#X})",
+            "mprotect({:#X}, {}, {:?})",
             b,
             c,
-            d
+            MapFlags::from_bits(d)
         ),
         SYS_NANOSLEEP => format!(
             "nanosleep({:?}, ({}, {}))",
@@ -277,10 +277,10 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -
             c
         ),
         SYS_PHYSMAP => format!(
-            "physmap({:#X}, {}, {:#X})",
+            "physmap({:#X}, {}, {:?})",
             b,
             c,
-            d
+            PhysmapFlags::from_bits(d)
         ),
         SYS_PHYSUNMAP => format!(
             "physunmap({:#X})",
@@ -315,10 +315,10 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -
             b
         ),
         SYS_WAITPID => format!(
-            "waitpid({}, {:#X}, {})",
+            "waitpid({}, {:#X}, {:?})",
             b,
             c,
-            d
+            WaitFlags::from_bits(d)
         ),
         SYS_YIELD => format!("yield()"),
         _ => format!(
diff --git a/src/syscall/driver.rs b/src/syscall/driver.rs
index 1ab0a4cbe1b018aec2bc0303a0e32e5edc25faf4..e1655fdb514c1430972d4b321d2afc76a84a9ed0 100644
--- a/src/syscall/driver.rs
+++ b/src/syscall/driver.rs
@@ -5,7 +5,7 @@ use crate::paging::entry::EntryFlags;
 use crate::context;
 use crate::context::memory::Grant;
 use crate::syscall::error::{Error, EFAULT, EINVAL, ENOMEM, EPERM, ESRCH, Result};
-use crate::syscall::flag::{PHYSMAP_WRITE, PHYSMAP_WRITE_COMBINE, PHYSMAP_NO_CACHE};
+use crate::syscall::flag::{PhysmapFlags, PHYSMAP_WRITE, PHYSMAP_WRITE_COMBINE, PHYSMAP_NO_CACHE};
 
 fn enforce_root() -> Result<()> {
     let contexts = context::contexts();
@@ -50,7 +50,7 @@ pub fn physfree(physical_address: usize, size: usize) -> Result<usize> {
 }
 
 //TODO: verify exlusive access to physical memory
-pub fn inner_physmap(physical_address: usize, size: usize, flags: usize) -> Result<usize> {
+pub fn inner_physmap(physical_address: usize, size: usize, flags: PhysmapFlags) -> Result<usize> {
     //TODO: Abstract with other grant creation
     if size == 0 {
         Ok(0)
@@ -67,13 +67,13 @@ pub fn inner_physmap(physical_address: usize, size: usize, flags: usize) -> Resu
         let mut to_address = crate::USER_GRANT_OFFSET;
 
         let mut entry_flags = EntryFlags::PRESENT | EntryFlags::NO_EXECUTE | EntryFlags::USER_ACCESSIBLE;
-        if flags & PHYSMAP_WRITE == PHYSMAP_WRITE {
+        if flags.contains(PHYSMAP_WRITE) {
             entry_flags |= EntryFlags::WRITABLE;
         }
-        if flags & PHYSMAP_WRITE_COMBINE == PHYSMAP_WRITE_COMBINE {
+        if flags.contains(PHYSMAP_WRITE_COMBINE) {
             entry_flags |= EntryFlags::HUGE_PAGE;
         }
-        if flags & PHYSMAP_NO_CACHE == PHYSMAP_NO_CACHE {
+        if flags.contains(PHYSMAP_NO_CACHE) {
             entry_flags |= EntryFlags::NO_CACHE;
         }
 
@@ -100,7 +100,7 @@ pub fn inner_physmap(physical_address: usize, size: usize, flags: usize) -> Resu
         Ok(to_address + offset)
     }
 }
-pub fn physmap(physical_address: usize, size: usize, flags: usize) -> Result<usize> {
+pub fn physmap(physical_address: usize, size: usize, flags: PhysmapFlags) -> Result<usize> {
     enforce_root()?;
     inner_physmap(physical_address, size, flags)
 }
diff --git a/src/syscall/fs.rs b/src/syscall/fs.rs
index 1746d77aca06fe945929aa2a9bbd8b248c4ba743..c4bcc6c909d74cfe1b4dec7223ec7f9ab2d36cf3 100644
--- a/src/syscall/fs.rs
+++ b/src/syscall/fs.rs
@@ -8,7 +8,7 @@ use crate::scheme::{self, FileHandle};
 use crate::syscall;
 use crate::syscall::data::{Packet, Stat};
 use crate::syscall::error::*;
-use crate::syscall::flag::{F_GETFD, F_SETFD, F_GETFL, F_SETFL, F_DUPFD, O_ACCMODE, O_DIRECTORY, O_RDONLY, O_SYMLINK, O_WRONLY, MODE_DIR, MODE_FILE, O_CLOEXEC};
+use crate::syscall::flag::*;
 use crate::context::file::{FileDescriptor, FileDescription};
 
 pub fn file_op(a: usize, fd: FileHandle, c: usize, d: usize) -> Result<usize> {
@@ -92,7 +92,7 @@ pub fn open(path: &[u8], flags: usize) -> Result<FileHandle> {
         (context.canonicalize(path), context.euid, context.egid, context.ens, context.umask)
     };
 
-    let flags = (flags & (!0o777)) | (flags & 0o777) & (!(umask & 0o777));
+    let flags = (flags & (!0o777)) | ((flags & 0o777) & (!(umask & 0o777)));
 
     //println!("open {}", unsafe { ::core::str::from_utf8_unchecked(&path_canon) });
 
diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs
index f76f96b67670f1d087e2c99ddf8ec0da8ca6c977..de4014a0bccf6130ec6725ffd567d77b8506fe2e 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::*;
@@ -16,6 +16,7 @@ pub use self::validate::*;
 
 use self::data::{SigAction, TimeSpec};
 use self::error::{Error, Result, ENOSYS};
+use self::flag::{CloneFlags, MapFlags, PhysmapFlags, WaitFlags};
 use self::number::*;
 
 use crate::context::ContextId;
@@ -94,8 +95,9 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u
                 SYS_GETPGID => getpgid(ContextId::from(b)).map(ContextId::into),
                 SYS_GETPPID => getppid().map(ContextId::into),
                 SYS_CLONE => {
+                    let b = CloneFlags::from_bits_truncate(b);
                     let old_rsp = stack.iret.rsp;
-                    if b & flag::CLONE_STACK == flag::CLONE_STACK {
+                    if b.contains(flag::CLONE_STACK) {
                         stack.iret.rsp = c;
                     }
                     let ret = clone(b, bp).map(ContextId::into);
@@ -104,7 +106,7 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u
                 },
                 SYS_EXIT => exit((b & 0xFF) << 8),
                 SYS_KILL => kill(ContextId::from(b), c),
-                SYS_WAITPID => waitpid(ContextId::from(b), c, d).map(ContextId::into),
+                SYS_WAITPID => waitpid(ContextId::from(b), c, WaitFlags::from_bits_truncate(d)).map(ContextId::into),
                 SYS_CHDIR => chdir(validate_slice(b as *const u8, c)?),
                 SYS_IOPL => iopl(b, stack),
                 SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?),
@@ -114,7 +116,7 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u
                 SYS_GETGID => getgid(),
                 SYS_GETNS => getns(),
                 SYS_GETUID => getuid(),
-                SYS_MPROTECT => mprotect(b, c, d),
+                SYS_MPROTECT => mprotect(b, c, MapFlags::from_bits_truncate(d)),
                 SYS_MKNS => mkns(validate_slice(b as *const [usize; 2], c)?),
                 SYS_SETPGID => setpgid(ContextId::from(b), ContextId::from(c)),
                 SYS_SETREUID => setreuid(b as u32, c as u32),
@@ -151,7 +153,7 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u
                 SYS_PIPE2 => pipe2(validate_slice_mut(b as *mut usize, 2)?, c),
                 SYS_PHYSALLOC => physalloc(b),
                 SYS_PHYSFREE => physfree(b, c),
-                SYS_PHYSMAP => physmap(b, c, d),
+                SYS_PHYSMAP => physmap(b, c, PhysmapFlags::from_bits_truncate(d)),
                 SYS_PHYSUNMAP => physunmap(b),
                 SYS_UMASK => umask(b),
                 SYS_VIRTTOPHYS => virttophys(b),
diff --git a/src/syscall/process.rs b/src/syscall/process.rs
index e683b4cfc644beeaff9d50765ad20fd31fcbbbd7..646db9a1a1300cbed5966aea78abdb3fc3c36cf4 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::flag::{CloneFlags, CLONE_VFORK, CLONE_VM, CLONE_FS, CLONE_FILES, CLONE_SIGHAND,
+                           CLONE_STACK, MapFlags, PROT_EXEC, PROT_READ, PROT_WRITE, PTRACE_EVENT_CLONE,
+                           SigActionFlags, SIG_DFL, SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK, SIGCONT, SIGTERM,
+                           WaitFlags, 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();
@@ -67,7 +67,7 @@ pub fn brk(address: usize) -> Result<usize> {
     }
 }
 
-pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
+pub fn clone(flags: CloneFlags, stack_base: usize) -> Result<ContextId> {
     let ppid;
     let pid;
     {
@@ -114,7 +114,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
             sigmask = context.sigmask;
             umask = context.umask;
 
-            if flags & CLONE_VM == CLONE_VM {
+            if flags.contains(CLONE_VM) {
                 cpu_id = context.cpu_id;
             }
 
@@ -155,7 +155,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
                 kstack_option = Some(new_stack);
             }
 
-            if flags & CLONE_VM == CLONE_VM {
+            if flags.contains(CLONE_VM) {
                 for memory_shared in context.image.iter() {
                     image.push(memory_shared.clone());
                 }
@@ -206,7 +206,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
             }
 
             if let Some(ref stack_shared) = context.stack {
-                if flags & CLONE_STACK == CLONE_STACK {
+                if flags.contains(CLONE_STACK) {
                     stack_option = Some(stack_shared.clone());
                 } else {
                     stack_shared.with(|stack| {
@@ -261,7 +261,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
                 };
 
 
-                if flags & CLONE_VM == CLONE_VM {
+                if flags.contains(CLONE_VM) {
                     unsafe {
                         new_tls.load();
                     }
@@ -277,7 +277,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
                 tls_option = Some(new_tls);
             }
 
-            if flags & CLONE_VM == CLONE_VM {
+            if flags.contains(CLONE_VM) {
                 grants = Arc::clone(&context.grants);
             } else {
                 let mut grants_vec = Vec::new();
@@ -288,25 +288,25 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
                 grants = Arc::new(Mutex::new(grants_vec));
             }
 
-            if flags & CLONE_VM == CLONE_VM {
+            if flags.contains(CLONE_VM) {
                 name = Arc::clone(&context.name);
             } else {
                 name = Arc::new(Mutex::new(context.name.lock().clone()));
             }
 
-            if flags & CLONE_FS == CLONE_FS {
+            if flags.contains(CLONE_FS) {
                 cwd = Arc::clone(&context.cwd);
             } else {
                 cwd = Arc::new(Mutex::new(context.cwd.lock().clone()));
             }
 
-            if flags & CLONE_FILES == CLONE_FILES {
+            if flags.contains(CLONE_FILES) {
                 files = Arc::clone(&context.files);
             } else {
                 files = Arc::new(Mutex::new(context.files.lock().clone()));
             }
 
-            if flags & CLONE_SIGHAND == CLONE_SIGHAND {
+            if flags.contains(CLONE_SIGHAND) {
                 actions = Arc::clone(&context.actions);
             } else {
                 actions = Arc::new(Mutex::new(context.actions.lock().clone()));
@@ -315,7 +315,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
 
         // If not cloning files, dup to get a new number from scheme
         // This has to be done outside the context lock to prevent deadlocks
-        if flags & CLONE_FILES == 0 {
+        if !flags.contains(CLONE_FILES) {
             for (_fd, file_option) in files.lock().iter_mut().enumerate() {
                 let new_file_option = if let Some(ref file) = *file_option {
                     Some(FileDescriptor {
@@ -331,7 +331,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
         }
 
         // If not cloning virtual memory, use fmap to re-obtain every grant where possible
-        if flags & CLONE_VM == 0 {
+        if !flags.contains(CLONE_VM) {
             let mut i = 0;
             while i < grants.lock().len() {
                 let remove = false;
@@ -350,7 +350,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
 
         // If vfork, block the current process
         // This has to be done after the operations that may require context switches
-        if flags & CLONE_VFORK == CLONE_VFORK {
+        if flags.contains(CLONE_VFORK) {
             let contexts = context::contexts();
             let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
             let mut context = context_lock.write();
@@ -430,7 +430,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
             // TODO: Clone ksig?
 
             // Setup image, heap, and grants
-            if flags & CLONE_VM == CLONE_VM {
+            if flags.contains(CLONE_VM) {
                 // Copy user image mapping, if found
                 if ! image.is_empty() {
                     let frame = active_table.p4()[crate::USER_PML4].pointed_frame().expect("user image not mapped");
@@ -514,7 +514,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
 
             // Setup user stack
             if let Some(stack_shared) = stack_option {
-                if flags & CLONE_STACK == CLONE_STACK {
+                if flags.contains(CLONE_STACK) {
                     let frame = active_table.p4()[crate::USER_STACK_PML4].pointed_frame().expect("user stack not mapped");
                     let flags = active_table.p4()[crate::USER_STACK_PML4].flags();
                     active_table.with(&mut new_table, &mut temporary_page, |mapper| {
@@ -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();
@@ -860,7 +853,7 @@ fn fexec_noreturn(
                 SigAction {
                     sa_handler: unsafe { mem::transmute(SIG_DFL) },
                     sa_mask: [0; 2],
-                    sa_flags: 0,
+                    sa_flags: SigActionFlags::empty(),
                 },
                 0
             ); 128]));
@@ -1297,7 +1290,7 @@ pub fn kill(pid: ContextId, sig: usize) -> Result<usize> {
     }
 }
 
-pub fn mprotect(address: usize, size: usize, flags: usize) -> Result<usize> {
+pub fn mprotect(address: usize, size: usize, flags: MapFlags) -> Result<usize> {
     println!("mprotect {:#X}, {}, {:#X}", address, size, flags);
 
     let end_offset = size.checked_sub(1).ok_or(Error::new(EFAULT))?;
@@ -1311,19 +1304,19 @@ pub fn mprotect(address: usize, size: usize, flags: usize) -> Result<usize> {
     let end_page = Page::containing_address(VirtualAddress::new(end_address));
     for page in Page::range_inclusive(start_page, end_page) {
         if let Some(mut page_flags) = active_table.translate_page_flags(page) {
-            if flags & PROT_EXEC > 0 {
+            if flags.contains(PROT_EXEC) {
                 page_flags.remove(EntryFlags::NO_EXECUTE);
             } else {
                 page_flags.insert(EntryFlags::NO_EXECUTE);
             }
 
-            if flags & PROT_WRITE > 0 {
+            if flags.contains(PROT_WRITE) {
                 //TODO: Not allowing gain of write privileges
             } else {
                 page_flags.remove(EntryFlags::WRITABLE);
             }
 
-            if flags & PROT_READ > 0 {
+            if flags.contains(PROT_READ) {
                 //TODO: No flags for readable pages
             } else {
                 //TODO: No flags for readable pages
@@ -1475,7 +1468,7 @@ fn reap(pid: ContextId) -> Result<ContextId> {
     Ok(pid)
 }
 
-pub fn waitpid(pid: ContextId, status_ptr: usize, flags: usize) -> Result<ContextId> {
+pub fn waitpid(pid: ContextId, status_ptr: usize, flags: WaitFlags) -> Result<ContextId> {
     let (ppid, waitpid) = {
         let contexts = context::contexts();
         let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
diff --git a/syscall b/syscall
index 9e9f47d2a570c55dd96cd80c83bc818d63cab8af..bf5e138def0f8ad9c4ce87b8eca2d96b57aef8ea 160000
--- a/syscall
+++ b/syscall
@@ -1 +1 @@
-Subproject commit 9e9f47d2a570c55dd96cd80c83bc818d63cab8af
+Subproject commit bf5e138def0f8ad9c4ce87b8eca2d96b57aef8ea