shadow_rs/host/
context.rs

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