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