Skip to content

Commit d8bd8de

Browse files
committed
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 rust-lang#12689
1 parent 8334dd4 commit d8bd8de

File tree

3 files changed

+22
-6
lines changed

3 files changed

+22
-6
lines changed

src/libnative/io/timer_other.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,15 @@ impl Timer {
218218
}
219219

220220
pub fn sleep(ms: u64) {
221-
// FIXME: this can fail because of EINTR, what do do?
222-
let _ = unsafe { libc::usleep((ms * 1000) as libc::c_uint) };
221+
let mut to_sleep = libc::timespec {
222+
tv_sec: (ms / 1000) as libc::time_t,
223+
tv_nsec: ((ms % 1000) * 1000000) as libc::c_long,
224+
};
225+
while unsafe { libc::nanosleep(&to_sleep, &mut to_sleep) } != 0 {
226+
if os::errno() as int != libc::EINTR as int {
227+
fail!("failed to sleep, but not because of EINTR?");
228+
}
229+
}
223230
}
224231

225232
fn inner(&mut self) -> ~Inner {

src/libnative/io/timer_timerfd.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
//! why).
2424
//!
2525
//! As with timer_other, timers just using sleep() do not use the timerfd at
26-
//! all. They remove the timerfd from the worker thread and then invoke usleep()
27-
//! to block the calling thread.
26+
//! all. They remove the timerfd from the worker thread and then invoke
27+
//! nanosleep() to block the calling thread.
2828
//!
2929
//! As with timer_other, all units in this file are in units of millseconds.
3030
@@ -183,8 +183,15 @@ impl Timer {
183183
}
184184

185185
pub fn sleep(ms: u64) {
186-
// FIXME: this can fail because of EINTR, what do do?
187-
let _ = unsafe { libc::usleep((ms * 1000) as libc::c_uint) };
186+
let mut to_sleep = libc::timespec {
187+
tv_sec: (ms / 1000) as libc::time_t,
188+
tv_nsec: ((ms % 1000) * 1000000) as libc::c_long,
189+
};
190+
while unsafe { libc::nanosleep(&to_sleep, &mut to_sleep) } != 0 {
191+
if os::errno() as int != libc::EINTR as int {
192+
fail!("failed to sleep, but not because of EINTR?");
193+
}
194+
}
188195
}
189196

190197
fn remove(&mut self) {

src/libstd/libc.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3682,6 +3682,7 @@ pub mod funcs {
36823682
use libc::types::common::c95::c_void;
36833683
use libc::types::os::arch::c95::{c_char, c_int, c_long, c_uint};
36843684
use libc::types::os::arch::c95::{size_t};
3685+
use libc::types::os::common::posix01::timespec;
36853686
use libc::types::os::arch::posix01::utimbuf;
36863687
use libc::types::os::arch::posix88::{gid_t, off_t, pid_t};
36873688
use libc::types::os::arch::posix88::{ssize_t, uid_t};
@@ -3731,6 +3732,7 @@ pub mod funcs {
37313732
pub fn setuid(uid: uid_t) -> c_int;
37323733
pub fn sleep(secs: c_uint) -> c_uint;
37333734
pub fn usleep(secs: c_uint) -> c_int;
3735+
pub fn nanosleep(rqtp: *timespec, rmtp: *mut timespec) -> c_int;
37343736
pub fn sysconf(name: c_int) -> c_long;
37353737
pub fn tcgetpgrp(fd: c_int) -> pid_t;
37363738
pub fn ttyname(fd: c_int) -> *c_char;

0 commit comments

Comments
 (0)