1 use crate::rt::execution; 2 use crate::rt::object::Operation; 3 use crate::rt::vv::VersionVec; 4 5 use std::{any::Any, collections::HashMap, fmt, ops}; 6 pub(crate) struct Thread { 7 pub id: Id, 8 9 /// If the thread is runnable, blocked, or terminated. 10 pub state: State, 11 12 /// True if the thread is in a critical section 13 pub critical: bool, 14 15 /// The operation the thread is about to take 16 pub(super) operation: Option<Operation>, 17 18 /// Tracks observed causality 19 pub causality: VersionVec, 20 21 /// Tracks DPOR relations 22 pub dpor_vv: VersionVec, 23 24 /// Version at which the thread last yielded 25 pub last_yield: Option<u16>, 26 27 /// Number of times the thread yielded 28 pub yield_count: usize, 29 30 locals: LocalMap, 31 } 32 33 #[derive(Debug)] 34 pub(crate) struct Set { 35 /// Unique execution identifier 36 execution_id: execution::Id, 37 38 /// Set of threads 39 threads: Vec<Thread>, 40 41 /// Currently scheduled thread. 42 /// 43 /// `None` signifies that no thread is runnable. 44 active: Option<usize>, 45 46 /// Sequential consistency causality. All sequentially consistent operations 47 /// synchronize with this causality. 48 pub seq_cst_causality: VersionVec, 49 } 50 51 #[derive(Eq, PartialEq, Hash, Copy, Clone)] 52 pub(crate) struct Id { 53 execution_id: execution::Id, 54 id: usize, 55 } 56 57 impl Id { 58 /// Returns an integer ID unique to this current execution (for use in 59 /// [`thread::ThreadId`]'s `Debug` impl) public_id(&self) -> usize60 pub(crate) fn public_id(&self) -> usize { 61 self.id 62 } 63 } 64 65 #[derive(Debug, Clone, Copy)] 66 pub(crate) enum State { 67 Runnable, 68 Blocked, 69 Yield, 70 Terminated, 71 } 72 73 type LocalMap = HashMap<LocalKeyId, LocalValue>; 74 75 #[derive(Eq, PartialEq, Hash, Copy, Clone)] 76 struct LocalKeyId(usize); 77 78 struct LocalValue(Option<Box<dyn Any>>); 79 80 impl Thread { new(id: Id) -> Thread81 fn new(id: Id) -> Thread { 82 Thread { 83 id, 84 state: State::Runnable, 85 critical: false, 86 operation: None, 87 causality: VersionVec::new(), 88 dpor_vv: VersionVec::new(), 89 last_yield: None, 90 yield_count: 0, 91 locals: HashMap::new(), 92 } 93 } 94 is_runnable(&self) -> bool95 pub(crate) fn is_runnable(&self) -> bool { 96 match self.state { 97 State::Runnable => true, 98 _ => false, 99 } 100 } 101 set_runnable(&mut self)102 pub(crate) fn set_runnable(&mut self) { 103 self.state = State::Runnable; 104 } 105 set_blocked(&mut self)106 pub(crate) fn set_blocked(&mut self) { 107 self.state = State::Blocked; 108 } 109 is_blocked(&self) -> bool110 pub(crate) fn is_blocked(&self) -> bool { 111 match self.state { 112 State::Blocked => true, 113 _ => false, 114 } 115 } 116 is_yield(&self) -> bool117 pub(crate) fn is_yield(&self) -> bool { 118 match self.state { 119 State::Yield => true, 120 _ => false, 121 } 122 } 123 set_yield(&mut self)124 pub(crate) fn set_yield(&mut self) { 125 self.state = State::Yield; 126 self.last_yield = Some(self.causality[self.id]); 127 self.yield_count += 1; 128 } 129 is_terminated(&self) -> bool130 pub(crate) fn is_terminated(&self) -> bool { 131 match self.state { 132 State::Terminated => true, 133 _ => false, 134 } 135 } 136 set_terminated(&mut self)137 pub(crate) fn set_terminated(&mut self) { 138 self.state = State::Terminated; 139 } 140 drop_locals(&mut self) -> Box<dyn std::any::Any>141 pub(crate) fn drop_locals(&mut self) -> Box<dyn std::any::Any> { 142 let mut locals = Vec::with_capacity(self.locals.len()); 143 144 // run the Drop impls of any mock thread-locals created by this thread. 145 for (_, local) in &mut self.locals { 146 locals.push(local.0.take()); 147 } 148 149 Box::new(locals) 150 } 151 unpark(&mut self, unparker: &Thread)152 pub(crate) fn unpark(&mut self, unparker: &Thread) { 153 self.causality.join(&unparker.causality); 154 155 if self.is_blocked() || self.is_yield() { 156 self.set_runnable(); 157 } 158 } 159 } 160 161 impl fmt::Debug for Thread { 162 // Manual debug impl is necessary because thread locals are represented as 163 // `dyn Any`, which does not implement `Debug`. fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result164 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 165 f.debug_struct("Thread") 166 .field("id", &self.id) 167 .field("state", &self.state) 168 .field("critical", &self.critical) 169 .field("operation", &self.operation) 170 .field("causality", &self.causality) 171 .field("dpor_vv", &self.dpor_vv) 172 .field("last_yield", &self.last_yield) 173 .field("yield_count", &self.yield_count) 174 .field("locals", &format_args!("[..locals..]")) 175 .finish() 176 } 177 } 178 179 impl Set { 180 /// Create an empty thread set. 181 /// 182 /// The set may contain up to `max_threads` threads. new(execution_id: execution::Id, max_threads: usize) -> Set183 pub(crate) fn new(execution_id: execution::Id, max_threads: usize) -> Set { 184 let mut threads = Vec::with_capacity(max_threads); 185 186 // Push initial thread 187 threads.push(Thread::new(Id::new(execution_id, 0))); 188 189 Set { 190 execution_id, 191 threads, 192 active: Some(0), 193 seq_cst_causality: VersionVec::new(), 194 } 195 } 196 execution_id(&self) -> execution::Id197 pub(crate) fn execution_id(&self) -> execution::Id { 198 self.execution_id 199 } 200 201 /// Create a new thread new_thread(&mut self) -> Id202 pub(crate) fn new_thread(&mut self) -> Id { 203 assert!(self.threads.len() < self.max()); 204 205 // Get the identifier for the thread about to be created 206 let id = self.threads.len(); 207 208 // Push the thread onto the stack 209 self.threads 210 .push(Thread::new(Id::new(self.execution_id, id))); 211 212 Id::new(self.execution_id, id) 213 } 214 max(&self) -> usize215 pub(crate) fn max(&self) -> usize { 216 self.threads.capacity() 217 } 218 is_active(&self) -> bool219 pub(crate) fn is_active(&self) -> bool { 220 self.active.is_some() 221 } 222 active_id(&self) -> Id223 pub(crate) fn active_id(&self) -> Id { 224 Id::new(self.execution_id, self.active.unwrap()) 225 } 226 active(&self) -> &Thread227 pub(crate) fn active(&self) -> &Thread { 228 &self.threads[self.active.unwrap()] 229 } 230 set_active(&mut self, id: Option<Id>)231 pub(crate) fn set_active(&mut self, id: Option<Id>) { 232 self.active = id.map(Id::as_usize); 233 } 234 active_mut(&mut self) -> &mut Thread235 pub(crate) fn active_mut(&mut self) -> &mut Thread { 236 &mut self.threads[self.active.unwrap()] 237 } 238 239 /// Get the active thread and second thread active2_mut(&mut self, other: Id) -> (&mut Thread, &mut Thread)240 pub(crate) fn active2_mut(&mut self, other: Id) -> (&mut Thread, &mut Thread) { 241 let active = self.active.unwrap(); 242 let other = other.id; 243 244 if other >= active { 245 let (l, r) = self.threads.split_at_mut(other); 246 247 (&mut l[active], &mut r[0]) 248 } else { 249 let (l, r) = self.threads.split_at_mut(active); 250 251 (&mut r[0], &mut l[other]) 252 } 253 } 254 active_causality_inc(&mut self)255 pub(crate) fn active_causality_inc(&mut self) { 256 let id = self.active_id(); 257 self.active_mut().causality.inc(id); 258 } 259 active_atomic_version(&self) -> u16260 pub(crate) fn active_atomic_version(&self) -> u16 { 261 let id = self.active_id(); 262 self.active().causality[id] 263 } 264 unpark(&mut self, id: Id)265 pub(crate) fn unpark(&mut self, id: Id) { 266 if id == self.active_id() { 267 return; 268 } 269 270 // Synchronize memory 271 let (active, th) = self.active2_mut(id); 272 th.unpark(&active); 273 } 274 275 /// Insert a point of sequential consistency seq_cst(&mut self)276 pub(crate) fn seq_cst(&mut self) { 277 // The previous implementation of sequential consistency was incorrect. 278 // As a quick fix, just disable it. This may fail to model correct code, 279 // but will not silently allow bugs. 280 } 281 clear(&mut self, execution_id: execution::Id)282 pub(crate) fn clear(&mut self, execution_id: execution::Id) { 283 self.threads.clear(); 284 self.threads.push(Thread::new(Id::new(execution_id, 0))); 285 286 self.execution_id = execution_id; 287 self.active = Some(0); 288 self.seq_cst_causality = VersionVec::new(); 289 } 290 iter<'a>(&'a self) -> impl ExactSizeIterator<Item = (Id, &'a Thread)> + 'a291 pub(crate) fn iter<'a>(&'a self) -> impl ExactSizeIterator<Item = (Id, &'a Thread)> + 'a { 292 let execution_id = self.execution_id; 293 self.threads 294 .iter() 295 .enumerate() 296 .map(move |(id, thread)| (Id::new(execution_id, id), thread)) 297 } 298 iter_mut<'a>( &'a mut self, ) -> impl ExactSizeIterator<Item = (Id, &'a mut Thread)>299 pub(crate) fn iter_mut<'a>( 300 &'a mut self, 301 ) -> impl ExactSizeIterator<Item = (Id, &'a mut Thread)> { 302 let execution_id = self.execution_id; 303 self.threads 304 .iter_mut() 305 .enumerate() 306 .map(move |(id, thread)| (Id::new(execution_id, id), thread)) 307 } 308 309 /// Split the set of threads into the active thread and an iterator of all 310 /// other threads. split_active(&mut self) -> (&mut Thread, impl Iterator<Item = &mut Thread>)311 pub(crate) fn split_active(&mut self) -> (&mut Thread, impl Iterator<Item = &mut Thread>) { 312 let active = self.active.unwrap(); 313 let (one, two) = self.threads.split_at_mut(active); 314 let (active, two) = two.split_at_mut(1); 315 316 let iter = one.iter_mut().chain(two.iter_mut()); 317 318 (&mut active[0], iter) 319 } 320 local<T: 'static>( &mut self, key: &'static crate::thread::LocalKey<T>, ) -> Option<Result<&T, AccessError>>321 pub(crate) fn local<T: 'static>( 322 &mut self, 323 key: &'static crate::thread::LocalKey<T>, 324 ) -> Option<Result<&T, AccessError>> { 325 self.active_mut() 326 .locals 327 .get(&LocalKeyId::new(key)) 328 .map(|local_value| local_value.get()) 329 } 330 local_init<T: 'static>( &mut self, key: &'static crate::thread::LocalKey<T>, value: T, )331 pub(crate) fn local_init<T: 'static>( 332 &mut self, 333 key: &'static crate::thread::LocalKey<T>, 334 value: T, 335 ) { 336 assert!(self 337 .active_mut() 338 .locals 339 .insert(LocalKeyId::new(key), LocalValue::new(value)) 340 .is_none()) 341 } 342 } 343 344 impl ops::Index<Id> for Set { 345 type Output = Thread; 346 index(&self, index: Id) -> &Thread347 fn index(&self, index: Id) -> &Thread { 348 &self.threads[index.id] 349 } 350 } 351 352 impl ops::IndexMut<Id> for Set { index_mut(&mut self, index: Id) -> &mut Thread353 fn index_mut(&mut self, index: Id) -> &mut Thread { 354 &mut self.threads[index.id] 355 } 356 } 357 358 impl Id { new(execution_id: execution::Id, id: usize) -> Id359 pub(crate) fn new(execution_id: execution::Id, id: usize) -> Id { 360 Id { execution_id, id } 361 } 362 as_usize(self) -> usize363 pub(crate) fn as_usize(self) -> usize { 364 self.id 365 } 366 } 367 368 impl From<Id> for usize { from(src: Id) -> usize369 fn from(src: Id) -> usize { 370 src.id 371 } 372 } 373 374 impl fmt::Display for Id { fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result375 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 376 self.id.fmt(fmt) 377 } 378 } 379 380 impl fmt::Debug for Id { fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result381 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 382 write!(fmt, "Id({})", self.id) 383 } 384 } 385 386 impl LocalKeyId { new<T>(key: &'static crate::thread::LocalKey<T>) -> Self387 fn new<T>(key: &'static crate::thread::LocalKey<T>) -> Self { 388 Self(key as *const _ as usize) 389 } 390 } 391 392 impl LocalValue { new<T: 'static>(value: T) -> Self393 fn new<T: 'static>(value: T) -> Self { 394 Self(Some(Box::new(value))) 395 } 396 get<T: 'static>(&self) -> Result<&T, AccessError>397 fn get<T: 'static>(&self) -> Result<&T, AccessError> { 398 self.0 399 .as_ref() 400 .ok_or(AccessError { _private: () }) 401 .map(|val| { 402 val.downcast_ref::<T>() 403 .expect("local value must downcast to expected type") 404 }) 405 } 406 } 407 408 /// An error returned by [`LocalKey::try_with`](struct.LocalKey.html#method.try_with). 409 pub struct AccessError { 410 _private: (), 411 } 412 413 impl fmt::Debug for AccessError { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result414 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 415 f.debug_struct("AccessError").finish() 416 } 417 } 418 419 impl fmt::Display for AccessError { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result420 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 421 fmt::Display::fmt("already destroyed", f) 422 } 423 } 424