diff --git a/ctr-std/Cargo.toml b/ctr-std/Cargo.toml index d4394a8..db79ae3 100644 --- a/ctr-std/Cargo.toml +++ b/ctr-std/Cargo.toml @@ -9,6 +9,9 @@ git = "https://github.com/rust-lang-nursery/compiler-builtins" [dependencies.ctr-libc] path = "../ctr-libc" +[dependencies.ctru-sys] +path = "../ctru-sys" + [dependencies.alloc_system] version = "0.1.1" diff --git a/ctr-std/src/lib.rs b/ctr-std/src/lib.rs index eebca4e..f9d3991 100644 --- a/ctr-std/src/lib.rs +++ b/ctr-std/src/lib.rs @@ -52,6 +52,7 @@ extern crate compiler_builtins; // 3ds-specific dependencies extern crate ctr_libc as libc; +extern crate ctru_sys as libctru; // stealing spin's mutex implementation for now extern crate spin; diff --git a/ctr-std/src/sys/unix/time.rs b/ctr-std/src/sys/unix/time.rs index 3eea581..9c80560 100644 --- a/ctr-std/src/sys/unix/time.rs +++ b/ctr-std/src/sys/unix/time.rs @@ -111,6 +111,9 @@ mod inner { use super::Timespec; + use spin; + use libctru; + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct Instant { t: Timespec, @@ -131,18 +134,13 @@ mod inner { }; impl Instant { - // devkitARM does not expose monotonic time functions or types, - // so we fall back to constructing Instant with gettimeofday(2) pub fn now() -> Instant { - use ptr; + let ms = monotonic_ms(); - let mut s = libc::timeval { - tv_sec: 0, - tv_usec: 0, + let s = libc::timeval { + tv_sec: ms as i32 * 1_000_000, + tv_usec: ms as i32, }; - cvt(unsafe { - libc::gettimeofday(&mut s, ptr::null_mut()) - }).unwrap(); return Instant::from(s) } @@ -161,6 +159,35 @@ mod inner { } } + // The initial system tick after which all Instants occur + static TICK: spin::Once = spin::Once::new(); + + // Returns a monotonic timer in microseconds + // + // Note that svcGetSystemTick always runs at 268MHz, even on a + // New 3DS running in 804MHz mode + // + // See https://www.3dbrew.org/wiki/Hardware#Common_hardware + fn monotonic_ms() -> u64 { + let first_tick = get_first_tick(); + let current_tick = get_system_tick(); + (current_tick - first_tick / 268) + } + + // The first time this function is called, it generates and returns the + // initial system tick used to create Instants + // + // subsequent calls to this function return the previously generated + // tick value + fn get_first_tick() -> u64 { + *TICK.call_once(get_system_tick) + } + + // Gets the current system tick + fn get_system_tick() -> u64 { + unsafe { libctru::svc::svcGetSystemTick() } + } + impl fmt::Debug for Instant { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Instant")