shadow_rs/host/context.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
//! This module provides several *Context* structs, intended to bundle together
//! current relevant objects in the hierarchy.
//!
//! These are meant to replace `worker_getActiveThread`, etc. Passing around
//! the current context explicitly instead of putting them in globals both
//! allows us to avoid interior mutability (and its associated runtime cost and
//! fallibility), and lets us keep a hierarchical object structure (e.g. allow
//! holding a mutable Process and a mutable Thread belonging to that process
//! simultaneously).
//!
//! Most code (e.g. syscall handlers) can take a [`ThreadContext`] argument and use
//! that to manipulate anything on the Host. The *current* [`Thread`] and [`Process`]
//! should typically be accessed directly. e.g. since a mutable reference to the
//! current `Thread` exists at [`ThreadContext::thread`], it *cannot* also be
//! accessible via [`ThreadContext::process`] or [`ThreadContext::host`].
//!
//! The manner in which they're unavailable isn't implemented yet, but the current
//! plan is that they'll be temporarily removed from their collections. e.g. something
//! conceptually like:
//!
//! ```ignore
//! impl Process {
//! pub fn continue_thread(&mut self, host_ctx: &mut HostContext, tid: ThreadId) {
//! let thread = self.threads.get_mut(tid).take();
//! thread.continue(&mut host_ctx.add_process(self));
//! self.threads.get_mut(tid).replace(thread);
//! }
//! }
//! ```
//!
//! The Context objects are designed to allow simultaneously borrowing from multiple
//! of their objects. This is currently implemented by exposing their fields
//! directly - Rust then allows each field to be borrowed independently. This could
//! alternatively be implemented by providing methods that borrow some or all of
//! their internal references simultaneously.
use std::ops::Deref;
use super::managed_thread::ManagedThread;
use super::process::ProcessId;
use super::thread::ThreadId;
use super::{host::Host, process::Process, thread::Thread};
/// Represent the "current" [`Host`].
pub struct HostContext<'a> {
// We expose fields directly rather than through accessors, so that
// users can borrow from each field independently.
pub host: &'a Host,
}
impl<'a> HostContext<'a> {
pub fn new(host: &'a Host) -> Self {
Self { host }
}
/// Add the given process to the context.
pub fn with_process(&'a self, process: &'a Process) -> ProcessContext<'a> {
ProcessContext::new(self.host, process)
}
}
/// Represent the "current" [`Host`] and [`Process`].
pub struct ProcessContext<'a> {
pub host: &'a Host,
pub process: &'a Process,
}
impl<'a> ProcessContext<'a> {
pub fn new(host: &'a Host, process: &'a Process) -> Self {
Self { host, process }
}
pub fn with_thread(&'a self, thread: &'a Thread) -> ThreadContext<'a> {
ThreadContext::new(self.host, self.process, thread)
}
}
/// Represent the "current" [`Host`], [`Process`], and [`Thread`].
pub struct ThreadContext<'a> {
pub host: &'a Host,
pub process: &'a Process,
pub thread: &'a Thread,
}
impl<'a> ThreadContext<'a> {
pub fn new(host: &'a Host, process: &'a Process, thread: &'a Thread) -> Self {
Self {
host,
process,
thread,
}
}
/// Split into a `&Process` and a `HostContext`. Useful e.g.
/// for calling `Process` methods that take a `&HostContext`.
pub fn split_process(&self) -> (HostContext, &Process) {
(HostContext::new(self.host), self.process)
}
/// Split into a `&Thread` and a `ProcessContext`. Useful e.g.
/// for calling `Thread` methods that take a `&ProcessContext`.
pub fn split_thread(&self) -> (ProcessContext, &Thread) {
(ProcessContext::new(self.host, self.process), self.thread)
}
pub fn mthread(&self) -> impl Deref<Target = ManagedThread> + '_ {
self.thread.mthread()
}
}
/// Shadow's C code doesn't know about contexts. In places where C code calls
/// Rust code, we can build them from C pointers.
pub struct ThreadContextObjs<'a> {
host: &'a Host,
pid: ProcessId,
tid: ThreadId,
}
impl<'a> ThreadContextObjs<'a> {
pub fn from_thread(host: &'a Host, thread: &'a Thread) -> Self {
let pid = thread.process_id();
let tid = thread.id();
Self { host, pid, tid }
}
pub fn with_ctx<F, R>(&mut self, f: F) -> R
where
F: FnOnce(&mut ThreadContext) -> R,
{
// Avoid holding a borrow of process and threads lists here, since
// handlers such as for `clone` may need to mutate them.
let processrc = self
.host
.process_borrow(self.pid)
.unwrap()
.clone(self.host.root());
let res = {
let process = processrc.borrow(self.host.root());
let threadrc = process
.thread_borrow(self.tid)
.unwrap()
.clone(self.host.root());
let res = {
let thread = threadrc.borrow(self.host.root());
let mut ctx = ThreadContext::new(self.host, &process, &thread);
f(&mut ctx)
};
threadrc.explicit_drop_recursive(self.host.root(), self.host);
res
};
processrc.explicit_drop_recursive(self.host.root(), self.host);
res
}
}