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}