diff --git a/src/context/context.rs b/src/context/context.rs
index cb2eee035c6d18c8561f76d6d6143503243fbedc..1627b6efdb311c1a003c551eaed3f336c37171b2 100644
--- a/src/context/context.rs
+++ b/src/context/context.rs
@@ -10,7 +10,7 @@ use spin::Mutex;
 use crate::arch::{macros::InterruptStack, paging::PAGE_SIZE};
 use crate::common::unique::Unique;
 use crate::context::arch;
-use crate::context::file::FileDescriptor;
+use crate::context::file::{FileDescriptor, FileDescription};
 use crate::context::memory::{Grant, Memory, SharedMemory, Tls};
 use crate::ipi::{ipi, IpiKind, IpiTarget};
 use crate::scheme::{SchemeNamespace, FileHandle};
@@ -91,6 +91,76 @@ impl PartialEq for WaitpidKey {
 
 impl Eq for WaitpidKey {}
 
+pub struct ContextSnapshot {
+    // Copy fields
+    pub id: ContextId,
+    pub pgid: ContextId,
+    pub ppid: ContextId,
+    pub ruid: u32,
+    pub rgid: u32,
+    pub rns: SchemeNamespace,
+    pub euid: u32,
+    pub egid: u32,
+    pub ens: SchemeNamespace,
+    pub sigmask: [u64; 2],
+    pub umask: usize,
+    pub status: Status,
+    pub status_reason: &'static str,
+    pub running: bool,
+    pub cpu_id: Option<usize>,
+    pub ticks: u64,
+    pub syscall: Option<(usize, usize, usize, usize, usize, usize)>,
+    // Clone fields
+    //TODO: is there a faster way than allocation?
+    pub name: Box<[u8]>,
+    pub files: Vec<Option<FileDescription>>,
+    // pub cwd: Box<[u8]>,
+}
+
+impl ContextSnapshot {
+    //TODO: Should this accept &mut Context to ensure name/files will not change?
+    pub fn new(context: &Context) -> Self {
+        let name = context.name.lock().clone();
+        let mut files = Vec::new();
+        for descriptor_opt in context.files.lock().iter() {
+            let description = if let Some(descriptor) = descriptor_opt {
+                let description = descriptor.description.read();
+                Some(FileDescription {
+                    namespace: description.namespace,
+                    scheme: description.scheme,
+                    number: description.number,
+                    flags: description.flags,
+                })
+            } else {
+                None
+            };
+            files.push(description);
+        }
+
+        Self {
+            id: context.id,
+            pgid: context.pgid,
+            ppid: context.ppid,
+            ruid: context.ruid,
+            rgid: context.rgid,
+            rns: context.rns,
+            euid: context.euid,
+            egid: context.egid,
+            ens: context.ens,
+            sigmask: context.sigmask,
+            umask: context.umask,
+            status: context.status,
+            status_reason: context.status_reason,
+            running: context.running,
+            cpu_id: context.cpu_id,
+            ticks: context.ticks,
+            syscall: context.syscall,
+            name,
+            files,
+        }
+    }
+}
+
 /// A context, which identifies either a process or a thread
 #[derive(Debug)]
 pub struct Context {
diff --git a/src/context/mod.rs b/src/context/mod.rs
index b7024334dc8f27cd04c50015300cc148e53db8af..3d8b7ecedbab5f56b3e48c7946a735a8144ca936 100644
--- a/src/context/mod.rs
+++ b/src/context/mod.rs
@@ -6,7 +6,7 @@ use core::alloc::{GlobalAlloc, Layout};
 use core::sync::atomic::Ordering;
 use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
 
-pub use self::context::{Context, ContextId, Status, WaitpidKey};
+pub use self::context::{Context, ContextId, ContextSnapshot, Status, WaitpidKey};
 pub use self::list::ContextList;
 pub use self::switch::switch;