diff --git a/kernel/common/int_like.rs b/kernel/common/int_like.rs
new file mode 100644
index 0000000000000000000000000000000000000000..10f84238d6569ebd934c1e4f4cb9c9fb36e45ce1
--- /dev/null
+++ b/kernel/common/int_like.rs
@@ -0,0 +1,108 @@
+//! Helpers used to define types that are backed by integers (typically `usize`),
+//! without compromising safety.
+//!
+//! # Example
+//!
+//! ```
+//! /// Define an opaque type `Pid` backed by a `usize`.
+//! int_like!(Pid, usize);
+//!
+//! const ZERO: Pid = Pid::from(0);
+//! ```
+//!
+//! # Example
+//!
+//! ```
+//! /// Define opaque types `Pid` and `AtomicPid`, backed respectively by a `usize`
+//! /// and a `AtomicUsize`.
+//!
+//! int_like!(Pid, AtomicPid, usize, AtomicUsize);
+//!
+//! const ZERO: Pid = Pid::from(0);
+//! let ATOMIC_PID: AtomicPid = AtomicPid::default();
+//! ```
+
+#[macro_export]
+macro_rules! int_like {
+    ($new_type_name:ident, $backing_type: ident) => {
+        #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
+        pub struct $new_type_name($backing_type);
+
+        impl $new_type_name {
+            pub const fn into(self) -> $backing_type {
+                self.0
+            }
+            pub const fn from(x: $backing_type) -> Self {
+                $new_type_name(x)
+            }
+        }
+    };
+
+    ($new_type_name:ident, $new_atomic_type_name: ident, $backing_type:ident, $backing_atomic_type:ident) => {
+        int_like!($new_type_name, $backing_type);
+
+        /// A mutable holder for T that can safely be shared among threads.
+        /// Runtime equivalent to using `AtomicUsize`, just type-safer.
+        pub struct $new_atomic_type_name {
+            container: $backing_atomic_type,
+        }
+
+        impl $new_atomic_type_name {
+            pub const fn new(x: $new_type_name) -> Self {
+                $new_atomic_type_name {
+                    container: $backing_atomic_type::new(x.into())
+                }
+            }
+            pub const fn default() -> Self {
+                Self::new($new_type_name::from(0))
+            }
+            pub fn load(&self, order: ::core::sync::atomic::Ordering) -> $new_type_name {
+                $new_type_name::from(self.container.load(order))
+            }
+            pub fn store(&self, val: $new_type_name, order: ::core::sync::atomic::Ordering) {
+                self.container.store(val.into(), order)
+            }
+            #[allow(dead_code)]
+            pub fn swap(&self, val: $new_type_name, order: ::core::sync::atomic::Ordering) -> $new_type_name {
+                $new_type_name::from(self.container.swap(val.into(), order))
+            }
+            #[allow(dead_code)]
+            pub fn compare_and_swap(&self, current: $new_type_name, new: $new_type_name, order: ::core::sync::atomic::Ordering) -> $new_type_name {
+                $new_type_name::from(self.container.compare_and_swap(current.into(), new.into(), order))
+            }
+            #[allow(dead_code)]
+            pub fn compare_exchange(&self, current: $new_type_name, new: $new_type_name, success: ::core::sync::atomic::Ordering, failure: ::core::sync::atomic::Ordering) -> ::core::result::Result<$new_type_name, $new_type_name> {
+                match self.container.compare_exchange(current.into(), new.into(), success, failure) {
+                    Ok(result) => Ok($new_type_name::from(result)),
+                    Err(result) => Err($new_type_name::from(result))
+                }
+            }
+            #[allow(dead_code)]
+            pub fn compare_exchange_weak(&self, current: $new_type_name, new: $new_type_name, success: ::core::sync::atomic::Ordering, failure: ::core::sync::atomic::Ordering) -> ::core::result::Result<$new_type_name, $new_type_name> {
+                match self.container.compare_exchange_weak(current.into(), new.into(), success, failure) {
+                    Ok(result) => Ok($new_type_name::from(result)),
+                    Err(result) => Err($new_type_name::from(result))
+                }
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+fn test() {
+    use core::mem::size_of;
+    use ::core::sync::atomic::AtomicUsize;
+
+    // Generate type `usize_like`.
+    int_like!(UsizeLike, usize);
+    const ZERO: UsizeLike = UsizeLike::from(0);
+    assert_eq!(size_of::<UsizeLike>(), size_of::<usize>());
+
+
+    // Generate types `usize_like` and `AtomicUsize`.
+    int_like!(UsizeLike2, AtomicUsizeLike, usize, AtomicUsize);
+    assert_eq!(size_of::<UsizeLike2>(), size_of::<usize>());
+    assert_eq!(size_of::<AtomicUsizeLike>(), size_of::<AtomicUsize>());
+}
+
+
diff --git a/kernel/common/mod.rs b/kernel/common/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..62c5921bdbfd28e92245e555ad9ad9814686ec5a
--- /dev/null
+++ b/kernel/common/mod.rs
@@ -0,0 +1,3 @@
+#[macro_use]
+#[macro_export]
+pub mod int_like;
diff --git a/kernel/context/context.rs b/kernel/context/context.rs
index 4df574f9e80d0ac6210fc77d0f8b267488682a14..f80f67574ef81ee26bdb9ec5aa1a56f0346b21f2 100644
--- a/kernel/context/context.rs
+++ b/kernel/context/context.rs
@@ -6,9 +6,14 @@ use spin::Mutex;
 use arch;
 use context::file::File;
 use context::memory::{Grant, Memory, SharedMemory, Tls};
+use scheme::FileHandle;
 use syscall::data::Event;
 use sync::{WaitMap, WaitQueue};
 
+/// Unique identifier for a context (i.e. `pid`).
+use ::core::sync::atomic::AtomicUsize;
+int_like!(ContextId, AtomicContextId, usize, AtomicUsize);
+
 /// The status of a context - used for scheduling
 /// See syscall::process::waitpid and the sync module for examples of usage
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
@@ -22,9 +27,9 @@ pub enum Status {
 #[derive(Debug)]
 pub struct Context {
     /// The ID of this context
-    pub id: usize,
+    pub id: ContextId,
     /// The ID of the parent context
-    pub ppid: usize,
+    pub ppid: ContextId,
     /// The real user id
     pub ruid: u32,
     /// The real group id
@@ -42,7 +47,7 @@ pub struct Context {
     /// Context is halting parent
     pub vfork: bool,
     /// Context is being waited on
-    pub waitpid: Arc<WaitMap<usize, usize>>,
+    pub waitpid: Arc<WaitMap<ContextId, usize>>,
     /// Context should wake up at specified time
     pub wake: Option<(u64, u64)>,
     /// The architecture specific context
@@ -75,10 +80,10 @@ pub struct Context {
 
 impl Context {
     /// Create a new context
-    pub fn new(id: usize) -> Context {
+    pub fn new(id: ContextId) -> Context {
         Context {
             id: id,
-            ppid: 0,
+            ppid: ContextId::from(0),
             ruid: 0,
             rgid: 0,
             euid: 0,
@@ -180,28 +185,28 @@ impl Context {
 
     /// Add a file to the lowest available slot.
     /// Return the file descriptor number or None if no slot was found
-    pub fn add_file(&self, file: File) -> Option<usize> {
+    pub fn add_file(&self, file: File) -> Option<FileHandle> {
         let mut files = self.files.lock();
         for (i, mut file_option) in files.iter_mut().enumerate() {
             if file_option.is_none() {
                 *file_option = Some(file);
-                return Some(i);
+                return Some(FileHandle::from(i));
             }
         }
         let len = files.len();
         if len < super::CONTEXT_MAX_FILES {
             files.push(Some(file));
-            Some(len)
+            Some(FileHandle::from(len))
         } else {
             None
         }
     }
 
     /// Get a file
-    pub fn get_file(&self, i: usize) -> Option<File> {
+    pub fn get_file(&self, i: FileHandle) -> Option<File> {
         let files = self.files.lock();
-        if i < files.len() {
-            files[i]
+        if i.into() < files.len() {
+            files[i.into()]
         } else {
             None
         }
@@ -209,10 +214,10 @@ impl Context {
 
     /// Remove a file
     // TODO: adjust files vector to smaller size if possible
-    pub fn remove_file(&self, i: usize) -> Option<File> {
+    pub fn remove_file(&self, i: FileHandle) -> Option<File> {
         let mut files = self.files.lock();
-        if i < files.len() {
-            files[i].take()
+        if i.into() < files.len() {
+            files[i.into()].take()
         } else {
             None
         }
diff --git a/kernel/context/event.rs b/kernel/context/event.rs
index 2ece46609dafb1055435307a5a51e28c679c6e3f..c6c9431be24fd56f65d8bf91be58953aeaf3ce84 100644
--- a/kernel/context/event.rs
+++ b/kernel/context/event.rs
@@ -3,6 +3,7 @@ use collections::BTreeMap;
 use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
 
 use context;
+use scheme::{FileHandle, SchemeId};
 use sync::WaitQueue;
 use syscall::data::Event;
 
@@ -10,14 +11,14 @@ type EventList = Weak<WaitQueue<Event>>;
 
 #[derive(PartialEq, Eq, PartialOrd, Ord)]
 pub struct RegKey {
-    scheme_id: usize,
+    scheme_id: SchemeId,
     event_id: usize,
 }
 
 #[derive(PartialEq, Eq, PartialOrd, Ord)]
 pub struct ProcessKey {
-    context_id: usize,
-    fd: usize,
+    context_id: context::context::ContextId,
+    fd: FileHandle,
 }
 
 type Registry = BTreeMap<RegKey, BTreeMap<ProcessKey, EventList>>;
@@ -39,7 +40,7 @@ pub fn registry_mut() -> RwLockWriteGuard<'static, Registry> {
     REGISTRY.call_once(init_registry).write()
 }
 
-pub fn register(fd: usize, scheme_id: usize, event_id: usize) -> bool {
+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");
@@ -66,7 +67,7 @@ pub fn register(fd: usize, scheme_id: usize, event_id: usize) -> bool {
     }
 }
 
-pub fn unregister(fd: usize, scheme_id: usize, event_id: usize) {
+pub fn unregister(fd: FileHandle, scheme_id: SchemeId, event_id: usize) {
     let mut registry = registry_mut();
 
     let mut remove = false;
@@ -91,7 +92,7 @@ pub fn unregister(fd: usize, scheme_id: usize, event_id: usize) {
     }
 }
 
-pub fn trigger(scheme_id: usize, event_id: usize, flags: usize, data: usize) {
+pub fn trigger(scheme_id: SchemeId, event_id: usize, flags: usize, data: usize) {
     let registry = registry();
     let key = RegKey {
         scheme_id: scheme_id,
@@ -101,7 +102,7 @@ pub fn trigger(scheme_id: usize, event_id: usize, flags: usize, data: usize) {
         for entry in event_lists.iter() {
             if let Some(event_list) = entry.1.upgrade() {
                 event_list.send(Event {
-                    id: (entry.0).fd,
+                    id: (entry.0).fd.into(),
                     flags: flags,
                     data: data
                 });
diff --git a/kernel/context/file.rs b/kernel/context/file.rs
index d9238d696df8849fb299d1d763f977811d8a47d1..26e0863cb8ae21176540a8eeaca27531f36d6bfb 100644
--- a/kernel/context/file.rs
+++ b/kernel/context/file.rs
@@ -1,11 +1,13 @@
 //! File struct
 
+use scheme::SchemeId;
+
 /// A file
 //TODO: Close on exec
 #[derive(Copy, Clone, Debug)]
 pub struct File {
     /// The scheme that this file refers to
-    pub scheme: usize,
+    pub scheme: SchemeId,
     /// The number the scheme uses to refer to this file
     pub number: usize,
     /// If events are on, this is the event ID
diff --git a/kernel/context/list.rs b/kernel/context/list.rs
index 5541efac4cb782989219faefbbfd11b326816856..11c25c221015b23169d596d41d5c901a3c947b78 100644
--- a/kernel/context/list.rs
+++ b/kernel/context/list.rs
@@ -7,11 +7,11 @@ use spin::RwLock;
 
 use arch;
 use syscall::error::{Result, Error, EAGAIN};
-use super::context::Context;
+use super::context::{Context, ContextId};
 
 /// Context list type
 pub struct ContextList {
-    map: BTreeMap<usize, Arc<RwLock<Context>>>,
+    map: BTreeMap<ContextId, Arc<RwLock<Context>>>,
     next_id: usize
 }
 
@@ -25,7 +25,7 @@ impl ContextList {
     }
 
     /// Get the nth context.
-    pub fn get(&self, id: usize) -> Option<&Arc<RwLock<Context>>> {
+    pub fn get(&self, id: ContextId) -> Option<&Arc<RwLock<Context>>> {
         self.map.get(&id)
     }
 
@@ -34,7 +34,7 @@ impl ContextList {
         self.map.get(&super::CONTEXT_ID.load(Ordering::SeqCst))
     }
 
-    pub fn iter(&self) -> ::collections::btree_map::Iter<usize, Arc<RwLock<Context>>> {
+    pub fn iter(&self) -> ::collections::btree_map::Iter<ContextId, Arc<RwLock<Context>>> {
         self.map.iter()
     }
 
@@ -44,7 +44,7 @@ impl ContextList {
             self.next_id = 1;
         }
 
-        while self.map.contains_key(&self.next_id) {
+        while self.map.contains_key(&ContextId::from(self.next_id)) {
             self.next_id += 1;
         }
 
@@ -52,7 +52,7 @@ impl ContextList {
             return Err(Error::new(EAGAIN));
         }
 
-        let id = self.next_id;
+        let id = ContextId::from(self.next_id);
         self.next_id += 1;
 
         assert!(self.map.insert(id, Arc::new(RwLock::new(Context::new(id)))).is_none());
@@ -85,7 +85,7 @@ impl ContextList {
         Ok(context_lock)
     }
 
-    pub fn remove(&mut self, id: usize) -> Option<Arc<RwLock<Context>>> {
+    pub fn remove(&mut self, id: ContextId) -> Option<Arc<RwLock<Context>>> {
         self.map.remove(&id)
     }
 }
diff --git a/kernel/context/mod.rs b/kernel/context/mod.rs
index d787eff4c2a07e6ee2b23d1edf619f9fa24514af..2b1214c931d13d29e45e77e5b8463d18bb473e7c 100644
--- a/kernel/context/mod.rs
+++ b/kernel/context/mod.rs
@@ -1,11 +1,12 @@
 //! Context management
 use alloc::boxed::Box;
-use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+use core::sync::atomic::Ordering;
 use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
 
 pub use self::context::{Context, Status};
 pub use self::list::ContextList;
 pub use self::switch::switch;
+pub use context::context::ContextId;
 
 /// Context struct
 mod context;
@@ -35,7 +36,7 @@ pub const CONTEXT_MAX_FILES: usize = 65536;
 static CONTEXTS: Once<RwLock<ContextList>> = Once::new();
 
 #[thread_local]
-static CONTEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT;
+static CONTEXT_ID: context::AtomicContextId = context::AtomicContextId::default();
 
 pub fn init() {
     let mut contexts = contexts_mut();
@@ -69,6 +70,6 @@ pub fn contexts_mut() -> RwLockWriteGuard<'static, ContextList> {
     CONTEXTS.call_once(init_contexts).write()
 }
 
-pub fn context_id() -> usize {
+pub fn context_id() -> context::ContextId {
     CONTEXT_ID.load(Ordering::SeqCst)
 }
diff --git a/kernel/lib.rs b/kernel/lib.rs
index b1daafc5c540f875081f18a7adbe3d7555fe170c..193e4c2973e9c336a321af4a6d9e4dbdae2956b4 100644
--- a/kernel/lib.rs
+++ b/kernel/lib.rs
@@ -43,6 +43,12 @@ extern crate goblin;
 extern crate spin;
 
 use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+use scheme::FileHandle;
+
+#[macro_use]
+#[macro_export]
+/// Shared data structures
+pub mod common;
 
 /// Context management
 pub mod context;
@@ -87,9 +93,9 @@ pub fn cpu_count() -> usize {
 pub extern fn userspace_init() {
     assert_eq!(syscall::chdir(b"initfs:bin"), Ok(0));
 
-    assert_eq!(syscall::open(b"debug:", 0), Ok(0));
-    assert_eq!(syscall::open(b"debug:", 0), Ok(1));
-    assert_eq!(syscall::open(b"debug:", 0), Ok(2));
+    assert_eq!(syscall::open(b"debug:", 0).map(FileHandle::into), Ok(0));
+    assert_eq!(syscall::open(b"debug:", 0).map(FileHandle::into), Ok(1));
+    assert_eq!(syscall::open(b"debug:", 0).map(FileHandle::into), Ok(2));
 
     syscall::exec(b"initfs:bin/init", &[]).expect("failed to execute initfs:init");
 
@@ -99,7 +105,7 @@ pub extern fn userspace_init() {
 /// Allow exception handlers to send signal to arch-independant kernel
 #[no_mangle]
 pub extern fn ksignal(signal: usize) {
-    println!("SIGNAL {}, CPU {}, PID {}", signal, cpu_id(), context::context_id());
+    println!("SIGNAL {}, CPU {}, PID {:?}", signal, cpu_id(), context::context_id());
     {
         let contexts = context::contexts();
         if let Some(context_lock) = contexts.current() {
diff --git a/kernel/scheme/debug.rs b/kernel/scheme/debug.rs
index 8a8f556a8e47c15de9b74eee2c89ae792c21b14c..f4b88db352206a270da91b7a9be0e4cc598676ed 100644
--- a/kernel/scheme/debug.rs
+++ b/kernel/scheme/debug.rs
@@ -1,14 +1,15 @@
 use core::str;
-use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
+use core::sync::atomic::Ordering;
 use spin::Once;
 
 use context;
+use scheme::*;
 use sync::WaitQueue;
 use syscall::error::*;
 use syscall::flag::EVENT_READ;
 use syscall::scheme::Scheme;
 
-pub static DEBUG_SCHEME_ID: AtomicUsize = ATOMIC_USIZE_INIT;
+pub static DEBUG_SCHEME_ID: AtomicSchemeId = ATOMIC_SCHEMEID_INIT;
 
 /// Input queue
 static INPUT: Once<WaitQueue<u8>> = Once::new();
diff --git a/kernel/scheme/irq.rs b/kernel/scheme/irq.rs
index a20aca71c39efa570a3744a348659e8b4c6c9f93..bde521d81f6f453f003f884a719337dbd97bc107 100644
--- a/kernel/scheme/irq.rs
+++ b/kernel/scheme/irq.rs
@@ -1,14 +1,15 @@
 use core::{mem, str};
-use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+use core::sync::atomic::Ordering;
 use spin::Mutex;
 
 use arch::interrupt::irq::acknowledge;
 use context;
+use scheme::{AtomicSchemeId, ATOMIC_SCHEMEID_INIT};
 use syscall::error::*;
 use syscall::flag::EVENT_READ;
 use syscall::scheme::Scheme;
 
-pub static IRQ_SCHEME_ID: AtomicUsize = ATOMIC_USIZE_INIT;
+pub static IRQ_SCHEME_ID: AtomicSchemeId = ATOMIC_SCHEMEID_INIT;
 
 /// IRQ queues
 static ACKS: Mutex<[usize; 16]> = Mutex::new([0; 16]);
diff --git a/kernel/scheme/mod.rs b/kernel/scheme/mod.rs
index 58aaa8e6d3f2ccb14c29c9408c6e64ef7af93c02..c1ad0cbbb58776b939eabfe9809b354cd1037e96 100644
--- a/kernel/scheme/mod.rs
+++ b/kernel/scheme/mod.rs
@@ -9,7 +9,7 @@
 use alloc::arc::Arc;
 use alloc::boxed::Box;
 use collections::BTreeMap;
-use core::sync::atomic::Ordering;
+use core::sync::atomic::{AtomicUsize, Ordering};
 use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
 
 use syscall::error::*;
@@ -62,10 +62,19 @@ pub mod zero;
 /// Limit on number of schemes
 pub const SCHEME_MAX_SCHEMES: usize = 65536;
 
+/// Unique identifier for a scheme.
+int_like!(SchemeId, AtomicSchemeId, usize, AtomicUsize);
+
+pub const ATOMIC_SCHEMEID_INIT: AtomicSchemeId = AtomicSchemeId::default();
+
+/// Unique identifier for a file descriptor.
+int_like!(FileHandle, AtomicFileHandle, usize, AtomicUsize);
+
+
 /// Scheme list type
 pub struct SchemeList {
-    map: BTreeMap<usize, Arc<Box<Scheme + Send + Sync>>>,
-    names: BTreeMap<Box<[u8]>, usize>,
+    map: BTreeMap<SchemeId, Arc<Box<Scheme + Send + Sync>>>,
+    names: BTreeMap<Box<[u8]>, SchemeId>,
     next_id: usize
 }
 
@@ -79,20 +88,20 @@ impl SchemeList {
         }
     }
 
-    pub fn iter(&self) -> ::collections::btree_map::Iter<usize, Arc<Box<Scheme + Send + Sync>>> {
+    pub fn iter(&self) -> ::collections::btree_map::Iter<SchemeId, Arc<Box<Scheme + Send + Sync>>> {
         self.map.iter()
     }
 
-    pub fn iter_name(&self) -> ::collections::btree_map::Iter<Box<[u8]>, usize> {
+    pub fn iter_name(&self) -> ::collections::btree_map::Iter<Box<[u8]>, SchemeId> {
         self.names.iter()
     }
 
     /// Get the nth scheme.
-    pub fn get(&self, id: usize) -> Option<&Arc<Box<Scheme + Send + Sync>>> {
+    pub fn get(&self, id: SchemeId) -> Option<&Arc<Box<Scheme + Send + Sync>>> {
         self.map.get(&id)
     }
 
-    pub fn get_name(&self, name: &[u8]) -> Option<(usize, &Arc<Box<Scheme + Send + Sync>>)> {
+    pub fn get_name(&self, name: &[u8]) -> Option<(SchemeId, &Arc<Box<Scheme + Send + Sync>>)> {
         if let Some(&id) = self.names.get(name) {
             self.get(id).map(|scheme| (id, scheme))
         } else {
@@ -101,7 +110,7 @@ impl SchemeList {
     }
 
     /// Create a new scheme.
-    pub fn insert(&mut self, name: Box<[u8]>, scheme: Arc<Box<Scheme + Send + Sync>>) -> Result<usize> {
+    pub fn insert(&mut self, name: Box<[u8]>, scheme: Arc<Box<Scheme + Send + Sync>>) -> Result<SchemeId> {
         if self.names.contains_key(&name) {
             return Err(Error::new(EEXIST));
         }
@@ -110,7 +119,7 @@ impl SchemeList {
             self.next_id = 1;
         }
 
-        while self.map.contains_key(&self.next_id) {
+        while self.map.contains_key(&SchemeId(self.next_id)) {
             self.next_id += 1;
         }
 
@@ -118,12 +127,11 @@ impl SchemeList {
             return Err(Error::new(EAGAIN));
         }
 
-        let id = self.next_id;
+        let id = SchemeId(self.next_id);
         self.next_id += 1;
 
         assert!(self.map.insert(id, scheme).is_none());
         assert!(self.names.insert(name, id).is_none());
-
         Ok(id)
     }
 }
diff --git a/kernel/scheme/pipe.rs b/kernel/scheme/pipe.rs
index 3f9ed62eb010a6b39bd701bc65b876cb56ac506f..30d0bd51da4f0357789a3778cb6c3a6f1c2ebee2 100644
--- a/kernel/scheme/pipe.rs
+++ b/kernel/scheme/pipe.rs
@@ -2,6 +2,7 @@ use alloc::arc::{Arc, Weak};
 use collections::{BTreeMap, VecDeque};
 use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
 use spin::{Mutex, Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
+use scheme::{AtomicSchemeId, ATOMIC_SCHEMEID_INIT};
 
 use sync::WaitCondition;
 use syscall::error::{Error, Result, EAGAIN, EBADF, EINVAL, EPIPE};
@@ -9,7 +10,7 @@ use syscall::flag::{F_GETFL, F_SETFL, O_CLOEXEC, O_NONBLOCK};
 use syscall::scheme::Scheme;
 
 /// Pipes list
-pub static PIPE_SCHEME_ID: AtomicUsize = ATOMIC_USIZE_INIT;
+pub static PIPE_SCHEME_ID: AtomicSchemeId = ATOMIC_SCHEMEID_INIT;
 static PIPE_NEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT;
 static PIPES: Once<RwLock<(BTreeMap<usize, Arc<PipeRead>>, BTreeMap<usize, Arc<PipeWrite>>)>> = Once::new();
 
diff --git a/kernel/scheme/root.rs b/kernel/scheme/root.rs
index 737e74b665f8e9fca93bfea4b69f794b139efe78..bc1ec427ba42768abed147a7bf07b665429b5b37 100644
--- a/kernel/scheme/root.rs
+++ b/kernel/scheme/root.rs
@@ -1,16 +1,16 @@
 use alloc::arc::Arc;
 use alloc::boxed::Box;
 use collections::BTreeMap;
-use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+use core::sync::atomic::{AtomicUsize, Ordering};
 use spin::RwLock;
 
 use context;
 use syscall::error::*;
 use syscall::scheme::Scheme;
-use scheme;
+use scheme::{self, AtomicSchemeId, ATOMIC_SCHEMEID_INIT};
 use scheme::user::{UserInner, UserScheme};
 
-pub static ROOT_SCHEME_ID: AtomicUsize = ATOMIC_USIZE_INIT;
+pub static ROOT_SCHEME_ID: AtomicSchemeId = ATOMIC_SCHEMEID_INIT;
 
 pub struct RootScheme {
     next_id: AtomicUsize,
diff --git a/kernel/scheme/sys/context.rs b/kernel/scheme/sys/context.rs
index 75b5e4f46cf1c0586b1bb540a2be2452b15db8fa..3f179b34f95ee620ddc1a907c272707e063d6d06 100644
--- a/kernel/scheme/sys/context.rs
+++ b/kernel/scheme/sys/context.rs
@@ -83,8 +83,8 @@ pub fn resource() -> Result<Vec<u8>> {
             let name = str::from_utf8(&name_bytes).unwrap_or("");
 
             string.push_str(&format!("{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<8}{}\n",
-                               context.id,
-                               context.ppid,
+                               context.id.into(),
+                               context.ppid.into(),
                                context.euid,
                                context.egid,
                                stat_string,
diff --git a/kernel/scheme/user.rs b/kernel/scheme/user.rs
index ef2bd22b0cb3a0dc67d493c1cef3b89841a35f68..3a8c4af10232958a38b7542e47a34cc9e50fdaef 100644
--- a/kernel/scheme/user.rs
+++ b/kernel/scheme/user.rs
@@ -1,6 +1,6 @@
 use alloc::arc::{Arc, Weak};
 use collections::BTreeMap;
-use core::sync::atomic::{AtomicUsize, AtomicU64, Ordering};
+use core::sync::atomic::{AtomicU64, Ordering};
 use core::{mem, slice, usize};
 use spin::{Mutex, RwLock};
 
@@ -10,6 +10,7 @@ use arch::paging::temporary_page::TemporaryPage;
 use context::{self, Context};
 use context::memory::Grant;
 use scheme::root::ROOT_SCHEME_ID;
+use scheme::{AtomicSchemeId, ATOMIC_SCHEMEID_INIT};
 use sync::{WaitQueue, WaitMap};
 use syscall::data::{Packet, Stat};
 use syscall::error::*;
@@ -20,7 +21,7 @@ use syscall::scheme::Scheme;
 pub struct UserInner {
     handle_id: usize,
     flags: usize,
-    pub scheme_id: AtomicUsize,
+    pub scheme_id: AtomicSchemeId,
     next_id: AtomicU64,
     context: Weak<RwLock<Context>>,
     todo: WaitQueue<Packet>,
@@ -33,7 +34,7 @@ impl UserInner {
         UserInner {
             handle_id: handle_id,
             flags: flags,
-            scheme_id: AtomicUsize::new(0),
+            scheme_id: ATOMIC_SCHEMEID_INIT,
             next_id: AtomicU64::new(1),
             context: context,
             todo: WaitQueue::new(),
@@ -52,7 +53,7 @@ impl UserInner {
 
         self.call_inner(Packet {
             id: self.next_id.fetch_add(1, Ordering::SeqCst),
-            pid: pid,
+            pid: pid.into(),
             uid: uid,
             gid: gid,
             a: a,
@@ -296,7 +297,7 @@ impl Scheme for UserScheme {
 
         inner.call_inner(Packet {
             id: id,
-            pid: pid,
+            pid: pid.into(),
             uid: uid,
             gid: gid,
             a: SYS_FMAP,
diff --git a/kernel/syscall/fs.rs b/kernel/syscall/fs.rs
index c40ec8de0d8503078ff702b61c2ccd05d1b14dd3..c12dc89d836cb216d0c3106430509b322417e037 100644
--- a/kernel/syscall/fs.rs
+++ b/kernel/syscall/fs.rs
@@ -2,13 +2,13 @@
 use core::sync::atomic::Ordering;
 
 use context;
-use scheme;
+use scheme::{self, FileHandle};
 use syscall;
 use syscall::data::{Packet, Stat};
 use syscall::error::*;
 use syscall::flag::{MODE_DIR, MODE_FILE};
 
-pub fn file_op(a: usize, fd: usize, c: usize, d: usize) -> Result<usize> {
+pub fn file_op(a: usize, fd: FileHandle, c: usize, d: usize) -> Result<usize> {
     let (file, pid, uid, gid) = {
         let contexts = context::contexts();
         let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
@@ -25,7 +25,7 @@ pub fn file_op(a: usize, fd: usize, c: usize, d: usize) -> Result<usize> {
 
     let mut packet = Packet {
         id: 0,
-        pid: pid,
+        pid: pid.into(),
         uid: uid,
         gid: gid,
         a: a,
@@ -39,11 +39,11 @@ pub fn file_op(a: usize, fd: usize, c: usize, d: usize) -> Result<usize> {
     Error::demux(packet.a)
 }
 
-pub fn file_op_slice(a: usize, fd: usize, slice: &[u8]) -> Result<usize> {
+pub fn file_op_slice(a: usize, fd: FileHandle, slice: &[u8]) -> Result<usize> {
     file_op(a, fd, slice.as_ptr() as usize, slice.len())
 }
 
-pub fn file_op_mut_slice(a: usize, fd: usize, slice: &mut [u8]) -> Result<usize> {
+pub fn file_op_mut_slice(a: usize, fd: FileHandle, slice: &mut [u8]) -> Result<usize> {
     file_op(a, fd, slice.as_mut_ptr() as usize, slice.len())
 }
 
@@ -81,7 +81,7 @@ pub fn getcwd(buf: &mut [u8]) -> Result<usize> {
 }
 
 /// Open syscall
-pub fn open(path: &[u8], flags: usize) -> Result<usize> {
+pub fn open(path: &[u8], flags: usize) -> Result<FileHandle> {
     let (path_canon, uid, gid) = {
         let contexts = context::contexts();
         let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
@@ -135,8 +135,8 @@ pub fn pipe2(fds: &mut [usize], flags: usize) -> Result<usize> {
             event: None,
         }).ok_or(Error::new(EMFILE))?;
 
-        fds[0] = read_fd;
-        fds[1] = write_fd;
+        fds[0] = read_fd.into();
+        fds[1] = write_fd.into();
 
         Ok(0)
     } else {
@@ -211,7 +211,7 @@ pub fn unlink(path: &[u8]) -> Result<usize> {
 }
 
 /// Close syscall
-pub fn close(fd: usize) -> Result<usize> {
+pub fn close(fd: FileHandle) -> Result<usize> {
     let file = {
         let contexts = context::contexts();
         let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
@@ -233,7 +233,7 @@ pub fn close(fd: usize) -> Result<usize> {
 }
 
 /// Duplicate file descriptor
-pub fn dup(fd: usize, buf: &[u8]) -> Result<usize> {
+pub fn dup(fd: FileHandle, buf: &[u8]) -> Result<FileHandle> {
     let file = {
         let contexts = context::contexts();
         let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
@@ -262,15 +262,15 @@ pub fn dup(fd: usize, buf: &[u8]) -> Result<usize> {
 }
 
 /// Register events for file
-pub fn fevent(fd: usize, flags: usize) -> Result<usize> {
+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();
-        let mut file = files.get_mut(fd).ok_or(Error::new(EBADF))?.ok_or(Error::new(EBADF))?;
+        let mut file = files.get_mut(fd.into()).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);
+            println!("{:?}: {:?}:{}: events already registered: {}", fd, file.scheme, file.number, event_id);
             context::event::unregister(fd, file.scheme, event_id);
         }
         file.clone()
@@ -287,7 +287,7 @@ pub fn fevent(fd: usize, flags: usize) -> Result<usize> {
         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))?;
+        let mut file = files.get_mut(fd.into()).ok_or(Error::new(EBADF))?.ok_or(Error::new(EBADF))?;
         file.event = Some(event_id);
     }
     context::event::register(fd, file.scheme, event_id);
diff --git a/kernel/syscall/mod.rs b/kernel/syscall/mod.rs
index 952ccfae30d6e842afa72d8423247e368a7b2d6e..b34df1d3f1122438c14ba936c1ab42734763ff66 100644
--- a/kernel/syscall/mod.rs
+++ b/kernel/syscall/mod.rs
@@ -14,6 +14,9 @@ use self::data::TimeSpec;
 use self::error::{Error, Result, ENOSYS};
 use self::number::*;
 
+use context::ContextId;
+use scheme::FileHandle;
+
 /// Filesystem syscalls
 pub mod fs;
 
@@ -34,19 +37,22 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize
     #[inline(always)]
     fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack: usize) -> Result<usize> {
         match a & SYS_CLASS {
-            SYS_CLASS_FILE => match a & SYS_ARG {
-                SYS_ARG_SLICE => file_op_slice(a, b, validate_slice(c as *const u8, d)?),
-                SYS_ARG_MSLICE => file_op_mut_slice(a, b, validate_slice_mut(c as *mut u8, d)?),
-                _ => match a {
-                    SYS_CLOSE => close(b),
-                    SYS_DUP => dup(b, validate_slice(c as *const u8, d)?),
-                    SYS_FEVENT => fevent(b, c),
-                    SYS_FUNMAP => funmap(b),
-                    _ => file_op(a, b, c, d)
+            SYS_CLASS_FILE => {
+                let fd = FileHandle::from(b);
+                match a & SYS_ARG {
+                    SYS_ARG_SLICE => file_op_slice(a, fd, validate_slice(c as *const u8, d)?),
+                    SYS_ARG_MSLICE => file_op_mut_slice(a, fd, validate_slice_mut(c as *mut u8, d)?),
+                    _ => match a {
+                        SYS_CLOSE => close(fd),
+                        SYS_DUP => dup(fd, validate_slice(c as *const u8, d)?).map(FileHandle::into),
+                        SYS_FEVENT => fevent(fd, c),
+                        SYS_FUNMAP => funmap(b),
+                        _ => file_op(a, fd, c, d)
+                    }
                 }
             },
             SYS_CLASS_PATH => match a {
-                SYS_OPEN => open(validate_slice(b as *const u8, c)?, d),
+                SYS_OPEN => open(validate_slice(b as *const u8, c)?, d).map(FileHandle::into),
                 SYS_MKDIR => mkdir(validate_slice(b as *const u8, c)?, d as u16),
                 SYS_RMDIR => rmdir(validate_slice(b as *const u8, c)?),
                 SYS_UNLINK => unlink(validate_slice(b as *const u8, c)?),
@@ -54,13 +60,13 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize
             },
             _ => match a {
                 SYS_EXIT => exit(b),
-                SYS_WAITPID => waitpid(b, c, d),
+                SYS_WAITPID => waitpid(ContextId::from(b), c, d).map(ContextId::into),
                 SYS_EXECVE => exec(validate_slice(b as *const u8, c)?, validate_slice(d as *const [usize; 2], e)?),
                 SYS_CHDIR => chdir(validate_slice(b as *const u8, c)?),
-                SYS_GETPID => getpid(),
+                SYS_GETPID => getpid().map(ContextId::into),
                 SYS_BRK => brk(b),
                 SYS_IOPL => iopl(b),
-                SYS_CLONE => clone(b, stack),
+                SYS_CLONE => clone(b, stack).map(ContextId::into),
                 SYS_YIELD => sched_yield(),
                 SYS_NANOSLEEP => nanosleep(validate_slice(b as *const TimeSpec, 1).map(|req| &req[0])?, validate_slice_mut(c as *mut TimeSpec, 1).ok().map(|rem| &mut rem[0])),
                 SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?),
diff --git a/kernel/syscall/process.rs b/kernel/syscall/process.rs
index 420edd445f6fc029d0d6dbdcfa376ec23192ba6c..0aaaaf2e22f84bfffc321af0803e6afaf4102226 100644
--- a/kernel/syscall/process.rs
+++ b/kernel/syscall/process.rs
@@ -12,9 +12,10 @@ use arch::paging::{ActivePageTable, InactivePageTable, Page, PhysicalAddress, Vi
 use arch::paging::temporary_page::TemporaryPage;
 use arch::start::usermode;
 use context;
+use context::ContextId;
 use context::memory::Grant;
 use elf::{self, program_header};
-use scheme;
+use scheme::{self, FileHandle};
 use syscall;
 use syscall::data::Stat;
 use syscall::error::*;
@@ -53,7 +54,7 @@ pub fn brk(address: usize) -> Result<usize> {
     }
 }
 
-pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
+pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
     let ppid;
     let pid;
     {
@@ -720,10 +721,10 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
                     if let Some(context_lock) = contexts.get(ppid) {
                         let mut context = context_lock.write();
                         if ! context.unblock() {
-                            println!("{} not blocked for exec vfork unblock", ppid);
+                            println!("{:?} not blocked for exec vfork unblock", ppid);
                         }
                     } else {
-                        println!("{} not found for exec vfork unblock", ppid);
+                        println!("{:?} not found for exec vfork unblock", ppid);
                     }
                 }
             },
@@ -749,7 +750,7 @@ pub fn exit(status: usize) -> ! {
         let mut close_files = Vec::new();
         let (pid, ppid) = {
             let mut context = context_lock.write();
-            if Arc::strong_count(&context.files) == 1 {
+            if Arc::strong_count(&context.files) == 1 { // FIXME: Looks like a race condition.
                 mem::swap(context.files.lock().deref_mut(), &mut close_files);
             }
             context.files = Arc::new(Mutex::new(Vec::new()));
@@ -760,7 +761,7 @@ pub fn exit(status: usize) -> ! {
         for (fd, file_option) in close_files.drain(..).enumerate() {
             if let Some(file) = file_option {
                 if let Some(event_id) = file.event {
-                    context::event::unregister(fd, file.scheme, event_id);
+                    context::event::unregister(FileHandle::from(fd), file.scheme, event_id);
                 }
 
                 let scheme_option = {
@@ -811,7 +812,7 @@ pub fn exit(status: usize) -> ! {
                     let mut parent = parent_lock.write();
                     if vfork {
                         if ! parent.unblock() {
-                            println!("{} not blocked for exit vfork unblock", ppid);
+                            println!("{:?} not blocked for exit vfork unblock", ppid);
                         }
                     }
                     parent.waitpid.clone()
@@ -822,7 +823,7 @@ pub fn exit(status: usize) -> ! {
                 }
                 waitpid.send(pid, status);
             } else {
-                println!("{} not found for exit vfork unblock", ppid);
+                println!("{:?} not found for exit vfork unblock", ppid);
             }
         }
     }
@@ -853,7 +854,7 @@ pub fn getgid() -> Result<usize> {
     Ok(context.rgid as usize)
 }
 
-pub fn getpid() -> Result<usize> {
+pub fn getpid() -> Result<ContextId> {
     let contexts = context::contexts();
     let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
     let context = context_lock.read();
@@ -872,7 +873,7 @@ pub fn iopl(_level: usize) -> Result<usize> {
     Ok(0)
 }
 
-pub fn kill(pid: usize, sig: usize) -> Result<usize> {
+pub fn kill(pid: ContextId, sig: usize) -> Result<usize> {
     use syscall::flag::*;
 
     let _context_lock = {
@@ -882,19 +883,19 @@ pub fn kill(pid: usize, sig: usize) -> Result<usize> {
     };
 
     let term = || {
-        println!("Terminate {}", pid);
+        println!("Terminate {:?}", pid);
     };
 
     let core = || {
-        println!("Core {}", pid);
+        println!("Core {:?}", pid);
     };
 
     let stop = || {
-        println!("Stop {}", pid);
+        println!("Stop {:?}", pid);
     };
 
     let cont = || {
-        println!("Continue {}", pid);
+        println!("Continue {:?}", pid);
     };
 
     match sig {
@@ -1056,7 +1057,7 @@ pub fn virttophys(virtual_address: usize) -> Result<usize> {
     }
 }
 
-fn reap(pid: usize) -> Result<usize> {
+fn reap(pid: ContextId) -> Result<ContextId> {
     // Spin until not running
     let mut running = false;
     while running {
@@ -1074,7 +1075,7 @@ fn reap(pid: usize) -> Result<usize> {
     contexts.remove(pid).ok_or(Error::new(ESRCH)).and(Ok(pid))
 }
 
-pub fn waitpid(pid: usize, status_ptr: usize, flags: usize) -> Result<usize> {
+pub fn waitpid(pid: ContextId, status_ptr: usize, flags: usize) -> Result<ContextId> {
     let waitpid = {
         let contexts = context::contexts();
         let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
@@ -1089,13 +1090,13 @@ pub fn waitpid(pid: usize, status_ptr: usize, flags: usize) -> Result<usize> {
         &mut tmp
     };
 
-    if pid == 0 {
+    if pid.into() == 0 {
         if flags & WNOHANG == WNOHANG {
             if let Some((w_pid, status)) = waitpid.receive_any_nonblock() {
                 status_slice[0] = status;
                 reap(w_pid)
             } else {
-                Ok(0)
+                Ok(ContextId::from(0))
             }
         } else {
             let (w_pid, status) = waitpid.receive_any();
@@ -1108,7 +1109,7 @@ pub fn waitpid(pid: usize, status_ptr: usize, flags: usize) -> Result<usize> {
                 status_slice[0] = status;
                 reap(pid)
             } else {
-                Ok(0)
+                Ok(ContextId::from(0))
             }
         } else {
             let status = waitpid.receive(&pid);
@@ -1117,3 +1118,4 @@ pub fn waitpid(pid: usize, status_ptr: usize, flags: usize) -> Result<usize> {
         }
     }
 }
+