about summary refs log tree commit diff
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2016-06-22 09:51:07 +0100
committerGitHub <noreply@github.com>2016-06-22 09:51:07 +0100
commit2aaf6a0e5cf5a857eb801fc8d9ebf5ae8e662085 (patch)
tree47dbf70939900fb58c4ea94a59b96ba0861a6b93
parente4ff7f0107a1c612285e6c3c265f227830761e26 (diff)
parentc02414e9bd4326d3db8d54a1cf4707089737b414 (diff)
downloadrust-2aaf6a0e5cf5a857eb801fc8d9ebf5ae8e662085.tar.gz
rust-2aaf6a0e5cf5a857eb801fc8d9ebf5ae8e662085.zip
Rollup merge of #34363 - GuillaumeGomez:sleep, r=alexcrichton
Fix overflow error in thread::sleep

Fixes #34330

I added a test to have a more clear error inside the function. Since `time_t` is `i64` and we expect `u64`, maybe we should changed the awaited type?
-rw-r--r--src/libstd/sys/unix/thread.rs21
-rw-r--r--src/test/run-pass/sleep.rs25
2 files changed, 40 insertions, 6 deletions
diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs
index cb34d1a5fbc..371319a93d2 100644
--- a/src/libstd/sys/unix/thread.rs
+++ b/src/libstd/sys/unix/thread.rs
@@ -125,16 +125,25 @@ impl Thread {
     }
 
     pub fn sleep(dur: Duration) {
-        let mut ts = libc::timespec {
-            tv_sec: dur.as_secs() as libc::time_t,
-            tv_nsec: dur.subsec_nanos() as libc::c_long,
-        };
+        let mut secs = dur.as_secs();
+        let mut nsecs = dur.subsec_nanos() as libc::c_long;
 
         // If we're awoken with a signal then the return value will be -1 and
         // nanosleep will fill in `ts` with the remaining time.
         unsafe {
-            while libc::nanosleep(&ts, &mut ts) == -1 {
-                assert_eq!(os::errno(), libc::EINTR);
+            while secs > 0 || nsecs > 0 {
+                let mut ts = libc::timespec {
+                    tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t,
+                    tv_nsec: nsecs,
+                };
+                secs -= ts.tv_sec as u64;
+                if libc::nanosleep(&ts, &mut ts) == -1 {
+                    assert_eq!(os::errno(), libc::EINTR);
+                    secs += ts.tv_sec as u64;
+                    nsecs = ts.tv_nsec;
+                } else {
+                    nsecs = 0;
+                }
             }
         }
     }
diff --git a/src/test/run-pass/sleep.rs b/src/test/run-pass/sleep.rs
new file mode 100644
index 00000000000..8b06b02f3cb
--- /dev/null
+++ b/src/test/run-pass/sleep.rs
@@ -0,0 +1,25 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::thread::{self, sleep};
+use std::time::Duration;
+use std::sync::{Arc, Mutex};
+use std::u64;
+
+fn main() {
+    let finished = Arc::new(Mutex::new(false));
+    let t_finished = finished.clone();
+    thread::spawn(move || {
+        sleep(Duration::new(u64::MAX, 0));
+        *t_finished.lock().unwrap() = true;
+    });
+    sleep(Duration::from_millis(100));
+    assert_eq!(*finished.lock().unwrap(), false);
+}