]> git.lizzy.rs Git - rust.git/blobdiff - src/thread.rs
Typo
[rust.git] / src / thread.rs
index b2f2a8098de2374b7ab89fe515b7b2419130e1ec..2135806de3ed56853f233519f3ebcf28c00b3ffb 100644 (file)
@@ -2,7 +2,6 @@
 
 use std::cell::RefCell;
 use std::collections::hash_map::Entry;
-use std::convert::TryFrom;
 use std::num::TryFromIntError;
 use std::time::{Duration, Instant, SystemTime};
 
@@ -11,7 +10,9 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::DefId;
 use rustc_index::vec::{Idx, IndexVec};
+use rustc_middle::mir::Mutability;
 
+use crate::concurrency::data_race;
 use crate::sync::SynchronizationState;
 use crate::*;
 
@@ -58,7 +59,7 @@ fn index(self) -> usize {
 impl TryFrom<u64> for ThreadId {
     type Error = TryFromIntError;
     fn try_from(id: u64) -> Result<Self, Self::Error> {
-        u32::try_from(id).map(|id_u32| Self(id_u32))
+        u32::try_from(id).map(Self)
     }
 }
 
@@ -69,8 +70,8 @@ fn from(id: u32) -> Self {
 }
 
 impl ThreadId {
-    pub fn to_u32_scalar<'tcx>(&self) -> Scalar<Tag> {
-        Scalar::from_u32(u32::try_from(self.0).unwrap())
+    pub fn to_u32_scalar(&self) -> Scalar<Tag> {
+        Scalar::from_u32(self.0)
     }
 }
 
@@ -235,7 +236,7 @@ fn default() -> Self {
         threads.push(main_thread);
         Self {
             active_thread: ThreadId::new(0),
-            threads: threads,
+            threads,
             sync: SynchronizationState::default(),
             thread_local_alloc_ids: Default::default(),
             yield_active_thread: false,
@@ -263,7 +264,7 @@ fn set_thread_local_alloc(&self, def_id: DefId, ptr: Pointer<Tag>) {
     }
 
     /// Borrow the stack of the active thread.
-    fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] {
+    pub fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] {
         &self.threads[self.active_thread].stack
     }
 
@@ -456,7 +457,7 @@ fn thread_terminated(
                 // Delete this static from the map and from memory.
                 // We cannot free directly here as we cannot use `?` in this context.
                 free_tls_statics.push(alloc_id);
-                return false;
+                false
             });
         }
         // Set the thread into a terminated state in the data-race detector
@@ -474,7 +475,7 @@ fn thread_terminated(
                 thread.state = ThreadState::Enabled;
             }
         }
-        return free_tls_statics;
+        free_tls_statics
     }
 
     /// Decide which action to take next and on which thread.
@@ -518,16 +519,26 @@ fn schedule(
             return Ok(SchedulingAction::ExecuteTimeoutCallback);
         }
         // No callbacks scheduled, pick a regular thread to execute.
