diff --git a/src/context/context.rs b/src/context/context.rs
index b06a397f69d4ad41b6b28fd1ab7e0e0c4503e8bd..adf53455c426b49f26be801894e8c266f6a67860 100644
--- a/src/context/context.rs
+++ b/src/context/context.rs
@@ -10,9 +10,9 @@ use context::file::FileDescriptor;
 use context::memory::{Grant, Memory, SharedMemory, Tls};
 use device;
 use scheme::{SchemeNamespace, FileHandle};
-use syscall::data::{Event, SigAction};
+use syscall::data::SigAction;
 use syscall::flag::SIG_DFL;
-use sync::{WaitMap, WaitQueue};
+use sync::WaitMap;
 
 /// Unique identifier for a context (i.e. `pid`).
 use ::core::sync::atomic::AtomicUsize;
@@ -150,8 +150,6 @@ pub struct Context {
     pub name: Arc<Mutex<Box<[u8]>>>,
     /// The current working directory
     pub cwd: Arc<Mutex<Vec<u8>>>,
-    /// Kernel events
-    pub events: Arc<WaitQueue<Event>>,
     /// The process environment
     pub env: Arc<Mutex<BTreeMap<Box<[u8]>, Arc<Mutex<Vec<u8>>>>>>,
     /// The open files in the scheme
@@ -193,7 +191,6 @@ impl Context {
             grants: Arc::new(Mutex::new(Vec::new())),
             name: Arc::new(Mutex::new(Vec::new().into_boxed_slice())),
             cwd: Arc::new(Mutex::new(Vec::new())),
-            events: Arc::new(WaitQueue::new()),
             env: Arc::new(Mutex::new(BTreeMap::new())),
             files: Arc::new(Mutex::new(Vec::new())),
             actions: Arc::new(Mutex::new(vec![(
diff --git a/src/context/event.rs b/src/context/event.rs
deleted file mode 100644
index fd582f2094a83fa7afe33089f2d548d9a4a47946..0000000000000000000000000000000000000000
--- a/src/context/event.rs
+++ /dev/null
@@ -1,112 +0,0 @@
-use alloc::arc::{Arc, Weak};
-use alloc::BTreeMap;
-use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
-
-use context;
-use scheme::{FileHandle, SchemeId};
-use sync::WaitQueue;
-use syscall::data::Event;
-
-type EventList = Weak<WaitQueue<Event>>;
-
-#[derive(PartialEq, Eq, PartialOrd, Ord)]
-pub struct RegKey {
-    scheme_id: SchemeId,
-    event_id: usize,
-}
-
-#[derive(PartialEq, Eq, PartialOrd, Ord)]
-pub struct ProcessKey {
-    context_id: context::context::ContextId,
-    fd: FileHandle,
-}
-
-type Registry = BTreeMap<RegKey, BTreeMap<ProcessKey, EventList>>;
-
-static REGISTRY: Once<RwLock<Registry>> = Once::new();
-
-/// Initialize registry, called if needed
-fn init_registry() -> RwLock<Registry> {
-    RwLock::new(Registry::new())
-}
-
-/// Get the global schemes list, const
-fn registry() -> RwLockReadGuard<'static, Registry> {
-    REGISTRY.call_once(init_registry).read()
-}
-
-/// Get the global schemes list, mutable
-pub fn registry_mut() -> RwLockWriteGuard<'static, Registry> {
-    REGISTRY.call_once(init_registry).write()
-}
-
-pub fn register(fd: FileHandle, scheme_id: SchemeId, event_id: usize) -> bool {
-    let (context_id, events) = {
-        let contexts = context::contexts();
-        let context_lock = contexts.current().expect("event::register: No context");
-        let context = context_lock.read();
-        (context.id, Arc::downgrade(&context.events))
-    };
-
-    let mut registry = registry_mut();
-    let entry = registry.entry(RegKey {
-        scheme_id: scheme_id,
-        event_id: event_id
-    }).or_insert_with(|| {
-        BTreeMap::new()
-    });
-    let process_key = ProcessKey {
-        context_id: context_id,
-        fd: fd
-    };
-    if entry.contains_key(&process_key) {
-        false
-    } else {
-        entry.insert(process_key, events);
-        true
-    }
-}
-
-pub fn unregister(fd: FileHandle, scheme_id: SchemeId, event_id: usize) {
-    let mut registry = registry_mut();
-
-    let mut remove = false;
-    let key = RegKey {
-        scheme_id: scheme_id,
-        event_id: event_id
-    };
-    if let Some(entry) = registry.get_mut(&key) {
-        let process_key = ProcessKey {
-            context_id: context::context_id(),
-            fd: fd,
-        };
-        entry.remove(&process_key);
-
-        if entry.is_empty() {
-            remove = true;
-        }
-    }
-
-    if remove {
-        registry.remove(&key);
-    }
-}
-
-pub fn trigger(scheme_id: SchemeId, event_id: usize, flags: usize, data: usize) {
-    let registry = registry();
-    let key = RegKey {
-        scheme_id: scheme_id,
-        event_id: event_id
-    };
-    if let Some(event_lists) = registry.get(&key) {
-        for entry in event_lists.iter() {
-            if let Some(event_list) = entry.1.upgrade() {
-                event_list.send(Event {
-                    id: (entry.0).fd.into(),
-                    flags: flags,
-                    data: data
-                });
-            }
-        }
-    }
-}
diff --git a/src/context/file.rs b/src/context/file.rs
index 9c19323e3eba7c47f458c5cec033263758a7404f..222cd37a06191ebd0d029db588b61debf65fdcc4 100644
--- a/src/context/file.rs
+++ b/src/context/file.rs
@@ -1,11 +1,11 @@
 //! File structs
 
 use alloc::arc::Arc;
+use event;
 use spin::RwLock;
 use scheme::{self, SchemeId};
 use syscall::error::{Result, Error, EBADF};
 use scheme::FileHandle;
-use context;
 
 /// A file description
 #[derive(Debug)]
@@ -23,20 +23,17 @@ pub struct FileDescription {
 pub struct FileDescriptor {
     /// Corresponding file description
     pub description: Arc<RwLock<FileDescription>>,
-    /// If events are on, this is the event ID
-    pub event: Option<usize>,
     /// Cloexec flag
     pub cloexec: bool,
 }
 
 impl FileDescriptor {
-    pub fn close(self, fd: FileHandle) -> Result<usize> {
-        if let Some(event_id) = self.event {
-            context::event::unregister(fd, self.description.read().scheme, event_id);
-        }
-
+    pub fn close(self) -> Result<usize> {
         if let Ok(file) = Arc::try_unwrap(self.description) {
             let file = file.into_inner();
+
+            event::unregister_file(file.scheme, file.number);
+
             let scheme = {
                 let schemes = scheme::schemes();
                 let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
diff --git a/src/context/mod.rs b/src/context/mod.rs
index fa2b6969a54764462904bc83ad7191c148866dd7..3902794d1cc93fc528d11eeb8330415263284c1e 100644
--- a/src/context/mod.rs
+++ b/src/context/mod.rs
@@ -21,9 +21,6 @@ mod list;
 /// Context switch function
 mod switch;
 
-/// Event handling
-pub mod event;
-
 /// File struct - defines a scheme and a file number
 pub mod file;
 
diff --git a/src/context/timeout.rs b/src/context/timeout.rs
index 3e5c886e50b5990f06df02f733c19431d3a24682..b6904133f1673d6723e6e03d19088fd42d8320bf 100644
--- a/src/context/timeout.rs
+++ b/src/context/timeout.rs
@@ -1,8 +1,7 @@
 use alloc::vec_deque::VecDeque;
-use core::mem;
 use spin::{Once, Mutex, MutexGuard};
 
-use context::event;
+use event;
 use scheme::SchemeId;
 use syscall::data::TimeSpec;
 use syscall::flag::{CLOCK_MONOTONIC, CLOCK_REALTIME, EVENT_READ};
@@ -65,7 +64,7 @@ pub fn trigger() {
 
         if trigger {
             let timeout = registry.remove(i).unwrap();
-            event::trigger(timeout.scheme_id, timeout.event_id, EVENT_READ, mem::size_of::<TimeSpec>());
+            event::trigger(timeout.scheme_id, timeout.event_id, EVENT_READ);
         } else {
             i += 1;
         }
diff --git a/src/event.rs b/src/event.rs
new file mode 100644
index 0000000000000000000000000000000000000000..063f59f17b31b6f0b2e981225c4bb018841fbc94
--- /dev/null
+++ b/src/event.rs
@@ -0,0 +1,167 @@
+use alloc::arc::Arc;
+use alloc::BTreeMap;
+use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
+use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
+
+use context;
+use scheme::SchemeId;
+use sync::WaitQueue;
+use syscall::data::Event;
+use syscall::error::{Error, Result, EBADF, ESRCH};
+
+int_like!(EventQueueId, AtomicEventQueueId, usize, AtomicUsize);
+
+pub struct EventQueue {
+    id: EventQueueId,
+    queue: WaitQueue<Event>,
+}
+
+impl EventQueue {
+    pub fn new(id: EventQueueId) -> EventQueue {
+        EventQueue {
+            id: id,
+            queue: WaitQueue::new()
+        }
+    }
+
+    pub fn dup(&self, other: &EventQueue) {
+        panic!("EventQeuue::dup");
+    }
+
+    pub fn read(&self, events: &mut [Event]) -> Result<usize> {
+        Ok(self.queue.receive_into(events, true))
+    }
+
+    pub fn write(&self, events: &[Event]) -> Result<usize> {
+        for event in events {
+            let file = {
+                let contexts = context::contexts();
+                let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
+                let context = context_lock.read();
+                let mut files = context.files.lock();
+                match files.get(event.id).ok_or(Error::new(EBADF))? {
+                    Some(file) => file.clone(),
+                    None => return Err(Error::new(EBADF))
+                }
+            };
+
+            let (scheme, number) = {
+                let description = file.description.read();
+                (description.scheme, description.number)
+            };
+
+            register(
+                RegKey { scheme, number },
+                QueueKey { queue: self.id, id: event.id, data: event.data },
+                event.flags
+            );
+        }
+
+        Ok(events.len())
+    }
+}
+
+pub type EventQueueList = BTreeMap<EventQueueId, Arc<EventQueue>>;
+
+// Next queue id
+static NEXT_QUEUE_ID: AtomicUsize = ATOMIC_USIZE_INIT;
+
+/// Get next queue id
+pub fn next_queue_id() -> EventQueueId {
+    EventQueueId::from(NEXT_QUEUE_ID.fetch_add(1, Ordering::SeqCst))
+}
+
+// Current event queues
+static QUEUES: Once<RwLock<EventQueueList>> = Once::new();
+
+/// Initialize queues, called if needed
+fn init_queues() -> RwLock<EventQueueList> {
+    RwLock::new(BTreeMap::new())
+}
+
+/// Get the event queues list, const
+pub fn queues() -> RwLockReadGuard<'static, EventQueueList> {
+    QUEUES.call_once(init_queues).read()
+}
+
+/// Get the event queues list, mutable
+pub fn queues_mut() -> RwLockWriteGuard<'static, EventQueueList> {
+    QUEUES.call_once(init_queues).write()
+}
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub struct RegKey {
+    pub scheme: SchemeId,
+    pub number: usize,
+}
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub struct QueueKey {
+    pub queue: EventQueueId,
+    pub id: usize,
+    pub data: usize
+}
+
+type Registry = BTreeMap<RegKey, BTreeMap<QueueKey, usize>>;
+
+static REGISTRY: Once<RwLock<Registry>> = Once::new();
+
+/// Initialize registry, called if needed
+fn init_registry() -> RwLock<Registry> {
+    RwLock::new(Registry::new())
+}
+
+/// Get the global schemes list, const
+fn registry() -> RwLockReadGuard<'static, Registry> {
+    REGISTRY.call_once(init_registry).read()
+}
+
+/// Get the global schemes list, mutable
+pub fn registry_mut() -> RwLockWriteGuard<'static, Registry> {
+    REGISTRY.call_once(init_registry).write()
+}
+
+pub fn register(reg_key: RegKey, queue_key: QueueKey, flags: usize) {
+    let mut registry = registry_mut();
+
+    let entry = registry.entry(reg_key).or_insert_with(|| {
+        BTreeMap::new()
+    });
+
+    if flags == 0 {
+        entry.remove(&queue_key);
+    } else {
+        entry.insert(queue_key, flags);
+    }
+}
+
+pub fn unregister_file(scheme: SchemeId, number: usize) {
+    let mut registry = registry_mut();
+
+    registry.remove(&RegKey { scheme, number });
+}
+
+//TODO: Implement unregister_queue
+// pub fn unregister_queue(scheme: SchemeId, number: usize) {
+//
+// }
+
+pub fn trigger(scheme: SchemeId, number: usize, flags: usize) {
+    let registry = registry();
+
+    if let Some(queue_list) = registry.get(&RegKey { scheme, number }) {
+        for (queue_key, queue_flags) in queue_list.iter() {
+            let common_flags = flags & queue_flags;
+            if common_flags != 0 {
+                let queues = queues();
+                if let Some(queue) = queues.get(&queue_key.queue) {
+                    queue.queue.send(Event {
+                        id: queue_key.id,
+                        flags: common_flags,
+                        data: queue_key.data
+                    });
+                }
+            }
+        }
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 55e1cbd1329c81bade06bfac57bb4fb6d79e3f86..530377dc0679a8cfd934e1042f9c4903d05e59bf 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -17,7 +17,6 @@
 #![feature(asm)]
 #![feature(collections)]
 #![feature(concat_idents)]
-#![feature(conservative_impl_trait)]
 #![feature(const_atomic_usize_new)]
 #![feature(const_fn)]
 #![feature(const_max_value)]
@@ -83,6 +82,9 @@ pub mod devices;
 #[cfg(not(feature="doc"))]
 pub mod elf;
 
+/// Event handling
+pub mod event;
+
 /// External functions
 pub mod externs;
 
diff --git a/src/scheme/debug.rs b/src/scheme/debug.rs
index aa69f83c08c6d056cf3da15f32a9d1f7ac2cf275..90bf8532ffd9be2e12ccf1f176aa6d11f0242d60 100644
--- a/src/scheme/debug.rs
+++ b/src/scheme/debug.rs
@@ -1,8 +1,8 @@
 use core::sync::atomic::Ordering;
 use spin::Once;
 
-use context;
 use device::serial::COM1;
+use event;
 use scheme::*;
 use sync::WaitQueue;
 use syscall::flag::{EVENT_READ, F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK};
@@ -20,8 +20,8 @@ fn init_input() -> WaitQueue<u8> {
 
 /// Add to the input queue
 pub fn debug_input(b: u8) {
-    let len = INPUT.call_once(init_input).send(b);
-    context::event::trigger(DEBUG_SCHEME_ID.load(Ordering::SeqCst), 0, EVENT_READ, len);
+    INPUT.call_once(init_input).send(b);
+    event::trigger(DEBUG_SCHEME_ID.load(Ordering::SeqCst), 0, EVENT_READ);
 }
 
 pub struct DebugScheme {
diff --git a/src/scheme/event.rs b/src/scheme/event.rs
index 80915e21303291d3d187733b1c15dba99c17bf8b..6efee8b9bd31e5d504e987c11088a8c108adbbde 100644
--- a/src/scheme/event.rs
+++ b/src/scheme/event.rs
@@ -1,75 +1,73 @@
-use alloc::arc::{Arc, Weak};
-use alloc::BTreeMap;
+use alloc::arc::Arc;
 use core::{mem, slice};
-use core::sync::atomic::{AtomicUsize, Ordering};
-use spin::RwLock;
 
-use context;
-use sync::WaitQueue;
+use event::{EventQueue, EventQueueId, next_queue_id, queues, queues_mut};
 use syscall::data::Event;
 use syscall::error::*;
 use syscall::scheme::Scheme;
 
-pub struct EventScheme {
-    next_id: AtomicUsize,
-    handles: RwLock<BTreeMap<usize, Weak<WaitQueue<Event>>>>
-}
-
-impl EventScheme {
-    pub fn new() -> EventScheme {
-        EventScheme {
-            next_id: AtomicUsize::new(0),
-            handles: RwLock::new(BTreeMap::new())
-        }
-    }
-}
+pub struct EventScheme;
 
 impl Scheme for EventScheme {
     fn open(&self, _path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result<usize> {
-        let handle = {
-            let contexts = context::contexts();
-            let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
-            let context = context_lock.read();
-            context.events.clone()
-        };
-
-        let id = self.next_id.fetch_add(1, Ordering::SeqCst);
-        self.handles.write().insert(id, Arc::downgrade(&handle));
+        let id = next_queue_id();
+        queues_mut().insert(id, Arc::new(EventQueue::new(id)));
 
-        Ok(id)
+        Ok(id.into())
     }
 
     fn dup(&self, id: usize, buf: &[u8]) -> Result<usize> {
+        let id = EventQueueId::from(id);
+
         if ! buf.is_empty() {
             return Err(Error::new(EINVAL));
         }
 
-        let handle = {
-            let handles = self.handles.read();
-            let handle_weak = handles.get(&id).ok_or(Error::new(EBADF))?;
-            handle_weak.upgrade().ok_or(Error::new(EBADF))?
+        let old_queue = {
+            let handles = queues();
+            let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
+            handle.clone()
         };
 
-        let new_id = self.next_id.fetch_add(1, Ordering::SeqCst);
-        self.handles.write().insert(new_id, Arc::downgrade(&handle));
-        Ok(new_id)
+        let new_id = next_queue_id();
+        let new_queue = Arc::new(EventQueue::new(new_id));
+        queues_mut().insert(new_id, new_queue.clone());
+        new_queue.dup(&old_queue);
+
+        Ok(new_id.into())
     }
 
     fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
-        let handle = {
-            let handles = self.handles.read();
-            let handle_weak = handles.get(&id).ok_or(Error::new(EBADF))?;
-            handle_weak.upgrade().ok_or(Error::new(EBADF))?
+        let id = EventQueueId::from(id);
+
+        let queue = {
+            let handles = queues();
+            let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
+            handle.clone()
         };
 
         let event_buf = unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut Event, buf.len()/mem::size_of::<Event>()) };
-        Ok(handle.receive_into(event_buf, true) * mem::size_of::<Event>())
+        Ok(queue.read(event_buf)? * mem::size_of::<Event>())
+    }
+
+    fn write(&self, id: usize, buf: &[u8]) -> Result<usize> {
+        let id = EventQueueId::from(id);
+
+        let queue = {
+            let handles = queues();
+            let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
+            handle.clone()
+        };
+
+        let event_buf = unsafe { slice::from_raw_parts(buf.as_ptr() as *const Event, buf.len()/mem::size_of::<Event>()) };
+        Ok(queue.write(event_buf)? * mem::size_of::<Event>())
     }
 
     fn fcntl(&self, id: usize, _cmd: usize, _arg: usize) -> Result<usize> {
-        let handles = self.handles.read();
-        let handle_weak = handles.get(&id).ok_or(Error::new(EBADF))?;
-        handle_weak.upgrade().ok_or(Error::new(EBADF)).and(Ok(0))
+        let id = EventQueueId::from(id);
+
+        let handles = queues();
+        handles.get(&id).ok_or(Error::new(EBADF)).and(Ok(0))
     }
 
     fn fpath(&self, _id: usize, buf: &mut [u8]) -> Result<usize> {
@@ -83,12 +81,14 @@ impl Scheme for EventScheme {
     }
 
     fn fsync(&self, id: usize) -> Result<usize> {
-        let handles = self.handles.read();
-        let handle_weak = handles.get(&id).ok_or(Error::new(EBADF))?;
-        handle_weak.upgrade().ok_or(Error::new(EBADF)).and(Ok(0))
+        let id = EventQueueId::from(id);
+
+        let handles = queues();
+        handles.get(&id).ok_or(Error::new(EBADF)).and(Ok(0))
     }
 
     fn close(&self, id: usize) -> Result<usize> {
-        self.handles.write().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0))
+        let id = EventQueueId::from(id);
+        queues_mut().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0))
     }
 }
diff --git a/src/scheme/irq.rs b/src/scheme/irq.rs
index b5499c8d40f191d8757ab89260a119ece197c375..d48e4c60c134903f6994c942983104ac139de94a 100644
--- a/src/scheme/irq.rs
+++ b/src/scheme/irq.rs
@@ -2,8 +2,8 @@ use core::{mem, str};
 use core::sync::atomic::Ordering;
 use spin::Mutex;
 
+use event;
 use interrupt::irq::acknowledge;
-use context;
 use scheme::{AtomicSchemeId, ATOMIC_SCHEMEID_INIT, SchemeId};
 use syscall::error::*;
 use syscall::flag::EVENT_READ;
@@ -19,7 +19,7 @@ static COUNTS: Mutex<[usize; 16]> = Mutex::new([0; 16]);
 #[no_mangle]
 pub extern fn irq_trigger(irq: u8) {
     COUNTS.lock()[irq as usize] += 1;
-    context::event::trigger(IRQ_SCHEME_ID.load(Ordering::SeqCst), irq as usize, EVENT_READ, mem::size_of::<usize>());
+    event::trigger(IRQ_SCHEME_ID.load(Ordering::SeqCst), irq as usize, EVENT_READ);
 }
 
 pub struct IrqScheme;
diff --git a/src/scheme/mod.rs b/src/scheme/mod.rs
index 96e734066c4fb4dd76d4deb1f09672ad8001c619..d54d655cfa94975daf7d8a25f14d0614a5c711a2 100644
--- a/src/scheme/mod.rs
+++ b/src/scheme/mod.rs
@@ -118,7 +118,7 @@ impl SchemeList {
         self.names.insert(ns, BTreeMap::new());
 
         self.insert(ns, Box::new(*b""), |scheme_id| Arc::new(Box::new(RootScheme::new(ns, scheme_id)))).unwrap();
-        self.insert(ns, Box::new(*b"event"), |_| Arc::new(Box::new(EventScheme::new()))).unwrap();
+        self.insert(ns, Box::new(*b"event"), |_| Arc::new(Box::new(EventScheme))).unwrap();
         self.insert(ns, Box::new(*b"env"), |_| Arc::new(Box::new(EnvScheme::new()))).unwrap();
         self.insert(ns, Box::new(*b"memory"), |_| Arc::new(Box::new(MemoryScheme))).unwrap();
         self.insert(ns, Box::new(*b"sys"), |_| Arc::new(Box::new(SysScheme::new()))).unwrap();
diff --git a/src/scheme/pipe.rs b/src/scheme/pipe.rs
index 0b0154d543139808fb69733472b125039bee336d..d7659b67999995ac5a74df06f999ad397a18b46b 100644
--- a/src/scheme/pipe.rs
+++ b/src/scheme/pipe.rs
@@ -3,7 +3,7 @@ use alloc::{BTreeMap, VecDeque};
 use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
 use spin::{Mutex, Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
 
-use context;
+use event;
 use scheme::{AtomicSchemeId, ATOMIC_SCHEMEID_INIT, SchemeId};
 use sync::WaitCondition;
 use syscall::error::{Error, Result, EAGAIN, EBADF, EINTR, EINVAL, EPIPE, ESPIPE};
@@ -288,17 +288,15 @@ impl PipeWrite {
     fn write(&self, buf: &[u8]) -> Result<usize> {
         if let Some(ref vec_weak) = self.vec {
             if let Some(vec_lock) = vec_weak.upgrade() {
-                let len = {
+                {
                     let mut vec = vec_lock.lock();
 
                     for &b in buf.iter() {
                         vec.push_back(b);
                     }
+                }
 
-                    vec.len()
-                };
-
-                context::event::trigger(self.scheme_id, self.event_id, EVENT_READ, len);
+                event::trigger(self.scheme_id, self.event_id, EVENT_READ);
                 self.condition.notify();
 
                 Ok(buf.len())
@@ -314,7 +312,7 @@ impl PipeWrite {
 impl Drop for PipeWrite {
     fn drop(&mut self) {
         drop(self.vec.take());
-        context::event::trigger(self.scheme_id, self.event_id, EVENT_READ, 0);
+        event::trigger(self.scheme_id, self.event_id, EVENT_READ);
         self.condition.notify();
     }
 }
diff --git a/src/scheme/user.rs b/src/scheme/user.rs
index c26c585debb17dd8217239c8025bfe51d81b8ad4..a24460d86b290c0d08cf35c624d936fe0f8dbdc4 100644
--- a/src/scheme/user.rs
+++ b/src/scheme/user.rs
@@ -5,11 +5,12 @@ use core::sync::atomic::{AtomicU64, Ordering};
 use core::{mem, slice, usize};
 use spin::{Mutex, RwLock};
 
+use context::{self, Context};
+use context::memory::Grant;
+use event;
 use paging::{InactivePageTable, Page, VirtualAddress};
 use paging::entry::EntryFlags;
 use paging::temporary_page::TemporaryPage;
-use context::{self, Context};
-use context::memory::Grant;
 use scheme::{AtomicSchemeId, ATOMIC_SCHEMEID_INIT, SchemeId};
 use sync::{WaitQueue, WaitMap};
 use syscall::data::{Packet, Stat, StatVfs, TimeSpec};
@@ -70,8 +71,8 @@ impl UserInner {
     fn call_inner(&self, packet: Packet) -> Result<usize> {
         let id = packet.id;
 
-        let len = self.todo.send(packet);
-        context::event::trigger(self.root_id, self.handle_id, EVENT_READ, mem::size_of::<Packet>() * len);
+        self.todo.send(packet);
+        event::trigger(self.root_id, self.handle_id, EVENT_READ);
 
         Error::demux(self.done.receive(&id))
     }
@@ -178,7 +179,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 => context::event::trigger(self.scheme_id.load(Ordering::SeqCst), packet.b, packet.c, packet.d),
+                    SYS_FEVENT => event::trigger(self.scheme_id.load(Ordering::SeqCst), packet.b, packet.c),
                     _ => println!("Unknown scheme -> kernel message {}", packet.a)
                 }
             } else {
diff --git a/src/syscall/fs.rs b/src/syscall/fs.rs
index 71e3abfc7becaf3e190dc6b13e73f613e641b9ec..cf2e7e75eb18df5429209f1a35b6729a97bca7ee 100644
--- a/src/syscall/fs.rs
+++ b/src/syscall/fs.rs
@@ -118,7 +118,6 @@ pub fn open(path: &[u8], flags: usize) -> Result<FileHandle> {
             number: file_id,
             flags: flags & !O_CLOEXEC,
         })),
-        event: None,
         cloexec: flags & O_CLOEXEC == O_CLOEXEC,
     }).ok_or(Error::new(EMFILE))
 }
@@ -138,7 +137,6 @@ pub fn pipe2(fds: &mut [usize], flags: usize) -> Result<usize> {
                 number: read_id,
                 flags: O_RDONLY | flags & !O_ACCMODE & !O_CLOEXEC,
             })),
-            event: None,
             cloexec: flags & O_CLOEXEC == O_CLOEXEC,
         }).ok_or(Error::new(EMFILE))?;
 
@@ -148,7 +146,6 @@ pub fn pipe2(fds: &mut [usize], flags: usize) -> Result<usize> {
                 number: write_id,
                 flags: O_WRONLY | flags & !O_ACCMODE & !O_CLOEXEC,
             })),
-            event: None,
             cloexec: flags & O_CLOEXEC == O_CLOEXEC,
         }).ok_or(Error::new(EMFILE))?;
 
@@ -236,7 +233,7 @@ pub fn close(fd: FileHandle) -> Result<usize> {
         context.remove_file(fd).ok_or(Error::new(EBADF))?
     };
 
-    file.close(fd)
+    file.close()
 }
 
 fn duplicate_file(fd: FileHandle, buf: &[u8]) -> Result<FileDescriptor> {
@@ -250,7 +247,6 @@ fn duplicate_file(fd: FileHandle, buf: &[u8]) -> Result<FileDescriptor> {
     if buf.is_empty() {
         Ok(FileDescriptor {
             description: Arc::clone(&file.description),
-            event: None,
             cloexec: false,
         })
     } else {
@@ -271,7 +267,6 @@ fn duplicate_file(fd: FileHandle, buf: &[u8]) -> Result<FileDescriptor> {
                 number: new_id,
                 flags: description.flags,
             })),
-            event: None,
             cloexec: false,
         })
     }
