]> git.lizzy.rs Git - rust.git/commitdiff
Implement thread::yield_now.
authorVytautas Astrauskas <astrauv@amazon.com>
Sat, 18 Apr 2020 22:39:53 +0000 (15:39 -0700)
committerVytautas Astrauskas <astrauv@amazon.com>
Mon, 27 Apr 2020 21:26:36 +0000 (14:26 -0700)
src/shims/foreign_items/posix.rs
src/shims/thread.rs
src/thread.rs

index 9e85bcc66bb2ac4ecb937f4a230a56b5a9d656c7..4574d203efb7972b9470e88f30f3b1fd7f499020 100644 (file)
@@ -318,6 +318,11 @@ fn emulate_foreign_item_by_name(
                 let result = this.prctl(args[0], args[1], args[2], args[3], args[4])?;
                 this.write_scalar(Scalar::from_i32(result), dest)?;
             }
                 let result = this.prctl(args[0], args[1], args[2], args[3], args[4])?;
                 this.write_scalar(Scalar::from_i32(result), dest)?;
             }
+            "sched_yield" => {
+                assert_eq!(args.len(), 0);
+                let result = this.sched_yield()?;
+                this.write_scalar(Scalar::from_i32(result), dest)?;
+            }
 
             // Miscellaneous
             "isatty" => {
 
             // Miscellaneous
             "isatty" => {
index d8ba11d267f39e3697521cc63df4de28e41a98b1..ccdf6df3f9d6f76dfb3c43a28d3cba0228e04b4f 100644 (file)
@@ -111,4 +111,12 @@ fn prctl(
 
         Ok(0)
     }
 
         Ok(0)
     }
+
+    fn sched_yield(&mut self) -> InterpResult<'tcx, i32> {
+        let this = self.eval_context_mut();
+
+        this.yield_active_thread()?;
+
+        Ok(0)
+    }
 }
 }
index d40b2a176e73f52cfa9a760c1f2e2482528b08b9..31296ad96ff0ff3b2b6a6b62024f98d91b320141 100644 (file)
@@ -143,6 +143,8 @@ pub struct ThreadManager<'mir, 'tcx> {
     /// A mapping from a thread-local static to an allocation id of a thread
     /// specific allocation.
     thread_local_alloc_ids: RefCell<FxHashMap<(DefId, ThreadId), AllocId>>,
     /// A mapping from a thread-local static to an allocation id of a thread
     /// specific allocation.
     thread_local_alloc_ids: RefCell<FxHashMap<(DefId, ThreadId), AllocId>>,
+    /// A flag that indicates that we should change the active thread.
+    yield_active_thread: bool,
 }
 
 impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> {
 }
 
 impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> {
@@ -154,6 +156,7 @@ fn default() -> Self {
             threads: threads,
             blockset_counter: 0,
             thread_local_alloc_ids: Default::default(),
             threads: threads,
             blockset_counter: 0,
             thread_local_alloc_ids: Default::default(),
+            yield_active_thread: false,
         }
     }
 }
         }
     }
 }
@@ -275,6 +278,11 @@ fn unblock_random_thread(&mut self, set: BlockSetId) -> Option<ThreadId> {
         None
     }
 
         None
     }
 
+    /// Change the active thread to some enabled thread.
+    fn yield_active_thread(&mut self) {
+        self.yield_active_thread = true;
+    }
+
     /// Decide which action to take next and on which thread.
     fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> {
         if self.threads[self.active_thread].check_terminated() {
     /// Decide which action to take next and on which thread.
     fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> {
         if self.threads[self.active_thread].check_terminated() {
@@ -287,13 +295,21 @@ fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> {
             }
             return Ok(SchedulingAction::ExecuteDtors);
         }
             }
             return Ok(SchedulingAction::ExecuteDtors);
         }
-        if self.threads[self.active_thread].state == ThreadState::Enabled {
+        if self.threads[self.active_thread].state == ThreadState::Enabled
+            && !self.yield_active_thread
+        {
             return Ok(SchedulingAction::ExecuteStep);
         }
             return Ok(SchedulingAction::ExecuteStep);
         }
-        if let Some(enabled_thread) =
-            self.threads.iter().position(|thread| thread.state == ThreadState::Enabled)
-        {
-            self.active_thread = ThreadId::new(enabled_thread);
+        for (id, thread) in self.threads.iter_enumerated() {
+            if thread.state == ThreadState::Enabled {
+                if !(self.yield_active_thread && id == self.active_thread) {
+                    self.active_thread = id;
+                    break;
+                }
+            }
+        }
+        self.yield_active_thread = false;
+        if self.threads[self.active_thread].state == ThreadState::Enabled {
             return Ok(SchedulingAction::ExecuteStep);
         }
         if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) {
             return Ok(SchedulingAction::ExecuteStep);
         }
         if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) {
@@ -453,6 +469,12 @@ fn unblock_random_thread(&mut self, set: BlockSetId) -> InterpResult<'tcx, Optio
         Ok(this.machine.threads.unblock_random_thread(set))
     }
 
         Ok(this.machine.threads.unblock_random_thread(set))
     }
 
+    fn yield_active_thread(&mut self) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+        this.machine.threads.yield_active_thread();
+        Ok(())
+    }
+
     /// Decide which action to take next and on which thread.
     fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> {
         let this = self.eval_context_mut();
     /// Decide which action to take next and on which thread.
     fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> {
         let this = self.eval_context_mut();