about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-03-04 17:40:45 -0800
committerAlex Crichton <alex@alexcrichton.com>2014-03-05 09:11:10 -0800
commitd8bd8de82e19702ad26fff704ff9a4890ebe1bf7 (patch)
treea4eb4b305a72fd8cd1e19d49a8d91179566a25c7
parent8334dd445fb10089a68808e7895f0c00d6fd0b3e (diff)
downloadrust-d8bd8de82e19702ad26fff704ff9a4890ebe1bf7.tar.gz
rust-d8bd8de82e19702ad26fff704ff9a4890ebe1bf7.zip
native: Move from usleep() to nanosleep()
Using nanosleep() allows us to gracefully recover from EINTR because on error it
fills in the second parameter with the remaining time to sleep.

Closes #12689
-rw-r--r--src/libnative/io/timer_other.rs11
-rw-r--r--src/libnative/io/timer_timerfd.rs15
-rw-r--r--src/libstd/libc.rs2
3 files changed, 22 insertions, 6 deletions
diff --git a/src/libnative/io/timer_other.rs b/src/libnative/io/timer_other.rs
index 9d700550863..d7323ddf499 100644
--- a/src/libnative/io/timer_other.rs
+++ b/src/libnative/io/timer_other.rs
@@ -218,8 +218,15 @@ impl Timer {
     }
 
     pub fn sleep(ms: u64) {
-        // FIXME: this can fail because of EINTR, what do do?
-        let _ = unsafe { libc::usleep((ms * 1000) as libc::c_uint) };
+        let mut to_sleep = libc::timespec {
+            tv_sec: (ms / 1000) as libc::time_t,
+            tv_nsec: ((ms % 1000) * 1000000) as libc::c_long,
+        };
+        while unsafe { libc::nanosleep(&to_sleep, &mut to_sleep) } != 0 {
+            if os::errno() as int != libc::EINTR as int {
+                fail!("failed to sleep, but not because of EINTR?");
+            }
+        }
     }
 
     fn inner(&mut self) -> ~Inner {
diff --git a/src/libnative/io/timer_timerfd.rs b/src/libnative/io/timer_timerfd.rs
index 68277efc9b7..55301b6f7c8 100644
--- a/src/libnative/io/timer_timerfd.rs
+++ b/src/libnative/io/timer_timerfd.rs
@@ -23,8 +23,8 @@
 //! why).
 //!
 //! As with timer_other, timers just using sleep() do not use the timerfd at
-//! all. They remove the timerfd from the worker thread and then invoke usleep()
-//! to block the calling thread.
+//! all. They remove the timerfd from the worker thread and then invoke
+//! nanosleep() to block the calling thread.
 //!
 //! As with timer_other, all units in this file are in units of millseconds.
 
@@ -183,8 +183,15 @@ impl Timer {
     }
 
     pub fn sleep(ms: u64) {
-        // FIXME: this can fail because of EINTR, what do do?
-        let _ = unsafe { libc::usleep((ms * 1000) as libc::c_uint) };
+        let mut to_sleep = libc::timespec {
+            tv_sec: (ms / 1000) as libc::time_t,
+            tv_nsec: ((ms % 1000) * 1000000) as libc::c_long,
+        };
+        while unsafe { libc::nanosleep(&to_sleep, &mut to_sleep) } != 0 {
+            if os::errno() as int != libc::EINTR as int {
+                fail!("failed to sleep, but not because of EINTR?");
+            }
+        }
     }
 
     fn remove(&mut self) {
diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs
index 7096765d9fc..d10fa7684e8 100644
--- a/src/libstd/libc.rs
+++ b/src/libstd/libc.rs
@@ -3682,6 +3682,7 @@ pub mod funcs {
             use libc::types::common::c95::c_void;
             use libc::types::os::arch::c95::{c_char, c_int, c_long, c_uint};
             use libc::types::os::arch::c95::{size_t};
+            use libc::types::os::common::posix01::timespec;
             use libc::types::os::arch::posix01::utimbuf;
             use libc::types::os::arch::posix88::{gid_t, off_t, pid_t};
             use libc::types::os::arch::posix88::{ssize_t, uid_t};
@@ -3731,6 +3732,7 @@ pub mod funcs {
                 pub fn setuid(uid: uid_t) -> c_int;
                 pub fn sleep(secs: c_uint) -> c_uint;
                 pub fn usleep(secs: c_uint) -> c_int;
+                pub fn nanosleep(rqtp: *timespec, rmtp: *mut timespec) -> c_int;
                 pub fn sysconf(name: c_int) -> c_long;
                 pub fn tcgetpgrp(fd: c_int) -> pid_t;
                 pub fn ttyname(fd: c_int) -> *c_char;