1 //! Mock implementation of `std::thread`.
2 
3 pub use crate::rt::thread::AccessError;
4 pub use crate::rt::yield_now;
5 use crate::rt::{self, Execution};
6 
7 pub use std::thread::panicking;
8 
9 use std::marker::PhantomData;
10 use std::sync::{Arc, Mutex};
11 use std::{fmt, io};
12 
13 /// Mock implementation of `std::thread::JoinHandle`.
14 pub struct JoinHandle<T> {
15     result: Arc<Mutex<Option<std::thread::Result<T>>>>,
16     notify: rt::Notify,
17     thread: Thread,
18 }
19 
20 /// Mock implementation of `std::thread::Thread`.
21 #[derive(Clone, Debug)]
22 pub struct Thread {
23     id: ThreadId,
24     name: Option<String>,
25 }
26 
27 impl Thread {
28     /// Returns a unique identifier for this thread
id(&self) -> ThreadId29     pub fn id(&self) -> ThreadId {
30         self.id
31     }
32 
33     /// Returns the (optional) name of this thread
name(&self) -> Option<&str>34     pub fn name(&self) -> Option<&str> {
35         self.name.as_ref().map(|s| s.as_str())
36     }
37 }
38 
39 /// Mock implementation of `std::thread::ThreadId`.
40 #[derive(Clone, Copy, Eq, Hash, PartialEq)]
41 pub struct ThreadId {
42     id: crate::rt::thread::Id,
43 }
44 
45 impl std::fmt::Debug for ThreadId {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result46     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47         write!(f, "ThreadId({})", self.id.public_id())
48     }
49 }
50 
51 /// Mock implementation of `std::thread::LocalKey`.
52 pub struct LocalKey<T> {
53     // Sadly, these fields have to be public, since function pointers in const
54     // fns are unstable. When fn pointer arguments to const fns stabilize, these
55     // should be made private and replaced with a `const fn new`.
56     //
57     // User code should not rely on the existence of these fields.
58     #[doc(hidden)]
59     pub init: fn() -> T,
60     #[doc(hidden)]
61     pub _p: PhantomData<fn(T)>,
62 }
63 
64 /// Thread factory, which can be used in order to configure the properties of
65 /// a new thread.
66 #[derive(Debug)]
67 pub struct Builder {
68     name: Option<String>,
69 }
70 
71 static CURRENT_THREAD_KEY: LocalKey<Thread> = LocalKey {
72     init: || unreachable!(),
73     _p: PhantomData,
74 };
75 
init_current(execution: &mut Execution, name: Option<String>) -> Thread76 fn init_current(execution: &mut Execution, name: Option<String>) -> Thread {
77     let id = execution.threads.active_id();
78     let thread = Thread {
79         id: ThreadId { id },
80         name,
81     };
82 
83     execution
84         .threads
85         .local_init(&CURRENT_THREAD_KEY, thread.clone());
86 
87     thread
88 }
89 
90 /// Returns a handle to the current thread.
current() -> Thread91 pub fn current() -> Thread {
92     rt::execution(|execution| {
93         let thread = execution.threads.local(&CURRENT_THREAD_KEY);
94         if let Some(thread) = thread {
95             thread.unwrap().clone()
96         } else {
97             // Lazily initialize the current() Thread. This is done to help
98             // handle the initial (unnamed) bootstrap thread.
99             init_current(execution, None)
100         }
101     })
102 }
103 
104 /// Mock implementation of `std::thread::spawn`.
spawn<F, T>(f: F) -> JoinHandle<T> where F: FnOnce() -> T, F: 'static, T: 'static,105 pub fn spawn<F, T>(f: F) -> JoinHandle<T>
106 where
107     F: FnOnce() -> T,
108     F: 'static,
109     T: 'static,
110 {
111     spawn_internal(f, None)
112 }
113 
spawn_internal<F, T>(f: F, name: Option<String>) -> JoinHandle<T> where F: FnOnce() -> T, F: 'static, T: 'static,114 fn spawn_internal<F, T>(f: F, name: Option<String>) -> JoinHandle<T>
115 where
116     F: FnOnce() -> T,
117     F: 'static,
118     T: 'static,
119 {
120     let result = Arc::new(Mutex::new(None));
121     let notify = rt::Notify::new(true, false);
122 
123     let id = {
124         let name = name.clone();
125         let result = result.clone();
126         rt::spawn(move || {
127             rt::execution(|execution| {
128                 init_current(execution, name);
129             });
130 
131             *result.lock().unwrap() = Some(Ok(f()));
132             notify.notify();
133         })
134     };
135 
136     JoinHandle {
137         result,
138         notify,
139         thread: Thread {
140             id: ThreadId { id },
141             name,
142         },
143     }
144 }
145 
146 impl Builder {
147     /// Generates the base configuration for spawning a thread, from which
148     /// configuration methods can be chained.
new() -> Builder149     pub fn new() -> Builder {
150         Builder { name: None }
151     }
152 
153     /// Names the thread-to-be. Currently the name is used for identification
154     /// only in panic messages.
name(mut self, name: String) -> Builder155     pub fn name(mut self, name: String) -> Builder {
156         self.name = Some(name);
157 
158         self
159     }
160 
161     /// Sets the size of the stack (in bytes) for the new thread.
stack_size(self, _size: usize) -> Builder162     pub fn stack_size(self, _size: usize) -> Builder {
163         self
164     }
165 
166     /// Spawns a new thread by taking ownership of the `Builder`, and returns an
167     /// `io::Result` to its `JoinHandle`.
spawn<F, T>(self, f: F) -> io::Result<JoinHandle<T>> where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static,168     pub fn spawn<F, T>(self, f: F) -> io::Result<JoinHandle<T>>
169     where
170         F: FnOnce() -> T,
171         F: Send + 'static,
172         T: Send + 'static,
173     {
174         Ok(spawn_internal(f, self.name))
175     }
176 }
177 
178 impl<T> JoinHandle<T> {
179     /// Waits for the associated thread to finish.
join(self) -> std::thread::Result<T>180     pub fn join(self) -> std::thread::Result<T> {
181         self.notify.wait();
182         self.result.lock().unwrap().take().unwrap()
183     }
184 
185     /// Gets a handle to the underlying [`Thread`]
thread(&self) -> &Thread186     pub fn thread(&self) -> &Thread {
187         &self.thread
188     }
189 }
190 
191 impl<T: fmt::Debug> fmt::Debug for JoinHandle<T> {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result192     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
193         fmt.debug_struct("JoinHandle").finish()
194     }
195 }
196 
_assert_traits()197 fn _assert_traits() {
198     fn assert<T: Send + Sync>() {}
199 
200     assert::<JoinHandle<()>>();
201 }
202 
203 impl<T: 'static> LocalKey<T> {
204     /// Mock implementation of `std::thread::LocalKey::with`.
with<F, R>(&'static self, f: F) -> R where F: FnOnce(&T) -> R,205     pub fn with<F, R>(&'static self, f: F) -> R
206     where
207         F: FnOnce(&T) -> R,
208     {
209         self.try_with(f)
210             .expect("cannot access a (mock) TLS value during or after it is destroyed")
211     }
212 
213     /// Mock implementation of `std::thread::LocalKey::try_with`.
try_with<F, R>(&'static self, f: F) -> Result<R, AccessError> where F: FnOnce(&T) -> R,214     pub fn try_with<F, R>(&'static self, f: F) -> Result<R, AccessError>
215     where
216         F: FnOnce(&T) -> R,
217     {
218         let value = match unsafe { self.get() } {
219             Some(v) => v?,
220             None => {
221                 // Init the value out of the `rt::execution`
222                 let value = (self.init)();
223 
224                 rt::execution(|execution| {
225                     execution.threads.local_init(self, value);
226                 });
227 
228                 unsafe { self.get() }.expect("bug")?
229             }
230         };
231         Ok(f(value))
232     }
233 
get(&'static self) -> Option<Result<&T, AccessError>>234     unsafe fn get(&'static self) -> Option<Result<&T, AccessError>> {
235         unsafe fn transmute_lt<'a, 'b, T>(t: &'a T) -> &'b T {
236             std::mem::transmute::<&'a T, &'b T>(t)
237         }
238 
239         rt::execution(|execution| {
240             let res = execution.threads.local(self)?;
241 
242             let local = match res {
243                 Ok(l) => l,
244                 Err(e) => return Some(Err(e)),
245             };
246 
247             // This is, sadly, necessary to allow nested `with` blocks to access
248             // different thread locals. The borrow on the thread-local needs to
249             // escape the lifetime of the borrow on `execution`, since
250             // `rt::execution` mutably borrows a RefCell, and borrowing it twice will
251             // cause a panic. This should be safe, as we know the function being
252             // passed the thread local will not outlive the thread on which
253             // it's executing, by construction --- it's just kind of unfortunate.
254             Some(Ok(transmute_lt(local)))
255         })
256     }
257 }
258 
259 impl<T: 'static> fmt::Debug for LocalKey<T> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result260     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
261         f.pad("LocalKey { .. }")
262     }
263 }
264