From 95d9518068483d68dfbd6f1377728be56f40d07d Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Tue, 1 Feb 2022 18:09:45 -0500 Subject: [PATCH 1/2] Implement CLOCK_MONOTONIC --- src/lib.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index e57233e..de11e9c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,17 @@ #![no_std] +use core::any::Any; +use core::convert::{TryFrom, TryInto}; use core::mem::MaybeUninit; +use core::num::TryFromIntError; use core::ptr; extern crate libc; +// avoid conflicting a real POSIX errno by using a value < 0 +// should we define this in ctru-sys somewhere or something? +const ECTRU: libc::c_int = -1; + /// Call this somewhere to force Rust to link this module. /// The call doesn't need to execute, just exist. /// @@ -62,6 +69,20 @@ unsafe extern "C" fn clock_gettime( (*tp).tv_sec = tv.tv_sec; } } + libc::CLOCK_MONOTONIC => { + if let Ok(tick) = i64::try_from(ctru_sys::svcGetSystemTick()) { + let sysclock = i64::from(ctru_sys::SYSCLOCK_ARM11); + (*tp).tv_sec = tick / sysclock; + + // This cast to i32 is safe because the remainder will always be less than sysclock, + // which fits in an i32, and it's required to convert to f64. + let remainder = f64::from((tick - sysclock * (*tp).tv_sec) as i32); + // Casting to int rounds towards zero, which seems fine in this case. + (*tp).tv_nsec = (1000.0 * remainder / ctru_sys::CPU_TICKS_PER_USEC) as i32; + } else { + *__errno() = ECTRU + } + } _ => *__errno() = libc::EINVAL, } From 7abc5e53669659cb2e77087ae8e36856d40b1fe7 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Wed, 2 Feb 2022 00:15:15 -0500 Subject: [PATCH 2/2] Fix some accuracy / retval issues with monotonic --- src/lib.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index de11e9c..589a199 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,7 @@ #![no_std] -use core::any::Any; -use core::convert::{TryFrom, TryInto}; +use core::convert::TryFrom; use core::mem::MaybeUninit; -use core::num::TryFromIntError; use core::ptr; extern crate libc; @@ -58,6 +56,7 @@ unsafe extern "C" fn clock_gettime( tp: *mut libc::timespec, ) -> libc::c_int { let mut retval = -1; + match clock_id { libc::CLOCK_REALTIME => { let mut tv = MaybeUninit::uninit(); @@ -71,15 +70,19 @@ unsafe extern "C" fn clock_gettime( } libc::CLOCK_MONOTONIC => { if let Ok(tick) = i64::try_from(ctru_sys::svcGetSystemTick()) { - let sysclock = i64::from(ctru_sys::SYSCLOCK_ARM11); - (*tp).tv_sec = tick / sysclock; - - // This cast to i32 is safe because the remainder will always be less than sysclock, - // which fits in an i32, and it's required to convert to f64. - let remainder = f64::from((tick - sysclock * (*tp).tv_sec) as i32); - // Casting to int rounds towards zero, which seems fine in this case. - (*tp).tv_nsec = (1000.0 * remainder / ctru_sys::CPU_TICKS_PER_USEC) as i32; + retval = 0; + + let sysclock_rate = i64::from(ctru_sys::SYSCLOCK_ARM11); + (*tp).tv_sec = tick / sysclock_rate; + + // this should always fit in an f64 easily, since it's < sysclock_rate + let remainder = (tick % sysclock_rate) as f64; + + // cast to i32 rounds toward zero, which should be fine for this use case + (*tp).tv_nsec = (1000.0 * (remainder / ctru_sys::CPU_TICKS_PER_USEC)) as i32; } else { + // Too many ticks, this device has been on for >1000 years! + // We would have otherwise given a negative result back to caller *__errno() = ECTRU } }