-        // We need to pick a new thread for execution.
-        for (id, thread) in self.threads.iter_enumerated() {
+        // The active thread blocked or yielded. So we go search for another enabled thread.
+        // Curcially, we start searching at the current active thread ID, rather than at 0, since we
+        // want to avoid always scheduling threads 0 and 1 without ever making progress in thread 2.
+        //
+        // `skip(N)` means we start iterating at thread N, so we skip 1 more to start just *after*
+        // the active thread. Then after that we look at `take(N)`, i.e., the threads *before* the
+        // active thread.
+        let threads = self
+            .threads
+            .iter_enumerated()
+            .skip(self.active_thread.index() + 1)
+            .chain(self.threads.iter_enumerated().take(self.active_thread.index()));
+        for (id, thread) in threads {
+            debug_assert_ne!(self.active_thread, id);
             if thread.state == ThreadState::Enabled {
-                if !self.yield_active_thread || id != self.active_thread {
-                    self.active_thread = id;
-                    if let Some(data_race) = data_race {
-                        data_race.thread_set_active(self.active_thread);
-                    }
-                    break;
+                self.active_thread = id;
+                if let Some(data_race) = data_race {
+                    data_race.thread_set_active(self.active_thread);
                 }
+                break;
             }
         }
         self.yield_active_thread = false;
@@ -572,9 +583,11 @@ fn get_or_create_thread_local_alloc(
                 throw_unsup_format!("foreign thread-local statics are not supported");
             }
             let allocation = tcx.eval_static_initializer(def_id)?;
+            let mut allocation = allocation.inner().clone();
+            // This allocation will be deallocated when the thread dies, so it is not in read-only memory.
+            allocation.mutability = Mutability::Mut;
             // Create a fresh allocation with this content.
-            let new_alloc =
-                this.memory.allocate_with(allocation.inner().clone(), MiriMemoryKind::Tls.into());
+            let new_alloc = this.allocate_raw_ptr(allocation, MiriMemoryKind::Tls.into())?;
             this.machine.threads.set_thread_local_alloc(def_id, new_alloc);
             Ok(new_alloc)
         }
@@ -584,7 +597,7 @@ fn get_or_create_thread_local_alloc(
     fn create_thread(&mut self) -> ThreadId {
         let this = self.eval_context_mut();
         let id = this.machine.threads.create_thread();
-        if let Some(data_race) = &mut this.memory.extra.data_race {
+        if let Some(data_race) = &mut this.machine.data_race {
             data_race.thread_created(id);
         }
         id
@@ -599,14 +612,14 @@ fn detach_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx> {
     #[inline]
     fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        this.machine.threads.join_thread(joined_thread_id, this.memory.extra.data_race.as_mut())?;
+        this.machine.threads.join_thread(joined_thread_id, this.machine.data_race.as_mut())?;
         Ok(())
     }
 
     #[inline]
     fn set_active_thread(&mut self, thread_id: ThreadId) -> ThreadId {
         let this = self.eval_context_mut();
-        if let Some(data_race) = &this.memory.extra.data_race {
+        if let Some(data_race) = &this.machine.data_race {
             data_race.thread_set_active(thread_id);
         }
         this.machine.threads.set_active_thread_id(thread_id)
@@ -669,7 +682,7 @@ fn active_thread_stack_mut(&mut self) -> &mut Vec<Frame<'mir, 'tcx, Tag, FrameDa
     #[inline]
     fn set_active_thread_name(&mut self, new_thread_name: Vec<u8>) {
         let this = self.eval_context_mut();
-        if let Some(data_race) = &mut this.memory.extra.data_race {
+        if let Some(data_race) = &mut this.machine.data_race {
             if let Ok(string) = String::from_utf8(new_thread_name.clone()) {
                 data_race.thread_set_name(this.machine.threads.active_thread, string);
             }
@@ -704,6 +717,16 @@ fn yield_active_thread(&mut self) {
         this.machine.threads.yield_active_thread();
     }
 
+    #[inline]
+    fn maybe_preempt_active_thread(&mut self) {
+        use rand::Rng as _;
+
+        let this = self.eval_context_mut();
+        if this.machine.rng.get_mut().gen_bool(this.machine.preemption_rate) {
+            this.yield_active_thread();
+        }
+    }
+
     #[inline]
     fn register_timeout_callback(
         &mut self,
@@ -753,7 +776,7 @@ fn run_timeout_callback(&mut self) -> InterpResult<'tcx> {
     #[inline]
     fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> {
         let this = self.eval_context_mut();
-        let data_race = &this.memory.extra.data_race;
+        let data_race = &this.machine.data_race;
         this.machine.threads.schedule(data_race)
     }
 
@@ -764,8 +787,8 @@ fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> {
     #[inline]
     fn thread_terminated(&mut self) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        for ptr in this.machine.threads.thread_terminated(this.memory.extra.data_race.as_mut()) {
-            this.memory.deallocate(ptr.into(), None, MiriMemoryKind::Tls.into())?;
+        for ptr in this.machine.threads.thread_terminated(this.machine.data_race.as_mut()) {
+            this.deallocate_ptr(ptr.into(), None, MiriMemoryKind::Tls.into())?;
         }
         Ok(())
     }