From a7ff3bc39433d114a7d339683b0d96fc7455cf2c Mon Sep 17 00:00:00 2001 From: AzureMarker Date: Sat, 5 Feb 2022 22:32:23 -0800 Subject: [PATCH] Fix pthread_cond_timedwait from sleeping for about 52 years pthread_cond_timedwait gives a timestamp as the timeout, but libctru expects a duration. After converting the timestamp to nanoseconds since epoch, we were telling libctru to sleep for over 52 years! This commit changes our impl to convert the timestamp to a duration. Additionally, CondVar_WaitTimeout returns a boolean indicating if it timed out or not. But pthread_cond_timedwait expects a libc-style error code. This conversion is added as well. --- src/lib.rs | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ad6a955..b9eaf68 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -131,9 +131,40 @@ pub unsafe extern "C" fn pthread_cond_timedwait( lock: *mut libc::pthread_mutex_t, abstime: *const libc::timespec, ) -> libc::c_int { - let nsec: i64 = ((*abstime).tv_sec as i64 * 1_000_000_000) + (*abstime).tv_nsec as i64; + // libctru expects a duration, but we have an absolute timestamp. + // Convert to a duration before calling libctru. + + // Get the current time so we can make a duration + let mut now = libc::timeval { + tv_sec: 0, + tv_usec: 0, + }; + let r = libc::gettimeofday(&mut now, ptr::null_mut()); + if r != 0 { + return r; + } - CondVar_WaitTimeout(cond as _, lock as _, nsec) + // Calculate the duration + let duration_nsec = (*abstime) + .tv_sec + // Get the difference in seconds + .saturating_sub(now.tv_sec) + // Convert to nanoseconds + .saturating_mul(1_000_000_000) + // Add the difference in nanoseconds + .saturating_add((*abstime).tv_nsec as i64) + .saturating_sub(now.tv_usec as i64 * 1_000) + // Don't go negative + .max(0); + + let r = CondVar_WaitTimeout(cond as _, lock as _, duration_nsec); + + // CondVar_WaitTimeout returns a boolean which is true (nonzero) if it timed out + if r == 0 { + 0 + } else { + libc::ETIMEDOUT + } } #[no_mangle]