diff --git a/examples/wait-signal.rs b/examples/wait-signal.rs
index d4f5bc3..a7afd07 100644
--- a/examples/wait-signal.rs
+++ b/examples/wait-signal.rs
@@ -33,12 +33,9 @@ mod example {
 
             // Process events.
             for ev in events.iter() {
-                match ev.key {
-                    1 => {
-                        println!("SIGINT received");
-                        return;
-                    }
-                    _ => unreachable!(),
+                if ev.key == 1 {
+                    println!("SIGINT received");
+                    return;
                 }
             }
 
diff --git a/src/os/kqueue.rs b/src/os/kqueue.rs
index aae36c3..888c735 100644
--- a/src/os/kqueue.rs
+++ b/src/os/kqueue.rs
@@ -4,6 +4,7 @@ use crate::sys::{mode_to_flags, SourceId};
 use crate::{PollMode, Poller};
 
 use std::io;
+use std::marker::PhantomData;
 use std::process::Child;
 use std::time::Duration;
 
@@ -171,11 +172,14 @@ impl Filter for Signal {}
 /// Monitor a child process.
 #[derive(Debug)]
 pub struct Process<'a> {
-    /// The child process to monitor.
-    child: &'a Child,
+    /// The process ID to monitor.
+    pid: std::os::raw::c_int,
 
     /// The operation to monitor.
     ops: ProcessOps,
+
+    /// Lifetime of the underlying process.
+    _lt: PhantomData<&'a Child>,
 }
 
 /// The operations that a monitored process can perform.
@@ -200,7 +204,26 @@ impl<'a> Process<'a> {
     /// Once registered into the `Poller`, the `Child` object must outlive this filter's
     /// registration into the poller.
     pub unsafe fn new(child: &'a Child, ops: ProcessOps) -> Self {
-        Self { child, ops }
+        Self {
+            pid: rustix::process::Pid::from_child(child)
+                .as_raw_nonzero()
+                .get(),
+            ops,
+            _lt: PhantomData,
+        }
+    }
+
+    /// Create a `Process` from a PID.
+    ///
+    /// # Safety
+    ///
+    /// The PID must be tied to an actual child process.
+    pub unsafe fn from_pid(pid: std::num::NonZeroI32, ops: ProcessOps) -> Self {
+        Self {
+            pid: pid.get(),
+            ops,
+            _lt: PhantomData,
+        }
     }
 }
 
@@ -215,7 +238,8 @@ unsafe impl FilterSealed for Process<'_> {
 
         kqueue::Event::new(
             kqueue::EventFilter::Proc {
-                pid: rustix::process::Pid::from_child(self.child),
+                // SAFETY: We know that the PID is nonzero.
+                pid: unsafe { rustix::process::Pid::from_raw_unchecked(self.pid) },
                 flags: events,
             },
             flags | kqueue::EventFlags::RECEIPT,
@@ -225,7 +249,8 @@ unsafe impl FilterSealed for Process<'_> {
 
     #[inline(always)]
     fn source_id(&self) -> SourceId {
-        SourceId::Pid(rustix::process::Pid::from_child(self.child))
+        // SAFETY: We know that the PID is nonzero
+        SourceId::Pid(unsafe { rustix::process::Pid::from_raw_unchecked(self.pid) })
     }
 }