From 8576b997596788ad3fd18d2c7231886de274a2cb Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jackpot51@gmail.com>
Date: Mon, 4 Apr 2022 20:23:29 -0600
Subject: [PATCH] Add timeout to futex_wait calls

---
 src/platform/linux/mod.rs |  4 ++--
 src/platform/pal/mod.rs   |  2 +-
 src/platform/pte.rs       | 13 ++++++++++---
 src/platform/redox/mod.rs |  4 ++--
 src/sync/mod.rs           | 10 +++++++---
 src/sync/semaphore.rs     |  5 +++--
 6 files changed, 25 insertions(+), 13 deletions(-)

diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs
index 4b92fc2c4..3c94ef972 100644
--- a/src/platform/linux/mod.rs
+++ b/src/platform/linux/mod.rs
@@ -207,8 +207,8 @@ impl Pal for Sys {
         e(unsafe { syscall!(FTRUNCATE, fildes, length) }) as c_int
     }
 
-    fn futex(addr: *mut c_int, op: c_int, val: c_int) -> c_int {
-        unsafe { syscall!(FUTEX, addr, op, val, 0, 0, 0) as c_int }
+    fn futex(addr: *mut c_int, op: c_int, val: c_int, val2: usize) -> c_int {
+        unsafe { syscall!(FUTEX, addr, op, val, val2, 0, 0) as c_int }
     }
 
     fn futimens(fd: c_int, times: *const timespec) -> c_int {
diff --git a/src/platform/pal/mod.rs b/src/platform/pal/mod.rs
index 73f32b1a1..66cae57e8 100644
--- a/src/platform/pal/mod.rs
+++ b/src/platform/pal/mod.rs
@@ -69,7 +69,7 @@ pub trait Pal {
 
     fn ftruncate(fildes: c_int, length: off_t) -> c_int;
 
-    fn futex(addr: *mut c_int, op: c_int, val: c_int) -> c_int;
+    fn futex(addr: *mut c_int, op: c_int, val: c_int, val2: usize) -> c_int;
 
     fn futimens(fd: c_int, times: *const timespec) -> c_int;
 
diff --git a/src/platform/pte.rs b/src/platform/pte.rs
index a7f2d8623..b10744b83 100644
--- a/src/platform/pte.rs
+++ b/src/platform/pte.rs
@@ -346,8 +346,15 @@ pub unsafe extern "C" fn pte_osSemaphorePend(
     handle: pte_osSemaphoreHandle,
     pTimeout: *mut c_uint,
 ) -> pte_osResult {
-    //TODO: pTimeout
-    (*handle).wait();
+    let timeout_opt = if ! pTimeout.is_null() {
+        let timeout = *pTimeout as i64;
+        let tv_sec = timeout / 1000;
+        let tv_nsec = (timeout % 1000) * 1000000;
+        Some(timespec { tv_sec, tv_nsec })
+    } else {
+        None
+    };
+    (*handle).wait(timeout_opt.as_ref());
     PTE_OS_OK
 }
 
@@ -356,7 +363,7 @@ pub unsafe extern "C" fn pte_osSemaphoreCancellablePend(
     handle: pte_osSemaphoreHandle,
     pTimeout: *mut c_uint,
 ) -> pte_osResult {
-    //TODO
+    //TODO: thread cancel
     pte_osSemaphorePend(handle, pTimeout)
 }
 
diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs
index 59b137a13..c1f36feea 100644
--- a/src/platform/redox/mod.rs
+++ b/src/platform/redox/mod.rs
@@ -446,13 +446,13 @@ impl Pal for Sys {
         e(syscall::ftruncate(fd as usize, len as usize)) as c_int
     }
 
-    fn futex(addr: *mut c_int, op: c_int, val: c_int) -> c_int {
+    fn futex(addr: *mut c_int, op: c_int, val: c_int, val2: usize) -> c_int {
         match unsafe {
             syscall::futex(
                 addr as *mut i32,
                 op as usize,
                 val as i32,
-                0,
+                val2,
                 ptr::null_mut(),
             )
         } {
diff --git a/src/sync/mod.rs b/src/sync/mod.rs
index 430abd5b7..dee4ac183 100644
--- a/src/sync/mod.rs
+++ b/src/sync/mod.rs
@@ -8,6 +8,7 @@ pub use self::{
     semaphore::Semaphore,
 };
 
+use crate::header::time::timespec;
 use crate::platform::{types::*, Pal, Sys};
 use core::{
     cell::UnsafeCell,
@@ -37,22 +38,25 @@ impl AtomicLock {
         }
     }
     pub fn notify_one(&self) {
-        Sys::futex(unsafe { &mut *self.atomic.get() }.get_mut(), FUTEX_WAKE, 1);
+        Sys::futex(unsafe { &mut *self.atomic.get() }.get_mut(), FUTEX_WAKE, 1, 0);
     }
     pub fn notify_all(&self) {
         Sys::futex(
             unsafe { &mut *self.atomic.get() }.get_mut(),
             FUTEX_WAKE,
             c_int::max_value(),
+            0
         );
     }
-    pub fn wait_if(&self, value: c_int) {
+    pub fn wait_if(&self, value: c_int, timeout_opt: Option<&timespec>) {
         Sys::futex(
             unsafe { &mut *self.atomic.get() }.get_mut(),
             FUTEX_WAIT,
             value,
+            timeout_opt.map_or(0, |timeout| timeout as *const timespec as usize)
         );
     }
+
     /// A general way to efficiently wait for what might be a long time, using two closures:
     ///
     /// - `attempt` = Attempt to modify the atomic value to any
@@ -103,7 +107,7 @@ impl AtomicLock {
                 // wait informed us that we might be done waiting
                 mark_long(self) != AttemptStatus::Desired
             {
-                self.wait_if(long);
+                self.wait_if(long, None);
             }
 
             previous = attempt(self);
diff --git a/src/sync/semaphore.rs b/src/sync/semaphore.rs
index aba5aff66..0827541f5 100644
--- a/src/sync/semaphore.rs
+++ b/src/sync/semaphore.rs
@@ -2,6 +2,7 @@
 //TODO: improve implementation
 
 use super::AtomicLock;
+use crate::header::time::timespec;
 use crate::platform::{types::*, Pal, Sys};
 use core::sync::atomic::Ordering;
 
@@ -21,7 +22,7 @@ impl Semaphore {
         self.lock.notify_one();
     }
 
-    pub fn wait(&self) {
+    pub fn wait(&self, timeout_opt: Option<&timespec>) {
         let mut value = 1;
 
         loop {
@@ -38,7 +39,7 @@ impl Semaphore {
             }
 
             if value == 0 {
-                self.lock.wait_if(0);
+                self.lock.wait_if(0, timeout_opt);
                 value = 1;
             }
         }
-- 
GitLab