From b2ae1cbf91c350fc2d317a524d764d677f1230a6 Mon Sep 17 00:00:00 2001 From: Ron Williams <ron.williams.redox@gmail.com> Date: Sat, 25 Jan 2025 22:49:28 +0000 Subject: [PATCH 1/2] Make nanosleep and sleep handle interrupts correctly --- src/header/unistd/mod.rs | 21 ++++++++++++++++----- src/platform/redox/mod.rs | 21 +++++++++++++-------- tests/unistd/sleep.c | 24 +++++++++++++++++++++++- 3 files changed, 52 insertions(+), 14 deletions(-) diff --git a/src/header/unistd/mod.rs b/src/header/unistd/mod.rs index 9d1ba2ff2..6e479598a 100644 --- a/src/header/unistd/mod.rs +++ b/src/header/unistd/mod.rs @@ -84,11 +84,13 @@ pub extern "C" fn alarm(seconds: c_uint) -> c_uint { }, ..Default::default() }; + let mut otimer = sys_time::itimerval::default(); + let errno_backup = platform::ERRNO.get(); - let secs = if unsafe { sys_time::setitimer(sys_time::ITIMER_REAL, &timer, &mut timer) } < 0 { + let secs = if unsafe { sys_time::setitimer(sys_time::ITIMER_REAL, &timer, &mut otimer) } < 0 { 0 } else { - timer.it_value.tv_sec as c_uint + if timer.it_value.tv_usec > 0 { 1 } else { 0 } + otimer.it_value.tv_sec as c_uint + if otimer.it_value.tv_usec > 0 { 1 } else { 0 } }; platform::ERRNO.set(errno_backup); @@ -788,9 +790,18 @@ pub extern "C" fn sleep(seconds: c_uint) -> c_uint { tv_sec: seconds as time_t, tv_nsec: 0, }; - let rmtp = ptr::null_mut(); - unsafe { Sys::nanosleep(&rqtp, rmtp).map(|()| 0).or_minus_one_errno() }; - 0 + let mut rmtp = timespec { + tv_sec: 0, + tv_nsec: 0, + }; + + // If sleep() returns because the requested time has elapsed, the value returned shall be 0. + // If sleep() returns due to delivery of a signal, the return value shall be the "unslept" amount + // (the requested time minus the time actually slept) in seconds. + match unsafe { Sys::nanosleep(&rqtp, &mut rmtp) } { + Err(Errno(EINTR)) => rmtp.tv_sec as c_uint, + r => 0, + } } #[no_mangle] diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 628dfb734..d4e0b0ecc 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -18,8 +18,8 @@ use crate::{ header::{ dirent::dirent, errno::{ - EBADF, EBADFD, EBADR, EINVAL, EIO, ENAMETOOLONG, ENOENT, ENOMEM, ENOSYS, EOPNOTSUPP, - EPERM, ERANGE, + EBADF, EBADFD, EBADR, EINTR, EINVAL, EIO, ENAMETOOLONG, ENOENT, ENOMEM, ENOSYS, + EOPNOTSUPP, EPERM, ERANGE, }, fcntl, limits, sys_mman::{MAP_ANONYMOUS, MAP_FAILED, PROT_READ, PROT_WRITE}, @@ -698,14 +698,19 @@ impl Pal for Sys { } else { redox_rmtp = unsafe { redox_timespec::from(&*rmtp) }; } - syscall::nanosleep(&redox_rqtp, &mut redox_rmtp)?; - unsafe { - if !rmtp.is_null() { - (*rmtp).tv_sec = redox_rmtp.tv_sec as time_t; - (*rmtp).tv_nsec = redox_rmtp.tv_nsec as c_long; + match syscall::nanosleep(&redox_rqtp, &mut redox_rmtp) { + Ok(_) => Ok(()), + Err(Error { errno: EINTR }) => { + unsafe { + if !rmtp.is_null() { + (*rmtp).tv_sec = redox_rmtp.tv_sec as time_t; + (*rmtp).tv_nsec = redox_rmtp.tv_nsec as c_long; + } + }; + Err(Errno(EINTR)) } + Err(Error { errno: e }) => Err(Errno(e)), } - Ok(()) } fn open(path: CStr, oflag: c_int, mode: mode_t) -> Result<c_int> { diff --git a/tests/unistd/sleep.c b/tests/unistd/sleep.c index 2d7457e2d..a6adcf36c 100644 --- a/tests/unistd/sleep.c +++ b/tests/unistd/sleep.c @@ -1,14 +1,36 @@ #include <time.h> #include <unistd.h> #include <stdio.h> +#include <signal.h> #include "test_helpers.h" -int main(void) { +int usleep(useconds_t); + +void handler(int _s) +{ + (void)_s; +} + +int main(void) +{ // sleep has no error codes and doesn't set errno unsigned int unslept = sleep(2); printf("unslept: %u\n", unslept); + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = handler; + sigaction(SIGALRM, &sa, NULL); + alarm(2); + + unslept = sleep(10); + if (unslept < 7) + { + printf("after alarm, unslept too short: %u\n", unslept); + exit(EXIT_FAILURE); + } + int us_status = usleep(1000); ERROR_IF(usleep, us_status, == -1); UNEXP_IF(usleep, us_status, != 0); -- GitLab From 20121d84403813bca8ce803ed82b540fc843aa45 Mon Sep 17 00:00:00 2001 From: Ron Williams <ron.williams.redox@gmail.com> Date: Sun, 26 Jan 2025 05:32:36 +0000 Subject: [PATCH 2/2] Format --- src/header/unistd/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/header/unistd/mod.rs b/src/header/unistd/mod.rs index 6e479598a..59f16f266 100644 --- a/src/header/unistd/mod.rs +++ b/src/header/unistd/mod.rs @@ -796,7 +796,7 @@ pub extern "C" fn sleep(seconds: c_uint) -> c_uint { }; // If sleep() returns because the requested time has elapsed, the value returned shall be 0. - // If sleep() returns due to delivery of a signal, the return value shall be the "unslept" amount + // If sleep() returns due to delivery of a signal, the return value shall be the "unslept" amount // (the requested time minus the time actually slept) in seconds. match unsafe { Sys::nanosleep(&rqtp, &mut rmtp) } { Err(Errno(EINTR)) => rmtp.tv_sec as c_uint, -- GitLab