@@ -378,44 +373,7 @@ pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize) -> Result<usize> {
 
 /// Register events for file
 pub fn fevent(fd: FileHandle, flags: usize) -> Result<usize> {
-    let file = {
-        let contexts = context::contexts();
-        let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
-        let context = context_lock.read();
-        let mut files = context.files.lock();
-        match *files.get_mut(fd.into()).ok_or(Error::new(EBADF))? {
-            Some(ref mut file) => {
-                let description = file.description.read();
-                if let Some(event_id) = file.event.take() {
-                    println!("{:?}: {:?}:{}: events already registered: {}", fd, description.scheme, description.number, event_id);
-                    context::event::unregister(fd, description.scheme, event_id);
-                }
-                file.clone()
-            },
-            None => return Err(Error::new(EBADF))
-        }
-    };
-
-    let description = file.description.read();
-
-    let scheme = {
-        let schemes = scheme::schemes();
-        let scheme = schemes.get(description.scheme).ok_or(Error::new(EBADF))?;
-        Arc::clone(&scheme)
-    };
-    let event_id = scheme.fevent(description.number, flags)?;
-    {
-        let contexts = context::contexts();
-        let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
-        let context = context_lock.read();
-        let mut files = context.files.lock();
-        match *files.get_mut(fd.into()).ok_or(Error::new(EBADF))? {
-            Some(ref mut file) => file.event = Some(event_id),
-            None => return Err(Error::new(EBADF)),
-        }
-    }
-    context::event::register(fd, description.scheme, event_id);
-    Ok(0)
+    Err(Error::new(ENOSYS))
 }
 
 pub fn frename(fd: FileHandle, path: &[u8]) -> Result<usize> {
diff --git a/src/syscall/process.rs b/src/syscall/process.rs
index 227853a8239d78ea5690f37f00de512e95c80996..362b7359fb5c9e897551abdb461318257871dac0 100644
--- a/src/syscall/process.rs
+++ b/src/syscall/process.rs
@@ -296,7 +296,6 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
                 let new_file_option = if let Some(ref file) = *file_option {
                     Some(FileDescriptor {
                         description: Arc::clone(&file.description),
-                        event: None,
                         cloexec: file.cloexec,
                     })
                 } else {
@@ -755,7 +754,7 @@ fn exec_noreturn(
             }
 
             if cloexec {
-                let _ = file_option.take().unwrap().close(FileHandle::from(fd));
+                let _ = file_option.take().unwrap().close();
             }
         }
 
@@ -933,7 +932,7 @@ pub fn exit(status: usize) -> ! {
         // Files must be closed while context is valid so that messages can be passed
         for (fd, file_option) in close_files.drain(..).enumerate() {
             if let Some(file) = file_option {
-                let _ = file.close(FileHandle::from(fd));
+                let _ = file.close();
             }
         }