Skip to content

Commit

Permalink
std: Add Instant and SystemTime to std::time
Browse files Browse the repository at this point in the history
This commit is an implementation of [RFC 1288][rfc] which adds two new unstable
types to the `std::time` module. The `Instant` type is used to represent
measurements of a monotonically increasing clock suitable for measuring time
withing a process for operations such as benchmarks or just the elapsed time to
do something. An `Instant` favors panicking when bugs are found as the bugs are
programmer errors rather than typical errors that can be encountered.

[rfc]: rust-lang/rfcs#1288

The `SystemTime` type is used to represent a system timestamp and is not
monotonic. Very few guarantees are provided about this measurement of the system
clock, but a fixed point in time (`UNIX_EPOCH`) is provided to learn about the
relative distance from this point for any particular time stamp.

This PR takes the same implementation strategy as the `time` crate on crates.io,
namely:

|  Platform  |  Instant                 |  SystemTime              |
|------------|--------------------------|--------------------------|
| Windows    | QueryPerformanceCounter  | GetSystemTimeAsFileTime  |
| OSX        | mach_absolute_time       | gettimeofday             |
| Unix       | CLOCK_MONOTONIC          | CLOCK_REALTIME           |

These implementations can perhaps be refined over time, but they currently
satisfy the requirements of the `Instant` and `SystemTime` types while also
being portable across implementations and revisions of each platform.
  • Loading branch information
alexcrichton committed Nov 19, 2015
1 parent 22e31f1 commit c6eb852
Show file tree
Hide file tree
Showing 8 changed files with 816 additions and 102 deletions.
8 changes: 3 additions & 5 deletions src/libstd/sync/condvar.rs
Expand Up @@ -12,11 +12,10 @@ use prelude::v1::*;

use sync::atomic::{AtomicUsize, Ordering};
use sync::{mutex, MutexGuard, PoisonError};
use sys::time::SteadyTime;
use sys_common::condvar as sys;
use sys_common::mutex as sys_mutex;
use sys_common::poison::{self, LockResult};
use time::Duration;
use time::{Instant, Duration};

/// A type indicating whether a timed wait on a condition variable returned
/// due to a time out or not.
Expand Down Expand Up @@ -345,14 +344,13 @@ impl StaticCondvar {
where F: FnMut(LockResult<&mut T>) -> bool {
// This could be made more efficient by pushing the implementation into
// sys::condvar
let start = SteadyTime::now();
let start = Instant::now();
let mut guard_result: LockResult<MutexGuard<'a, T>> = Ok(guard);
while !f(guard_result
.as_mut()
.map(|g| &mut **g)
.map_err(|e| PoisonError::new(&mut **e.get_mut()))) {
let now = SteadyTime::now();
let consumed = &now - &start;
let consumed = start.elapsed();
let guard = guard_result.unwrap_or_else(|e| e.into_inner());
let (new_guard_result, timed_out) = if consumed > dur {
(Ok(guard), WaitTimeoutResult(true))
Expand Down
19 changes: 19 additions & 0 deletions src/libstd/sys/common/mod.rs
Expand Up @@ -98,3 +98,22 @@ pub fn cleanup() {
at_exit_imp::cleanup();
});
}

// Computes (value*numer)/denom without overflow, as long as both
// (numer*denom) and the overall result fit into i64 (which is the case
// for our time conversions).
#[allow(dead_code)] // not used on all platforms
pub fn mul_div_u64(value: u64, numer: u64, denom: u64) -> u64 {
let q = value / denom;
let r = value % denom;
// Decompose value as (value/denom*denom + value%denom),
// substitute into (value*numer)/denom and simplify.
// r < denom, so (denom*numer) is the upper bound of (r*numer)
q * numer + r * numer / denom
}

#[test]
fn test_muldiv() {
assert_eq!(mul_div_u64( 1_000_000_000_001, 1_000_000_000, 1_000_000),
1_000_000_000_001_000);
}
7 changes: 3 additions & 4 deletions src/libstd/sys/unix/condvar.rs
Expand Up @@ -12,8 +12,7 @@ use cell::UnsafeCell;
use libc;
use ptr;
use sys::mutex::{self, Mutex};
use sys::time;
use time::Duration;
use time::{Instant, Duration};

pub struct Condvar { inner: UnsafeCell<libc::pthread_cond_t> }

Expand Down Expand Up @@ -53,7 +52,7 @@ impl Condvar {
// stable time. pthread_cond_timedwait uses system time, but we want to
// report timeout based on stable time.
let mut sys_now = libc::timeval { tv_sec: 0, tv_usec: 0 };
let stable_now = time::SteadyTime::now();
let stable_now = Instant::now();
let r = libc::gettimeofday(&mut sys_now, ptr::null_mut());
debug_assert_eq!(r, 0);

Expand Down Expand Up @@ -81,7 +80,7 @@ impl Condvar {

// ETIMEDOUT is not a totally reliable method of determining timeout due
// to clock shifts, so do the check ourselves
&time::SteadyTime::now() - &stable_now < dur
stable_now.elapsed() < dur
}

#[inline]
Expand Down

0 comments on commit c6eb852

Please sign in to comment.