diff --git a/context/event.rs b/context/event.rs
index 19d119d369e459a36dec01be93bc862d5b6faa2d..a42ecef2cb221f6877aa587bb49740c44ec508ef 100644
--- a/context/event.rs
+++ b/context/event.rs
@@ -27,7 +27,7 @@ pub fn registry_mut() -> RwLockWriteGuard<'static, Registry> {
     REGISTRY.call_once(init_registry).write()
 }
 
-pub fn register(fd: usize, scheme_id: usize, id: usize) -> bool {
+pub fn register(fd: usize, scheme_id: usize, event_id: usize) -> bool {
     let (context_id, events) = {
         let contexts = context::contexts();
         let context_lock = contexts.current().expect("event::register: No context");
@@ -36,7 +36,7 @@ pub fn register(fd: usize, scheme_id: usize, id: usize) -> bool {
     };
 
     let mut registry = registry_mut();
-    let entry = registry.entry((scheme_id, id)).or_insert_with(|| {
+    let entry = registry.entry((scheme_id, event_id)).or_insert_with(|| {
         BTreeMap::new()
     });
     if entry.contains_key(&(context_id, fd)) {
@@ -47,11 +47,11 @@ pub fn register(fd: usize, scheme_id: usize, id: usize) -> bool {
     }
 }
 
-pub fn unregister(fd: usize, scheme_id: usize, id: usize) {
+pub fn unregister(fd: usize, scheme_id: usize, event_id: usize) {
     let mut registry = registry_mut();
 
     let mut remove = false;
-    if let Some(entry) = registry.get_mut(&(scheme_id, id)) {
+    if let Some(entry) = registry.get_mut(&(scheme_id, event_id)) {
         entry.remove(&(context::context_id(), fd));
 
         if entry.is_empty() {
@@ -60,13 +60,13 @@ pub fn unregister(fd: usize, scheme_id: usize, id: usize) {
     }
 
     if remove {
-        registry.remove(&(scheme_id, id));
+        registry.remove(&(scheme_id, event_id));
     }
 }
 
-pub fn trigger(scheme_id: usize, id: usize, flags: usize, data: usize) {
+pub fn trigger(scheme_id: usize, event_id: usize, flags: usize, data: usize) {
     let registry = registry();
-    if let Some(event_lists) = registry.get(&(scheme_id, id)) {
+    if let Some(event_lists) = registry.get(&(scheme_id, event_id)) {
         for entry in event_lists.iter() {
             if let Some(event_list) = entry.1.upgrade() {
                 event_list.send(Event {
diff --git a/context/file.rs b/context/file.rs
index 67a28eb86cfd7ccf9cf92b08c4c928ea1d36e79f..d9238d696df8849fb299d1d763f977811d8a47d1 100644
--- a/context/file.rs
+++ b/context/file.rs
@@ -8,4 +8,6 @@ pub struct File {
     pub scheme: usize,
     /// The number the scheme uses to refer to this file
     pub number: usize,
+    /// If events are on, this is the event ID
+    pub event: Option<usize>,
 }
diff --git a/scheme/irq.rs b/scheme/irq.rs
index 2ed891e0f60e2b6bc057cfc8997c494dbb372ed5..ce99c42335bcded79be69874b9e602385b5f3680 100644
--- a/scheme/irq.rs
+++ b/scheme/irq.rs
@@ -93,8 +93,8 @@ impl Scheme for IrqScheme {
         }
     }
 
-    fn fevent(&self, _file: usize, _flags: usize) -> Result<usize> {
-        Ok(0)
+    fn fevent(&self, file: usize, _flags: usize) -> Result<usize> {
+        Ok(file)
     }
 
     fn fsync(&self, _file: usize) -> Result<usize> {
diff --git a/scheme/root.rs b/scheme/root.rs
index 1d4d4d0495c783b2b1508de9a73e1545638964f1..57877bf8f6768256addf89cd184a6c41086b8044 100644
--- a/scheme/root.rs
+++ b/scheme/root.rs
@@ -89,8 +89,8 @@ impl Scheme for RootScheme {
         inner.write(buf)
     }
 
-    fn fevent(&self, _file: usize, _flags: usize) -> Result<usize> {
-        Ok(0)
+    fn fevent(&self, file: usize, _flags: usize) -> Result<usize> {
+        Ok(file)
     }
 
     fn fsync(&self, _file: usize) -> Result<usize> {
diff --git a/syscall/fs.rs b/syscall/fs.rs
index fb06884e19a5e4713698886f63be7bd790f76273..6c953e468f2caf6a272a4409c03a0122f9aaea87 100644
--- a/syscall/fs.rs
+++ b/syscall/fs.rs
@@ -98,7 +98,8 @@ pub fn open(path: &[u8], flags: usize) -> Result<usize> {
     let context = context_lock.read();
     context.add_file(::context::file::File {
         scheme: scheme_id,
-        number: file_id
+        number: file_id,
+        event: None,
     }).ok_or(Error::new(EMFILE))
 }
 
@@ -113,12 +114,14 @@ pub fn pipe2(fds: &mut [usize], flags: usize) -> Result<usize> {
 
         let read_fd = context.add_file(::context::file::File {
             scheme: scheme_id,
-            number: read_id
+            number: read_id,
+            event: None,
         }).ok_or(Error::new(EMFILE))?;
 
         let write_fd = context.add_file(::context::file::File {
             scheme: scheme_id,
-            number: write_id
+            number: write_id,
+            event: None,
         }).ok_or(Error::new(EMFILE))?;
 
         fds[0] = read_fd;
@@ -206,7 +209,9 @@ pub fn close(fd: usize) -> Result<usize> {
         file
     };
 
-    context::event::unregister(fd, file.scheme, file.number);
+    if let Some(event_id) = file.event {
+        context::event::unregister(fd, file.scheme, event_id);
+    }
 
     let scheme = {
         let schemes = scheme::schemes();
@@ -240,7 +245,8 @@ pub fn dup(fd: usize) -> Result<usize> {
     let context = context_lock.read();
     context.add_file(::context::file::File {
         scheme: file.scheme,
-        number: new_id
+        number: new_id,
+        event: None,
     }).ok_or(Error::new(EMFILE))
 }
 
@@ -250,8 +256,13 @@ pub fn fevent(fd: usize, flags: usize) -> Result<usize> {
         let contexts = context::contexts();
         let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
         let context = context_lock.read();
-        let file = context.get_file(fd).ok_or(Error::new(EBADF))?;
-        file
+        let mut files = context.files.lock();
+        let mut file = files.get_mut(fd).ok_or(Error::new(EBADF))?.ok_or(Error::new(EBADF))?;
+        if let Some(event_id) = file.event.take() {
+            println!("{}: {}:{}: events already registered: {}", fd, file.scheme, file.number, event_id);
+            context::event::unregister(fd, file.scheme, event_id);
+        }
+        file.clone()
     };
 
     let scheme = {
@@ -259,7 +270,15 @@ pub fn fevent(fd: usize, flags: usize) -> Result<usize> {
         let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
         scheme.clone()
     };
-    scheme.fevent(file.number, flags)?;
-    context::event::register(fd, file.scheme, file.number);
+    let event_id = scheme.fevent(file.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();
+        let mut file = files.get_mut(fd).ok_or(Error::new(EBADF))?.ok_or(Error::new(EBADF))?;
+        file.event = Some(event_id);
+    }
+    context::event::register(fd, file.scheme, event_id);
     Ok(0)
 }
diff --git a/syscall/process.rs b/syscall/process.rs
index 5763c891568c1f9828d0e7e5928663af902b0b9e..ddd2cec9865eeab68e5d0dad9aad728ef8844046 100644
--- a/syscall/process.rs
+++ b/syscall/process.rs
@@ -232,7 +232,11 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
                     };
                     match result {
                         Ok(new_number) => {
-                            Some(context::file::File { scheme: file.scheme, number: new_number })
+                            Some(context::file::File {
+                                scheme: file.scheme,
+                                number: new_number,
+                                event: None,
+                            })
                         },
                         Err(err) => {
                             println!("clone: failed to dup {}: {:?}", fd, err);
@@ -616,7 +620,9 @@ 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 {
-                context::event::unregister(fd, file.scheme, file.number);
+                if let Some(event_id) = file.event {
+                    context::event::unregister(fd, file.scheme, event_id);
+                }
 
                 let scheme_option = {
                     let schemes = scheme::schemes();