diff options
Diffstat (limited to 'third_party/chromium/base/time')
-rw-r--r-- | third_party/chromium/base/time/clock.cc | 11 | ||||
-rw-r--r-- | third_party/chromium/base/time/clock.h | 40 | ||||
-rw-r--r-- | third_party/chromium/base/time/default_clock.cc | 15 | ||||
-rw-r--r-- | third_party/chromium/base/time/default_clock.h | 25 | ||||
-rw-r--r-- | third_party/chromium/base/time/time.cc | 325 | ||||
-rw-r--r-- | third_party/chromium/base/time/time.h | 784 | ||||
-rw-r--r-- | third_party/chromium/base/time/time_posix.cc | 368 | ||||
-rw-r--r-- | third_party/chromium/base/time/time_unittest.cc | 848 |
8 files changed, 2416 insertions, 0 deletions
diff --git a/third_party/chromium/base/time/clock.cc b/third_party/chromium/base/time/clock.cc new file mode 100644 index 0000000..34dc37e --- /dev/null +++ b/third_party/chromium/base/time/clock.cc @@ -0,0 +1,11 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/time/clock.h" + +namespace base { + +Clock::~Clock() {} + +} // namespace base diff --git a/third_party/chromium/base/time/clock.h b/third_party/chromium/base/time/clock.h new file mode 100644 index 0000000..507a850 --- /dev/null +++ b/third_party/chromium/base/time/clock.h @@ -0,0 +1,40 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_TIME_CLOCK_H_ +#define BASE_TIME_CLOCK_H_ + +#include "base/base_export.h" +#include "base/time/time.h" + +namespace base { + +// A Clock is an interface for objects that vend Times. It is +// intended to be able to test the behavior of classes with respect to +// time. +// +// See DefaultClock (base/time/default_clock.h) for the default +// implementation that simply uses Time::Now(). +// +// (An implementation that uses Time::SystemTime() should be added as +// needed.) +// +// See SimpleTestClock (base/test/simple_test_clock.h) for a simple +// test implementation. +// +// See TickClock (base/time/tick_clock.h) for the equivalent interface for +// TimeTicks. +class BASE_EXPORT Clock { + public: + virtual ~Clock(); + + // Now() must be safe to call from any thread. The caller cannot + // make any ordering assumptions about the returned Time. For + // example, the system clock may change to an earlier time. + virtual Time Now() = 0; +}; + +} // namespace base + +#endif // BASE_TIME_CLOCK_H_ diff --git a/third_party/chromium/base/time/default_clock.cc b/third_party/chromium/base/time/default_clock.cc new file mode 100644 index 0000000..5f70114 --- /dev/null +++ b/third_party/chromium/base/time/default_clock.cc @@ -0,0 +1,15 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/time/default_clock.h" + +namespace base { + +DefaultClock::~DefaultClock() {} + +Time DefaultClock::Now() { + return Time::Now(); +} + +} // namespace base diff --git a/third_party/chromium/base/time/default_clock.h b/third_party/chromium/base/time/default_clock.h new file mode 100644 index 0000000..140e6f4 --- /dev/null +++ b/third_party/chromium/base/time/default_clock.h @@ -0,0 +1,25 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_TIME_DEFAULT_CLOCK_H_ +#define BASE_TIME_DEFAULT_CLOCK_H_ + +#include "base/base_export.h" +#include "base/compiler_specific.h" +#include "base/time/clock.h" + +namespace base { + +// DefaultClock is a Clock implementation that uses Time::Now(). +class DefaultClock : public Clock { + public: + ~DefaultClock() override; + + // Simply returns Time::Now(). + Time Now() override; +}; + +} // namespace base + +#endif // BASE_TIME_DEFAULT_CLOCK_H_ diff --git a/third_party/chromium/base/time/time.cc b/third_party/chromium/base/time/time.cc new file mode 100644 index 0000000..7006407 --- /dev/null +++ b/third_party/chromium/base/time/time.cc @@ -0,0 +1,325 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/time/time.h" + +#include <cmath> +#include <ios> +#include <limits> +#include <ostream> +#include <sstream> + +#include "base/logging.h" +#include "base/strings/stringprintf.h" + +namespace base { + +// TimeDelta ------------------------------------------------------------------ + +// static +TimeDelta TimeDelta::Max() { + return TimeDelta(std::numeric_limits<int64>::max()); +} + +int TimeDelta::InDays() const { + if (is_max()) { + // Preserve max to prevent overflow. + return std::numeric_limits<int>::max(); + } + return static_cast<int>(delta_ / Time::kMicrosecondsPerDay); +} + +int TimeDelta::InHours() const { + if (is_max()) { + // Preserve max to prevent overflow. + return std::numeric_limits<int>::max(); + } + return static_cast<int>(delta_ / Time::kMicrosecondsPerHour); +} + +int TimeDelta::InMinutes() const { + if (is_max()) { + // Preserve max to prevent overflow. + return std::numeric_limits<int>::max(); + } + return static_cast<int>(delta_ / Time::kMicrosecondsPerMinute); +} + +double TimeDelta::InSecondsF() const { + if (is_max()) { + // Preserve max to prevent overflow. + return std::numeric_limits<double>::infinity(); + } + return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond; +} + +int64 TimeDelta::InSeconds() const { + if (is_max()) { + // Preserve max to prevent overflow. + return std::numeric_limits<int64>::max(); + } + return delta_ / Time::kMicrosecondsPerSecond; +} + +double TimeDelta::InMillisecondsF() const { + if (is_max()) { + // Preserve max to prevent overflow. + return std::numeric_limits<double>::infinity(); + } + return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond; +} + +int64 TimeDelta::InMilliseconds() const { + if (is_max()) { + // Preserve max to prevent overflow. + return std::numeric_limits<int64>::max(); + } + return delta_ / Time::kMicrosecondsPerMillisecond; +} + +int64 TimeDelta::InMillisecondsRoundedUp() const { + if (is_max()) { + // Preserve max to prevent overflow. + return std::numeric_limits<int64>::max(); + } + return (delta_ + Time::kMicrosecondsPerMillisecond - 1) / + Time::kMicrosecondsPerMillisecond; +} + +int64 TimeDelta::InMicroseconds() const { + if (is_max()) { + // Preserve max to prevent overflow. + return std::numeric_limits<int64>::max(); + } + return delta_; +} + +namespace time_internal { + +int64 SaturatedAdd(TimeDelta delta, int64 value) { + CheckedNumeric<int64> rv(delta.delta_); + rv += value; + return FromCheckedNumeric(rv); +} + +int64 SaturatedSub(TimeDelta delta, int64 value) { + CheckedNumeric<int64> rv(delta.delta_); + rv -= value; + return FromCheckedNumeric(rv); +} + +int64 FromCheckedNumeric(const CheckedNumeric<int64> value) { + if (value.IsValid()) + return value.ValueUnsafe(); + + // We could return max/min but we don't really expose what the maximum delta + // is. Instead, return max/(-max), which is something that clients can reason + // about. + // TODO(rvargas) crbug.com/332611: don't use internal values. + int64 limit = std::numeric_limits<int64>::max(); + if (value.validity() == internal::RANGE_UNDERFLOW) + limit = -limit; + return value.ValueOrDefault(limit); +} + +} // namespace time_internal + +std::ostream& operator<<(std::ostream& os, TimeDelta time_delta) { + return os << time_delta.InSecondsF() << "s"; +} + +// Time ----------------------------------------------------------------------- + +// static +Time Time::Max() { + return Time(std::numeric_limits<int64>::max()); +} + +// static +Time Time::FromTimeT(time_t tt) { + if (tt == 0) + return Time(); // Preserve 0 so we can tell it doesn't exist. + if (tt == std::numeric_limits<time_t>::max()) + return Max(); + return Time((tt * kMicrosecondsPerSecond) + kTimeTToMicrosecondsOffset); +} + +time_t Time::ToTimeT() const { + if (is_null()) + return 0; // Preserve 0 so we can tell it doesn't exist. + if (is_max()) { + // Preserve max without offset to prevent overflow. + return std::numeric_limits<time_t>::max(); + } + if (std::numeric_limits<int64>::max() - kTimeTToMicrosecondsOffset <= us_) { + DLOG(WARNING) << "Overflow when converting base::Time with internal " << + "value " << us_ << " to time_t."; + return std::numeric_limits<time_t>::max(); + } + return (us_ - kTimeTToMicrosecondsOffset) / kMicrosecondsPerSecond; +} + +// static +Time Time::FromDoubleT(double dt) { + if (dt == 0 || std::isnan(dt)) + return Time(); // Preserve 0 so we can tell it doesn't exist. + if (dt == std::numeric_limits<double>::infinity()) + return Max(); + return Time(static_cast<int64>((dt * + static_cast<double>(kMicrosecondsPerSecond)) + + kTimeTToMicrosecondsOffset)); +} + +double Time::ToDoubleT() const { + if (is_null()) + return 0; // Preserve 0 so we can tell it doesn't exist. + if (is_max()) { + // Preserve max without offset to prevent overflow. + return std::numeric_limits<double>::infinity(); + } + return (static_cast<double>(us_ - kTimeTToMicrosecondsOffset) / + static_cast<double>(kMicrosecondsPerSecond)); +} + +#if defined(OS_POSIX) +// static +Time Time::FromTimeSpec(const timespec& ts) { + return FromDoubleT(ts.tv_sec + + static_cast<double>(ts.tv_nsec) / + base::Time::kNanosecondsPerSecond); +} +#endif + +// static +Time Time::FromJsTime(double ms_since_epoch) { + // The epoch is a valid time, so this constructor doesn't interpret + // 0 as the null time. + if (ms_since_epoch == std::numeric_limits<double>::infinity()) + return Max(); + return Time(static_cast<int64>(ms_since_epoch * kMicrosecondsPerMillisecond) + + kTimeTToMicrosecondsOffset); +} + +double Time::ToJsTime() const { + if (is_null()) { + // Preserve 0 so the invalid result doesn't depend on the platform. + return 0; + } + if (is_max()) { + // Preserve max without offset to prevent overflow. + return std::numeric_limits<double>::infinity(); + } + return (static_cast<double>(us_ - kTimeTToMicrosecondsOffset) / + kMicrosecondsPerMillisecond); +} + +int64 Time::ToJavaTime() const { + if (is_null()) { + // Preserve 0 so the invalid result doesn't depend on the platform. + return 0; + } + if (is_max()) { + // Preserve max without offset to prevent overflow. + return std::numeric_limits<int64>::max(); + } + return ((us_ - kTimeTToMicrosecondsOffset) / + kMicrosecondsPerMillisecond); +} + +// static +Time Time::UnixEpoch() { + Time time; + time.us_ = kTimeTToMicrosecondsOffset; + return time; +} + +Time Time::LocalMidnight() const { + Exploded exploded; + LocalExplode(&exploded); + exploded.hour = 0; + exploded.minute = 0; + exploded.second = 0; + exploded.millisecond = 0; + return FromLocalExploded(exploded); +} + +std::ostream& operator<<(std::ostream& os, Time time) { + Time::Exploded exploded; + time.UTCExplode(&exploded); + // Use StringPrintf because iostreams formatting is painful. + return os << StringPrintf("%04d-%02d-%02d %02d:%02d:%02d.%03d UTC", + exploded.year, + exploded.month, + exploded.day_of_month, + exploded.hour, + exploded.minute, + exploded.second, + exploded.millisecond); +} + +// Local helper class to hold the conversion from Time to TickTime at the +// time of the Unix epoch. +class UnixEpochSingleton { + public: + UnixEpochSingleton() + : unix_epoch_(TimeTicks::Now() - (Time::Now() - Time::UnixEpoch())) {} + + TimeTicks unix_epoch() const { return unix_epoch_; } + + private: + const TimeTicks unix_epoch_; + + DISALLOW_COPY_AND_ASSIGN(UnixEpochSingleton); +}; + +TimeTicks TimeTicks::SnappedToNextTick(TimeTicks tick_phase, + TimeDelta tick_interval) const { + // |interval_offset| is the offset from |this| to the next multiple of + // |tick_interval| after |tick_phase|, possibly negative if in the past. + TimeDelta interval_offset = (tick_phase - *this) % tick_interval; + // If |this| is exactly on the interval (i.e. offset==0), don't adjust. + // Otherwise, if |tick_phase| was in the past, adjust forward to the next + // tick after |this|. + if (!interval_offset.is_zero() && tick_phase < *this) + interval_offset += tick_interval; + return *this + interval_offset; +} + +std::ostream& operator<<(std::ostream& os, TimeTicks time_ticks) { + // This function formats a TimeTicks object as "bogo-microseconds". + // The origin and granularity of the count are platform-specific, and may very + // from run to run. Although bogo-microseconds usually roughly correspond to + // real microseconds, the only real guarantee is that the number never goes + // down during a single run. + const TimeDelta as_time_delta = time_ticks - TimeTicks(); + return os << as_time_delta.InMicroseconds() << " bogo-microseconds"; +} + +std::ostream& operator<<(std::ostream& os, ThreadTicks thread_ticks) { + const TimeDelta as_time_delta = thread_ticks - ThreadTicks(); + return os << as_time_delta.InMicroseconds() << " bogo-thread-microseconds"; +} + +std::ostream& operator<<(std::ostream& os, TraceTicks trace_ticks) { + const TimeDelta as_time_delta = trace_ticks - TraceTicks(); + return os << as_time_delta.InMicroseconds() << " bogo-trace-microseconds"; +} + +// Time::Exploded ------------------------------------------------------------- + +inline bool is_in_range(int value, int lo, int hi) { + return lo <= value && value <= hi; +} + +bool Time::Exploded::HasValidValues() const { + return is_in_range(month, 1, 12) && + is_in_range(day_of_week, 0, 6) && + is_in_range(day_of_month, 1, 31) && + is_in_range(hour, 0, 23) && + is_in_range(minute, 0, 59) && + is_in_range(second, 0, 60) && + is_in_range(millisecond, 0, 999); +} + +} // namespace base diff --git a/third_party/chromium/base/time/time.h b/third_party/chromium/base/time/time.h new file mode 100644 index 0000000..f421539 --- /dev/null +++ b/third_party/chromium/base/time/time.h @@ -0,0 +1,784 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Time represents an absolute point in coordinated universal time (UTC), +// internally represented as microseconds (s/1,000,000) since the Windows epoch +// (1601-01-01 00:00:00 UTC). System-dependent clock interface routines are +// defined in time_PLATFORM.cc. Note that values for Time may skew and jump +// around as the operating system makes adjustments to synchronize (e.g., with +// NTP servers). Thus, client code that uses the Time class must account for +// this. +// +// TimeDelta represents a duration of time, internally represented in +// microseconds. +// +// TimeTicks, ThreadTicks, and TraceTicks represent an abstract time that is +// most of the time incrementing, for use in measuring time durations. +// Internally, they are represented in microseconds. They can not be converted +// to a human-readable time, but are guaranteed not to decrease (unlike the Time +// class). Note that TimeTicks may "stand still" (e.g., if the computer is +// suspended), and ThreadTicks will "stand still" whenever the thread has been +// de-scheduled by the operating system. +// +// All time classes are copyable, assignable, and occupy 64-bits per +// instance. Thus, they can be efficiently passed by-value (as opposed to +// by-reference). +// +// Definitions of operator<< are provided to make these types work with +// DCHECK_EQ() and other log macros. For human-readable formatting, see +// "base/i18n/time_formatting.h". +// +// So many choices! Which time class should you use? Examples: +// +// Time: Interpreting the wall-clock time provided by a remote +// system. Detecting whether cached resources have +// expired. Providing the user with a display of the current date +// and time. Determining the amount of time between events across +// re-boots of the machine. +// +// TimeTicks: Tracking the amount of time a task runs. Executing delayed +// tasks at the right time. Computing presentation timestamps. +// Synchronizing audio and video using TimeTicks as a common +// reference clock (lip-sync). Measuring network round-trip +// latency. +// +// ThreadTicks: Benchmarking how long the current thread has been doing actual +// work. +// +// TraceTicks: This is only meant to be used by the event tracing +// infrastructure, and by outside code modules in special +// circumstances. Please be sure to consult a +// base/trace_event/OWNER before committing any new code that +// uses this. + +#ifndef BASE_TIME_TIME_H_ +#define BASE_TIME_TIME_H_ + +#include <time.h> + +#include <iosfwd> + +#include "base/base_export.h" +#include "base/basictypes.h" +#include "base/build/build_config.h" +#include "base/numerics/safe_math.h" + +#if defined(OS_MACOSX) +#include <CoreFoundation/CoreFoundation.h> +// Avoid Mac system header macro leak. +#undef TYPE_BOOL +#endif + +#if defined(OS_POSIX) +#include <unistd.h> +#include <sys/time.h> +#endif + +#if defined(OS_WIN) +// For FILETIME in FromFileTime, until it moves to a new converter class. +// See TODO(iyengar) below. +#include <windows.h> +#endif + +#include <limits> + +namespace base { + +class TimeDelta; + +// The functions in the time_internal namespace are meant to be used only by the +// time classes and functions. Please use the math operators defined in the +// time classes instead. +namespace time_internal { + +// Add or subtract |value| from a TimeDelta. The int64 argument and return value +// are in terms of a microsecond timebase. +BASE_EXPORT int64 SaturatedAdd(TimeDelta delta, int64 value); +BASE_EXPORT int64 SaturatedSub(TimeDelta delta, int64 value); + +// Clamp |value| on overflow and underflow conditions. The int64 argument and +// return value are in terms of a microsecond timebase. +BASE_EXPORT int64 FromCheckedNumeric(const CheckedNumeric<int64> value); + +} // namespace time_internal + +// TimeDelta ------------------------------------------------------------------ + +class BASE_EXPORT TimeDelta { + public: + TimeDelta() : delta_(0) { + } + + // Converts units of time to TimeDeltas. + static TimeDelta FromDays(int days); + static TimeDelta FromHours(int hours); + static TimeDelta FromMinutes(int minutes); + static TimeDelta FromSeconds(int64 secs); + static TimeDelta FromMilliseconds(int64 ms); + static TimeDelta FromSecondsD(double secs); + static TimeDelta FromMillisecondsD(double ms); + static TimeDelta FromMicroseconds(int64 us); +#if defined(OS_WIN) + static TimeDelta FromQPCValue(LONGLONG qpc_value); +#endif + + // Converts an integer value representing TimeDelta to a class. This is used + // when deserializing a |TimeDelta| structure, using a value known to be + // compatible. It is not provided as a constructor because the integer type + // may be unclear from the perspective of a caller. + static TimeDelta FromInternalValue(int64 delta) { + return TimeDelta(delta); + } + + // Returns the maximum time delta, which should be greater than any reasonable + // time delta we might compare it to. Adding or subtracting the maximum time + // delta to a time or another time delta has an undefined result. + static TimeDelta Max(); + + // Returns the internal numeric value of the TimeDelta object. Please don't + // use this and do arithmetic on it, as it is more error prone than using the + // provided operators. + // For serializing, use FromInternalValue to reconstitute. + int64 ToInternalValue() const { + return delta_; + } + + // Returns the magnitude (absolute value) of this TimeDelta. + TimeDelta magnitude() const { + // Some toolchains provide an incomplete C++11 implementation and lack an + // int64 overload for std::abs(). The following is a simple branchless + // implementation: + const int64 mask = delta_ >> (sizeof(delta_) * 8 - 1); + return TimeDelta((delta_ + mask) ^ mask); + } + + // Returns true if the time delta is zero. + bool is_zero() const { + return delta_ == 0; + } + + // Returns true if the time delta is the maximum time delta. + bool is_max() const { + return delta_ == std::numeric_limits<int64>::max(); + } + +#if defined(OS_POSIX) + struct timespec ToTimeSpec() const; +#endif + + // Returns the time delta in some unit. The F versions return a floating + // point value, the "regular" versions return a rounded-down value. + // + // InMillisecondsRoundedUp() instead returns an integer that is rounded up + // to the next full millisecond. + int InDays() const; + int InHours() const; + int InMinutes() const; + double InSecondsF() const; + int64 InSeconds() const; + double InMillisecondsF() const; + int64 InMilliseconds() const; + int64 InMillisecondsRoundedUp() const; + int64 InMicroseconds() const; + + TimeDelta& operator=(TimeDelta other) { + delta_ = other.delta_; + return *this; + } + + // Computations with other deltas. + TimeDelta operator+(TimeDelta other) const { + return TimeDelta(time_internal::SaturatedAdd(*this, other.delta_)); + } + TimeDelta operator-(TimeDelta other) const { + return TimeDelta(time_internal::SaturatedSub(*this, other.delta_)); + } + + TimeDelta& operator+=(TimeDelta other) { + return *this = (*this + other); + } + TimeDelta& operator-=(TimeDelta other) { + return *this = (*this - other); + } + TimeDelta operator-() const { + return TimeDelta(-delta_); + } + + // Computations with numeric types. + template<typename T> + TimeDelta operator*(T a) const { + CheckedNumeric<int64> rv(delta_); + rv *= a; + return TimeDelta(time_internal::FromCheckedNumeric(rv)); + } + template<typename T> + TimeDelta operator/(T a) const { + CheckedNumeric<int64> rv(delta_); + rv /= a; + return TimeDelta(time_internal::FromCheckedNumeric(rv)); + } + template<typename T> + TimeDelta& operator*=(T a) { + return *this = (*this * a); + } + template<typename T> + TimeDelta& operator/=(T a) { + return *this = (*this / a); + } + + int64 operator/(TimeDelta a) const { + return delta_ / a.delta_; + } + TimeDelta operator%(TimeDelta a) const { + return TimeDelta(delta_ % a.delta_); + } + + // Comparison operators. + bool operator==(TimeDelta other) const { + return delta_ == other.delta_; + } + bool operator!=(TimeDelta other) const { + return delta_ != other.delta_; + } + bool operator<(TimeDelta other) const { + return delta_ < other.delta_; + } + bool operator<=(TimeDelta other) const { + return delta_ <= other.delta_; + } + bool operator>(TimeDelta other) const { + return delta_ > other.delta_; + } + bool operator>=(TimeDelta other) const { + return delta_ >= other.delta_; + } + + private: + friend int64 time_internal::SaturatedAdd(TimeDelta delta, int64 value); + friend int64 time_internal::SaturatedSub(TimeDelta delta, int64 value); + + // Constructs a delta given the duration in microseconds. This is private + // to avoid confusion by callers with an integer constructor. Use + // FromSeconds, FromMilliseconds, etc. instead. + explicit TimeDelta(int64 delta_us) : delta_(delta_us) { + } + + // Delta in microseconds. + int64 delta_; +}; + +template<typename T> +inline TimeDelta operator*(T a, TimeDelta td) { + return td * a; +} + +// For logging use only. +BASE_EXPORT std::ostream& operator<<(std::ostream& os, TimeDelta time_delta); + +// Do not reference the time_internal::TimeBase template class directly. Please +// use one of the time subclasses instead, and only reference the public +// TimeBase members via those classes. +namespace time_internal { + +// TimeBase-------------------------------------------------------------------- + +// Provides value storage and comparison/math operations common to all time +// classes. Each subclass provides for strong type-checking to ensure +// semantically meaningful comparison/math of time values from the same clock +// source or timeline. +template<class TimeClass> +class TimeBase { + public: + static const int64 kHoursPerDay = 24; + static const int64 kMillisecondsPerSecond = 1000; + static const int64 kMillisecondsPerDay = kMillisecondsPerSecond * 60 * 60 * + kHoursPerDay; + static const int64 kMicrosecondsPerMillisecond = 1000; + static const int64 kMicrosecondsPerSecond = kMicrosecondsPerMillisecond * + kMillisecondsPerSecond; + static const int64 kMicrosecondsPerMinute = kMicrosecondsPerSecond * 60; + static const int64 kMicrosecondsPerHour = kMicrosecondsPerMinute * 60; + static const int64 kMicrosecondsPerDay = kMicrosecondsPerHour * kHoursPerDay; + static const int64 kMicrosecondsPerWeek = kMicrosecondsPerDay * 7; + static const int64 kNanosecondsPerMicrosecond = 1000; + static const int64 kNanosecondsPerSecond = kNanosecondsPerMicrosecond * + kMicrosecondsPerSecond; + + // Returns true if this object has not been initialized. + // + // Warning: Be careful when writing code that performs math on time values, + // since it's possible to produce a valid "zero" result that should not be + // interpreted as a "null" value. + bool is_null() const { + return us_ == 0; + } + + // Returns true if this object represents the maximum time. + bool is_max() const { + return us_ == std::numeric_limits<int64>::max(); + } + + // For serializing only. Use FromInternalValue() to reconstitute. Please don't + // use this and do arithmetic on it, as it is more error prone than using the + // provided operators. + int64 ToInternalValue() const { + return us_; + } + + TimeClass& operator=(TimeClass other) { + us_ = other.us_; + return *(static_cast<TimeClass*>(this)); + } + + // Compute the difference between two times. + TimeDelta operator-(TimeClass other) const { + return TimeDelta::FromMicroseconds(us_ - other.us_); + } + + // Return a new time modified by some delta. + TimeClass operator+(TimeDelta delta) const { + return TimeClass(time_internal::SaturatedAdd(delta, us_)); + } + TimeClass operator-(TimeDelta delta) const { + return TimeClass(-time_internal::SaturatedSub(delta, us_)); + } + + // Modify by some time delta. + TimeClass& operator+=(TimeDelta delta) { + return static_cast<TimeClass&>(*this = (*this + delta)); + } + TimeClass& operator-=(TimeDelta delta) { + return static_cast<TimeClass&>(*this = (*this - delta)); + } + + // Comparison operators + bool operator==(TimeClass other) const { + return us_ == other.us_; + } + bool operator!=(TimeClass other) const { + return us_ != other.us_; + } + bool operator<(TimeClass other) const { + return us_ < other.us_; + } + bool operator<=(TimeClass other) const { + return us_ <= other.us_; + } + bool operator>(TimeClass other) const { + return us_ > other.us_; + } + bool operator>=(TimeClass other) const { + return us_ >= other.us_; + } + + // Converts an integer value representing TimeClass to a class. This is used + // when deserializing a |TimeClass| structure, using a value known to be + // compatible. It is not provided as a constructor because the integer type + // may be unclear from the perspective of a caller. + static TimeClass FromInternalValue(int64 us) { + return TimeClass(us); + } + + protected: + explicit TimeBase(int64 us) : us_(us) { + } + + // Time value in a microsecond timebase. + int64 us_; +}; + +} // namespace time_internal + +template<class TimeClass> +inline TimeClass operator+(TimeDelta delta, TimeClass t) { + return t + delta; +} + +// Time ----------------------------------------------------------------------- + +// Represents a wall clock time in UTC. Values are not guaranteed to be +// monotonically non-decreasing and are subject to large amounts of skew. +class BASE_EXPORT Time : public time_internal::TimeBase<Time> { + public: + // The representation of Jan 1, 1970 UTC in microseconds since the + // platform-dependent epoch. + static const int64 kTimeTToMicrosecondsOffset; + +#if !defined(OS_WIN) + // On Mac & Linux, this value is the delta from the Windows epoch of 1601 to + // the Posix delta of 1970. This is used for migrating between the old + // 1970-based epochs to the new 1601-based ones. It should be removed from + // this global header and put in the platform-specific ones when we remove the + // migration code. + static const int64 kWindowsEpochDeltaMicroseconds; +#else + // To avoid overflow in QPC to Microseconds calculations, since we multiply + // by kMicrosecondsPerSecond, then the QPC value should not exceed + // (2^63 - 1) / 1E6. If it exceeds that threshold, we divide then multiply. + static const int64 kQPCOverflowThreshold = 0x8637BD05AF7; +#endif + + // Represents an exploded time that can be formatted nicely. This is kind of + // like the Win32 SYSTEMTIME structure or the Unix "struct tm" with a few + // additions and changes to prevent errors. + struct Exploded { + int year; // Four digit year "2007" + int month; // 1-based month (values 1 = January, etc.) + int day_of_week; // 0-based day of week (0 = Sunday, etc.) + int day_of_month; // 1-based day of month (1-31) + int hour; // Hour within the current day (0-23) + int minute; // Minute within the current hour (0-59) + int second; // Second within the current minute (0-59 plus leap + // seconds which may take it up to 60). + int millisecond; // Milliseconds within the current second (0-999) + + // A cursory test for whether the data members are within their + // respective ranges. A 'true' return value does not guarantee the + // Exploded value can be successfully converted to a Time value. + bool HasValidValues() const; + }; + + // Contains the NULL time. Use Time::Now() to get the current time. + Time() : TimeBase(0) { + } + + // Returns the time for epoch in Unix-like system (Jan 1, 1970). + static Time UnixEpoch(); + + // Returns the current time. Watch out, the system might adjust its clock + // in which case time will actually go backwards. We don't guarantee that + // times are increasing, or that two calls to Now() won't be the same. + static Time Now(); + + // Returns the maximum time, which should be greater than any reasonable time + // with which we might compare it. + static Time Max(); + + // Returns the current time. Same as Now() except that this function always + // uses system time so that there are no discrepancies between the returned + // time and system time even on virtual environments including our test bot. + // For timing sensitive unittests, this function should be used. + static Time NowFromSystemTime(); + + // Converts to/from time_t in UTC and a Time class. + // TODO(brettw) this should be removed once everybody starts using the |Time| + // class. + static Time FromTimeT(time_t tt); + time_t ToTimeT() const; + + // Converts time to/from a double which is the number of seconds since epoch + // (Jan 1, 1970). Webkit uses this format to represent time. + // Because WebKit initializes double time value to 0 to indicate "not + // initialized", we map it to empty Time object that also means "not + // initialized". + static Time FromDoubleT(double dt); + double ToDoubleT() const; + +#if defined(OS_POSIX) + // Converts the timespec structure to time. MacOS X 10.8.3 (and tentatively, + // earlier versions) will have the |ts|'s tv_nsec component zeroed out, + // having a 1 second resolution, which agrees with + // https://developer.apple.com/legacy/library/#technotes/tn/tn1150.html#HFSPlusDates. + static Time FromTimeSpec(const timespec& ts); +#endif + + // Converts to/from the Javascript convention for times, a number of + // milliseconds since the epoch: + // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/getTime. + static Time FromJsTime(double ms_since_epoch); + double ToJsTime() const; + + // Converts to Java convention for times, a number of + // milliseconds since the epoch. + int64 ToJavaTime() const; + +#if defined(OS_POSIX) + static Time FromTimeVal(struct timeval t); + struct timeval ToTimeVal() const; +#endif + +#if defined(OS_MACOSX) + static Time FromCFAbsoluteTime(CFAbsoluteTime t); + CFAbsoluteTime ToCFAbsoluteTime() const; +#endif + +#if defined(OS_WIN) + static Time FromFileTime(FILETIME ft); + FILETIME ToFileTime() const; + + // The minimum time of a low resolution timer. This is basically a windows + // constant of ~15.6ms. While it does vary on some older OS versions, we'll + // treat it as static across all windows versions. + static const int kMinLowResolutionThresholdMs = 16; + + // Enable or disable Windows high resolution timer. + static void EnableHighResolutionTimer(bool enable); + + // Activates or deactivates the high resolution timer based on the |activate| + // flag. If the HighResolutionTimer is not Enabled (see + // EnableHighResolutionTimer), this function will return false. Otherwise + // returns true. Each successful activate call must be paired with a + // subsequent deactivate call. + // All callers to activate the high resolution timer must eventually call + // this function to deactivate the high resolution timer. + static bool ActivateHighResolutionTimer(bool activate); + + // Returns true if the high resolution timer is both enabled and activated. + // This is provided for testing only, and is not tracked in a thread-safe + // way. + static bool IsHighResolutionTimerInUse(); +#endif + + // Converts an exploded structure representing either the local time or UTC + // into a Time class. + static Time FromUTCExploded(const Exploded& exploded) { + return FromExploded(false, exploded); + } + static Time FromLocalExploded(const Exploded& exploded) { + return FromExploded(true, exploded); + } + + // Fills the given exploded structure with either the local time or UTC from + // this time structure (containing UTC). + void UTCExplode(Exploded* exploded) const { + return Explode(false, exploded); + } + void LocalExplode(Exploded* exploded) const { + return Explode(true, exploded); + } + + // Rounds this time down to the nearest day in local time. It will represent + // midnight on that day. + Time LocalMidnight() const; + + private: + friend class time_internal::TimeBase<Time>; + + explicit Time(int64 us) : TimeBase(us) { + } + + // Explodes the given time to either local time |is_local = true| or UTC + // |is_local = false|. + void Explode(bool is_local, Exploded* exploded) const; + + // Unexplodes a given time assuming the source is either local time + // |is_local = true| or UTC |is_local = false|. + static Time FromExploded(bool is_local, const Exploded& exploded); +}; + +// Inline the TimeDelta factory methods, for fast TimeDelta construction. + +// static +inline TimeDelta TimeDelta::FromDays(int days) { + // Preserve max to prevent overflow. + if (days == std::numeric_limits<int>::max()) + return Max(); + return TimeDelta(days * Time::kMicrosecondsPerDay); +} + +// static +inline TimeDelta TimeDelta::FromHours(int hours) { + // Preserve max to prevent overflow. + if (hours == std::numeric_limits<int>::max()) + return Max(); + return TimeDelta(hours * Time::kMicrosecondsPerHour); +} + +// static +inline TimeDelta TimeDelta::FromMinutes(int minutes) { + // Preserve max to prevent overflow. + if (minutes == std::numeric_limits<int>::max()) + return Max(); + return TimeDelta(minutes * Time::kMicrosecondsPerMinute); +} + +// static +inline TimeDelta TimeDelta::FromSeconds(int64 secs) { + // Preserve max to prevent overflow. + if (secs == std::numeric_limits<int64>::max()) + return Max(); + return TimeDelta(secs * Time::kMicrosecondsPerSecond); +} + +// static +inline TimeDelta TimeDelta::FromMilliseconds(int64 ms) { + // Preserve max to prevent overflow. + if (ms == std::numeric_limits<int64>::max()) + return Max(); + return TimeDelta(ms * Time::kMicrosecondsPerMillisecond); +} + +// static +inline TimeDelta TimeDelta::FromSecondsD(double secs) { + // Preserve max to prevent overflow. + if (secs == std::numeric_limits<double>::infinity()) + return Max(); + return TimeDelta(static_cast<int64>(secs * Time::kMicrosecondsPerSecond)); +} + +// static +inline TimeDelta TimeDelta::FromMillisecondsD(double ms) { + // Preserve max to prevent overflow. + if (ms == std::numeric_limits<double>::infinity()) + return Max(); + return TimeDelta(static_cast<int64>(ms * Time::kMicrosecondsPerMillisecond)); +} + +// static +inline TimeDelta TimeDelta::FromMicroseconds(int64 us) { + // Preserve max to prevent overflow. + if (us == std::numeric_limits<int64>::max()) + return Max(); + return TimeDelta(us); +} + +// For logging use only. +BASE_EXPORT std::ostream& operator<<(std::ostream& os, Time time); + +// TimeTicks ------------------------------------------------------------------ + +// Represents monotonically non-decreasing clock time. +class TimeTicks : public time_internal::TimeBase<TimeTicks> { + public: + TimeTicks() : TimeBase(0) { + } + + // Platform-dependent tick count representing "right now." When + // IsHighResolution() returns false, the resolution of the clock could be + // as coarse as ~15.6ms. Otherwise, the resolution should be no worse than one + // microsecond. + static TimeTicks Now(); + + // Returns true if the high resolution clock is working on this system and + // Now() will return high resolution values. Note that, on systems where the + // high resolution clock works but is deemed inefficient, the low resolution + // clock will be used instead. + static bool IsHighResolution(); + +#if defined(OS_WIN) + // Translates an absolute QPC timestamp into a TimeTicks value. The returned + // value has the same origin as Now(). Do NOT attempt to use this if + // IsHighResolution() returns false. + static TimeTicks FromQPCValue(LONGLONG qpc_value); +#endif + + // Get the TimeTick value at the time of the UnixEpoch. This is useful when + // you need to relate the value of TimeTicks to a real time and date. + // Note: Upon first invocation, this function takes a snapshot of the realtime + // clock to establish a reference point. This function will return the same + // value for the duration of the application, but will be different in future + // application runs. + static TimeTicks UnixEpoch(); + + // Returns |this| snapped to the next tick, given a |tick_phase| and + // repeating |tick_interval| in both directions. |this| may be before, + // after, or equal to the |tick_phase|. + TimeTicks SnappedToNextTick(TimeTicks tick_phase, + TimeDelta tick_interval) const; + +#if defined(OS_WIN) + protected: + typedef DWORD (*TickFunctionType)(void); + static TickFunctionType SetMockTickFunction(TickFunctionType ticker); +#endif + + private: + friend class time_internal::TimeBase<TimeTicks>; + + // Please use Now() to create a new object. This is for internal use + // and testing. + explicit TimeTicks(int64 us) : TimeBase(us) { + } +}; + +// For logging use only. +std::ostream& operator<<(std::ostream& os, TimeTicks time_ticks); + +// ThreadTicks ---------------------------------------------------------------- + +// Represents a clock, specific to a particular thread, than runs only while the +// thread is running. +class ThreadTicks : public time_internal::TimeBase<ThreadTicks> { + public: + ThreadTicks() : TimeBase(0) { + } + + // Returns true if ThreadTicks::Now() is supported on this system. + static bool IsSupported() { +#if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \ + (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_ANDROID) + return true; +#else + return false; +#endif + } + + // Returns thread-specific CPU-time on systems that support this feature. + // Needs to be guarded with a call to IsSupported(). Use this timer + // to (approximately) measure how much time the calling thread spent doing + // actual work vs. being de-scheduled. May return bogus results if the thread + // migrates to another CPU between two calls. + static ThreadTicks Now(); + + private: + friend class time_internal::TimeBase<ThreadTicks>; + + // Please use Now() to create a new object. This is for internal use + // and testing. + explicit ThreadTicks(int64 us) : TimeBase(us) { + } +}; + +// For logging use only. +std::ostream& operator<<(std::ostream& os, ThreadTicks time_ticks); + +// TraceTicks ---------------------------------------------------------------- + +// Represents high-resolution system trace clock time. +class TraceTicks : public time_internal::TimeBase<TraceTicks> { + public: + // We define this even without OS_CHROMEOS for seccomp sandbox testing. +#if defined(OS_LINUX) + // Force definition of the system trace clock; it is a chromeos-only api + // at the moment and surfacing it in the right place requires mucking + // with glibc et al. + static const clockid_t kClockSystemTrace = 11; +#endif + + TraceTicks() : TimeBase(0) { + } + + // Returns the current system trace time or, if not available on this + // platform, a high-resolution time value; or a low-resolution time value if + // neither are avalable. On systems where a global trace clock is defined, + // timestamping TraceEvents's with this value guarantees synchronization + // between events collected inside chrome and events collected outside + // (e.g. kernel, X server). + // + // On some platforms, the clock source used for tracing can vary depending on + // hardware and/or kernel support. Do not make any assumptions without + // consulting the documentation for this functionality in the time_win.cc, + // time_posix.cc, etc. files. + // + // NOTE: This is only meant to be used by the event tracing infrastructure, + // and by outside code modules in special circumstances. Please be sure to + // consult a base/trace_event/OWNER before committing any new code that uses + // this. + static TraceTicks Now(); + + private: + friend class time_internal::TimeBase<TraceTicks>; + + // Please use Now() to create a new object. This is for internal use + // and testing. + explicit TraceTicks(int64 us) : TimeBase(us) { + } +}; + +// For logging use only. +std::ostream& operator<<(std::ostream& os, TraceTicks time_ticks); + +} // namespace base + +#endif // BASE_TIME_TIME_H_ diff --git a/third_party/chromium/base/time/time_posix.cc b/third_party/chromium/base/time/time_posix.cc new file mode 100644 index 0000000..b625af6 --- /dev/null +++ b/third_party/chromium/base/time/time_posix.cc @@ -0,0 +1,368 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/time/time.h" + +#include <stdint.h> +#include <sys/time.h> +#include <time.h> +#if defined(OS_ANDROID) && !defined(__LP64__) +#include <time64.h> +#endif +#include <unistd.h> + +#include <limits> +#include <ostream> + +#include "base/basictypes.h" +#include "base/build/build_config.h" +#include "base/logging.h" + +namespace { + +#if !defined(OS_MACOSX) +// Define a system-specific SysTime that wraps either to a time_t or +// a time64_t depending on the host system, and associated convertion. +// See crbug.com/162007 +#if defined(OS_ANDROID) && !defined(__LP64__) +typedef time64_t SysTime; + +SysTime SysTimeFromTimeStruct(struct tm* timestruct, bool is_local) { + if (is_local) + return mktime64(timestruct); + else + return timegm64(timestruct); +} + +void SysTimeToTimeStruct(SysTime t, struct tm* timestruct, bool is_local) { + if (is_local) + localtime64_r(&t, timestruct); + else + gmtime64_r(&t, timestruct); +} + +#else // OS_ANDROID && !__LP64__ +typedef time_t SysTime; + +SysTime SysTimeFromTimeStruct(struct tm* timestruct, bool is_local) { + if (is_local) + return mktime(timestruct); + else + return timegm(timestruct); +} + +void SysTimeToTimeStruct(SysTime t, struct tm* timestruct, bool is_local) { + if (is_local) + localtime_r(&t, timestruct); + else + gmtime_r(&t, timestruct); +} +#endif // OS_ANDROID + +int64 ConvertTimespecToMicros(const struct timespec& ts) { + base::CheckedNumeric<int64> result(ts.tv_sec); + result *= base::Time::kMicrosecondsPerSecond; + result += (ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond); + return result.ValueOrDie(); +} + +// Helper function to get results from clock_gettime() and convert to a +// microsecond timebase. Minimum requirement is MONOTONIC_CLOCK to be supported +// on the system. FreeBSD 6 has CLOCK_MONOTONIC but defines +// _POSIX_MONOTONIC_CLOCK to -1. +#if (defined(OS_POSIX) && \ + defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0) || \ + defined(OS_BSD) || defined(OS_ANDROID) +int64 ClockNow(clockid_t clk_id) { + struct timespec ts; + if (clock_gettime(clk_id, &ts) != 0) { + NOTREACHED() << "clock_gettime(" << clk_id << ") failed."; + return 0; + } + return ConvertTimespecToMicros(ts); +} +#else // _POSIX_MONOTONIC_CLOCK +#error No usable tick clock function on this platform. +#endif // _POSIX_MONOTONIC_CLOCK +#endif // !defined(OS_MACOSX) + +} // namespace + +namespace base { + +struct timespec TimeDelta::ToTimeSpec() const { + int64 microseconds = InMicroseconds(); + time_t seconds = 0; + if (microseconds >= Time::kMicrosecondsPerSecond) { + seconds = InSeconds(); + microseconds -= seconds * Time::kMicrosecondsPerSecond; + } + struct timespec result = + {seconds, + static_cast<long>(microseconds * Time::kNanosecondsPerMicrosecond)}; + return result; +} + +#if !defined(OS_MACOSX) +// The Time routines in this file use standard POSIX routines, or almost- +// standard routines in the case of timegm. We need to use a Mach-specific +// function for TimeTicks::Now() on Mac OS X. + +// Time ----------------------------------------------------------------------- + +// Windows uses a Gregorian epoch of 1601. We need to match this internally +// so that our time representations match across all platforms. See bug 14734. +// irb(main):010:0> Time.at(0).getutc() +// => Thu Jan 01 00:00:00 UTC 1970 +// irb(main):011:0> Time.at(-11644473600).getutc() +// => Mon Jan 01 00:00:00 UTC 1601 +static const int64 kWindowsEpochDeltaSeconds = INT64_C(11644473600); + +// static +const int64 Time::kWindowsEpochDeltaMicroseconds = + kWindowsEpochDeltaSeconds * Time::kMicrosecondsPerSecond; + +// Some functions in time.cc use time_t directly, so we provide an offset +// to convert from time_t (Unix epoch) and internal (Windows epoch). +// static +const int64 Time::kTimeTToMicrosecondsOffset = kWindowsEpochDeltaMicroseconds; + +// static +Time Time::Now() { + struct timeval tv; + struct timezone tz = { 0, 0 }; // UTC + if (gettimeofday(&tv, &tz) != 0) { + DCHECK(0) << "Could not determine time of day"; + LOG(ERROR) << "Call to gettimeofday failed."; + // Return null instead of uninitialized |tv| value, which contains random + // garbage data. This may result in the crash seen in crbug.com/147570. + return Time(); + } + // Combine seconds and microseconds in a 64-bit field containing microseconds + // since the epoch. That's enough for nearly 600 centuries. Adjust from + // Unix (1970) to Windows (1601) epoch. + return Time((tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec) + + kWindowsEpochDeltaMicroseconds); +} + +// static +Time Time::NowFromSystemTime() { + // Just use Now() because Now() returns the system time. + return Now(); +} + +void Time::Explode(bool is_local, Exploded* exploded) const { + // Time stores times with microsecond resolution, but Exploded only carries + // millisecond resolution, so begin by being lossy. Adjust from Windows + // epoch (1601) to Unix epoch (1970); + int64 microseconds = us_ - kWindowsEpochDeltaMicroseconds; + // The following values are all rounded towards -infinity. + int64 milliseconds; // Milliseconds since epoch. + SysTime seconds; // Seconds since epoch. + int millisecond; // Exploded millisecond value (0-999). + if (microseconds >= 0) { + // Rounding towards -infinity <=> rounding towards 0, in this case. + milliseconds = microseconds / kMicrosecondsPerMillisecond; + seconds = milliseconds / kMillisecondsPerSecond; + millisecond = milliseconds % kMillisecondsPerSecond; + } else { + // Round these *down* (towards -infinity). + milliseconds = (microseconds - kMicrosecondsPerMillisecond + 1) / + kMicrosecondsPerMillisecond; + seconds = (milliseconds - kMillisecondsPerSecond + 1) / + kMillisecondsPerSecond; + // Make this nonnegative (and between 0 and 999 inclusive). + millisecond = milliseconds % kMillisecondsPerSecond; + if (millisecond < 0) + millisecond += kMillisecondsPerSecond; + } + + struct tm timestruct; + SysTimeToTimeStruct(seconds, ×truct, is_local); + + exploded->year = timestruct.tm_year + 1900; + exploded->month = timestruct.tm_mon + 1; + exploded->day_of_week = timestruct.tm_wday; + exploded->day_of_month = timestruct.tm_mday; + exploded->hour = timestruct.tm_hour; + exploded->minute = timestruct.tm_min; + exploded->second = timestruct.tm_sec; + exploded->millisecond = millisecond; +} + +// static +Time Time::FromExploded(bool is_local, const Exploded& exploded) { + struct tm timestruct; + timestruct.tm_sec = exploded.second; + timestruct.tm_min = exploded.minute; + timestruct.tm_hour = exploded.hour; + timestruct.tm_mday = exploded.day_of_month; + timestruct.tm_mon = exploded.month - 1; + timestruct.tm_year = exploded.year - 1900; + timestruct.tm_wday = exploded.day_of_week; // mktime/timegm ignore this + timestruct.tm_yday = 0; // mktime/timegm ignore this + timestruct.tm_isdst = -1; // attempt to figure it out +#if !defined(OS_NACL) && !defined(OS_SOLARIS) + timestruct.tm_gmtoff = 0; // not a POSIX field, so mktime/timegm ignore + timestruct.tm_zone = NULL; // not a POSIX field, so mktime/timegm ignore +#endif + + + int64 milliseconds; + SysTime seconds; + + // Certain exploded dates do not really exist due to daylight saving times, + // and this causes mktime() to return implementation-defined values when + // tm_isdst is set to -1. On Android, the function will return -1, while the + // C libraries of other platforms typically return a liberally-chosen value. + // Handling this requires the special code below. + + // SysTimeFromTimeStruct() modifies the input structure, save current value. + struct tm timestruct0 = timestruct; + + seconds = SysTimeFromTimeStruct(×truct, is_local); + if (seconds == -1) { + // Get the time values with tm_isdst == 0 and 1, then select the closest one + // to UTC 00:00:00 that isn't -1. + timestruct = timestruct0; + timestruct.tm_isdst = 0; + int64 seconds_isdst0 = SysTimeFromTimeStruct(×truct, is_local); + + timestruct = timestruct0; + timestruct.tm_isdst = 1; + int64 seconds_isdst1 = SysTimeFromTimeStruct(×truct, is_local); + + // seconds_isdst0 or seconds_isdst1 can be -1 for some timezones. + // E.g. "CLST" (Chile Summer Time) returns -1 for 'tm_isdt == 1'. + if (seconds_isdst0 < 0) + seconds = seconds_isdst1; + else if (seconds_isdst1 < 0) + seconds = seconds_isdst0; + else + seconds = std::min(seconds_isdst0, seconds_isdst1); + } + + // Handle overflow. Clamping the range to what mktime and timegm might + // return is the best that can be done here. It's not ideal, but it's better + // than failing here or ignoring the overflow case and treating each time + // overflow as one second prior to the epoch. + if (seconds == -1 && + (exploded.year < 1969 || exploded.year > 1970)) { + // If exploded.year is 1969 or 1970, take -1 as correct, with the + // time indicating 1 second prior to the epoch. (1970 is allowed to handle + // time zone and DST offsets.) Otherwise, return the most future or past + // time representable. Assumes the time_t epoch is 1970-01-01 00:00:00 UTC. + // + // The minimum and maximum representible times that mktime and timegm could + // return are used here instead of values outside that range to allow for + // proper round-tripping between exploded and counter-type time + // representations in the presence of possible truncation to time_t by + // division and use with other functions that accept time_t. + // + // When representing the most distant time in the future, add in an extra + // 999ms to avoid the time being less than any other possible value that + // this function can return. + + // On Android, SysTime is int64, special care must be taken to avoid + // overflows. + const int64 min_seconds = (sizeof(SysTime) < sizeof(int64)) + ? std::numeric_limits<SysTime>::min() + : std::numeric_limits<int32_t>::min(); + const int64 max_seconds = (sizeof(SysTime) < sizeof(int64)) + ? std::numeric_limits<SysTime>::max() + : std::numeric_limits<int32_t>::max(); + if (exploded.year < 1969) { + milliseconds = min_seconds * kMillisecondsPerSecond; + } else { + milliseconds = max_seconds * kMillisecondsPerSecond; + milliseconds += (kMillisecondsPerSecond - 1); + } + } else { + milliseconds = seconds * kMillisecondsPerSecond + exploded.millisecond; + } + + // Adjust from Unix (1970) to Windows (1601) epoch. + return Time((milliseconds * kMicrosecondsPerMillisecond) + + kWindowsEpochDeltaMicroseconds); +} + +// TimeTicks ------------------------------------------------------------------ +// static +TimeTicks TimeTicks::Now() { + return TimeTicks(ClockNow(CLOCK_MONOTONIC)); +} + +// static +bool TimeTicks::IsHighResolution() { + return true; +} + +// static +ThreadTicks ThreadTicks::Now() { +#if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \ + defined(OS_ANDROID) + return ThreadTicks(ClockNow(CLOCK_THREAD_CPUTIME_ID)); +#else + NOTREACHED(); + return ThreadTicks(); +#endif +} + +// Use the Chrome OS specific system-wide clock. +#if defined(OS_CHROMEOS) +// static +TraceTicks TraceTicks::Now() { + struct timespec ts; + if (clock_gettime(kClockSystemTrace, &ts) != 0) { + // NB: fall-back for a chrome os build running on linux + return TraceTicks(ClockNow(CLOCK_MONOTONIC)); + } + return TraceTicks(ConvertTimespecToMicros(ts)); +} + +#else // !defined(OS_CHROMEOS) + +// static +TraceTicks TraceTicks::Now() { + return TraceTicks(ClockNow(CLOCK_MONOTONIC)); +} + +#endif // defined(OS_CHROMEOS) + +#endif // !OS_MACOSX + +// static +Time Time::FromTimeVal(struct timeval t) { + DCHECK_LT(t.tv_usec, static_cast<int>(Time::kMicrosecondsPerSecond)); + DCHECK_GE(t.tv_usec, 0); + if (t.tv_usec == 0 && t.tv_sec == 0) + return Time(); + if (t.tv_usec == static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1 && + t.tv_sec == std::numeric_limits<time_t>::max()) + return Max(); + return Time( + (static_cast<int64>(t.tv_sec) * Time::kMicrosecondsPerSecond) + + t.tv_usec + + kTimeTToMicrosecondsOffset); +} + +struct timeval Time::ToTimeVal() const { + struct timeval result; + if (is_null()) { + result.tv_sec = 0; + result.tv_usec = 0; + return result; + } + if (is_max()) { + result.tv_sec = std::numeric_limits<time_t>::max(); + result.tv_usec = static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1; + return result; + } + int64 us = us_ - kTimeTToMicrosecondsOffset; + result.tv_sec = us / Time::kMicrosecondsPerSecond; + result.tv_usec = us % Time::kMicrosecondsPerSecond; + return result; +} + +} // namespace base diff --git a/third_party/chromium/base/time/time_unittest.cc b/third_party/chromium/base/time/time_unittest.cc new file mode 100644 index 0000000..43373e7 --- /dev/null +++ b/third_party/chromium/base/time/time_unittest.cc @@ -0,0 +1,848 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/time/time.h" + +#include <stdint.h> +#include <time.h> +#include <limits> +#include <string> + +#include <gtest/gtest.h> + +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "base/strings/stringprintf.h" +#include "base/build/build_config.h" + +namespace base { + +namespace { + +// Specialized test fixture allowing time strings without timezones to be +// tested by comparing them to a known time in the local zone. +// See also pr_time_unittests.cc +class TimeTest : public testing::Test { + protected: + void SetUp() override { + // Use mktime to get a time_t, and turn it into a PRTime by converting + // seconds to microseconds. Use 15th Oct 2007 12:45:00 local. This + // must be a time guaranteed to be outside of a DST fallback hour in + // any timezone. + struct tm local_comparison_tm = { + 0, // second + 45, // minute + 12, // hour + 15, // day of month + 10 - 1, // month + 2007 - 1900, // year + 0, // day of week (ignored, output only) + 0, // day of year (ignored, output only) + -1 // DST in effect, -1 tells mktime to figure it out + }; + + time_t converted_time = mktime(&local_comparison_tm); + ASSERT_GT(converted_time, 0); + comparison_time_local_ = Time::FromTimeT(converted_time); + + // time_t representation of 15th Oct 2007 12:45:00 PDT + comparison_time_pdt_ = Time::FromTimeT(1192477500); + } + + Time comparison_time_local_; + Time comparison_time_pdt_; +}; + +// Test conversions to/from time_t and exploding/unexploding. +TEST_F(TimeTest, TimeT) { + // C library time and exploded time. + time_t now_t_1 = time(NULL); + struct tm tms; +#if defined(OS_WIN) + localtime_s(&tms, &now_t_1); +#elif defined(OS_POSIX) + localtime_r(&now_t_1, &tms); +#endif + + // Convert to ours. + Time our_time_1 = Time::FromTimeT(now_t_1); + Time::Exploded exploded; + our_time_1.LocalExplode(&exploded); + + // This will test both our exploding and our time_t -> Time conversion. + EXPECT_EQ(tms.tm_year + 1900, exploded.year); + EXPECT_EQ(tms.tm_mon + 1, exploded.month); + EXPECT_EQ(tms.tm_mday, exploded.day_of_month); + EXPECT_EQ(tms.tm_hour, exploded.hour); + EXPECT_EQ(tms.tm_min, exploded.minute); + EXPECT_EQ(tms.tm_sec, exploded.second); + + // Convert exploded back to the time struct. + Time our_time_2 = Time::FromLocalExploded(exploded); + EXPECT_TRUE(our_time_1 == our_time_2); + + time_t now_t_2 = our_time_2.ToTimeT(); + EXPECT_EQ(now_t_1, now_t_2); + + EXPECT_EQ(10, Time().FromTimeT(10).ToTimeT()); + EXPECT_EQ(10.0, Time().FromTimeT(10).ToDoubleT()); + + // Conversions of 0 should stay 0. + EXPECT_EQ(0, Time().ToTimeT()); + EXPECT_EQ(0, Time::FromTimeT(0).ToInternalValue()); +} + +// Test conversions to/from javascript time. +TEST_F(TimeTest, JsTime) { + Time epoch = Time::FromJsTime(0.0); + EXPECT_EQ(epoch, Time::UnixEpoch()); + Time t = Time::FromJsTime(700000.3); + EXPECT_EQ(700.0003, t.ToDoubleT()); + t = Time::FromDoubleT(800.73); + EXPECT_EQ(800730.0, t.ToJsTime()); +} + +#if defined(OS_POSIX) +TEST_F(TimeTest, FromTimeVal) { + Time now = Time::Now(); + Time also_now = Time::FromTimeVal(now.ToTimeVal()); + EXPECT_EQ(now, also_now); +} +#endif // OS_POSIX + +TEST_F(TimeTest, FromExplodedWithMilliseconds) { + // Some platform implementations of FromExploded are liable to drop + // milliseconds if we aren't careful. + Time now = Time::NowFromSystemTime(); + Time::Exploded exploded1 = {0}; + now.UTCExplode(&exploded1); + exploded1.millisecond = 500; + Time time = Time::FromUTCExploded(exploded1); + Time::Exploded exploded2 = {0}; + time.UTCExplode(&exploded2); + EXPECT_EQ(exploded1.millisecond, exploded2.millisecond); +} + +TEST_F(TimeTest, ZeroIsSymmetric) { + Time zero_time(Time::FromTimeT(0)); + EXPECT_EQ(0, zero_time.ToTimeT()); + + EXPECT_EQ(0.0, zero_time.ToDoubleT()); +} + +TEST_F(TimeTest, LocalExplode) { + Time a = Time::Now(); + Time::Exploded exploded; + a.LocalExplode(&exploded); + + Time b = Time::FromLocalExploded(exploded); + + // The exploded structure doesn't have microseconds, and on Mac & Linux, the + // internal OS conversion uses seconds, which will cause truncation. So we + // can only make sure that the delta is within one second. + EXPECT_TRUE((a - b) < TimeDelta::FromSeconds(1)); +} + +TEST_F(TimeTest, UTCExplode) { + Time a = Time::Now(); + Time::Exploded exploded; + a.UTCExplode(&exploded); + + Time b = Time::FromUTCExploded(exploded); + EXPECT_TRUE((a - b) < TimeDelta::FromSeconds(1)); +} + +TEST_F(TimeTest, LocalMidnight) { + Time::Exploded exploded; + Time::Now().LocalMidnight().LocalExplode(&exploded); + EXPECT_EQ(0, exploded.hour); + EXPECT_EQ(0, exploded.minute); + EXPECT_EQ(0, exploded.second); + EXPECT_EQ(0, exploded.millisecond); +} + +TEST_F(TimeTest, ExplodeBeforeUnixEpoch) { + static const int kUnixEpochYear = 1970; // In case this changes (ha!). + Time t; + Time::Exploded exploded; + + t = Time::UnixEpoch() - TimeDelta::FromMicroseconds(1); + t.UTCExplode(&exploded); + EXPECT_TRUE(exploded.HasValidValues()); + // Should be 1969-12-31 23:59:59 999 milliseconds (and 999 microseconds). + EXPECT_EQ(kUnixEpochYear - 1, exploded.year); + EXPECT_EQ(12, exploded.month); + EXPECT_EQ(31, exploded.day_of_month); + EXPECT_EQ(23, exploded.hour); + EXPECT_EQ(59, exploded.minute); + EXPECT_EQ(59, exploded.second); + EXPECT_EQ(999, exploded.millisecond); + + t = Time::UnixEpoch() - TimeDelta::FromMicroseconds(1000); + t.UTCExplode(&exploded); + EXPECT_TRUE(exploded.HasValidValues()); + // Should be 1969-12-31 23:59:59 999 milliseconds. + EXPECT_EQ(kUnixEpochYear - 1, exploded.year); + EXPECT_EQ(12, exploded.month); + EXPECT_EQ(31, exploded.day_of_month); + EXPECT_EQ(23, exploded.hour); + EXPECT_EQ(59, exploded.minute); + EXPECT_EQ(59, exploded.second); + EXPECT_EQ(999, exploded.millisecond); + + t = Time::UnixEpoch() - TimeDelta::FromMicroseconds(1001); + t.UTCExplode(&exploded); + EXPECT_TRUE(exploded.HasValidValues()); + // Should be 1969-12-31 23:59:59 998 milliseconds (and 999 microseconds). + EXPECT_EQ(kUnixEpochYear - 1, exploded.year); + EXPECT_EQ(12, exploded.month); + EXPECT_EQ(31, exploded.day_of_month); + EXPECT_EQ(23, exploded.hour); + EXPECT_EQ(59, exploded.minute); + EXPECT_EQ(59, exploded.second); + EXPECT_EQ(998, exploded.millisecond); + + t = Time::UnixEpoch() - TimeDelta::FromMilliseconds(1000); + t.UTCExplode(&exploded); + EXPECT_TRUE(exploded.HasValidValues()); + // Should be 1969-12-31 23:59:59. + EXPECT_EQ(kUnixEpochYear - 1, exploded.year); + EXPECT_EQ(12, exploded.month); + EXPECT_EQ(31, exploded.day_of_month); + EXPECT_EQ(23, exploded.hour); + EXPECT_EQ(59, exploded.minute); + EXPECT_EQ(59, exploded.second); + EXPECT_EQ(0, exploded.millisecond); + + t = Time::UnixEpoch() - TimeDelta::FromMilliseconds(1001); + t.UTCExplode(&exploded); + EXPECT_TRUE(exploded.HasValidValues()); + // Should be 1969-12-31 23:59:58 999 milliseconds. + EXPECT_EQ(kUnixEpochYear - 1, exploded.year); + EXPECT_EQ(12, exploded.month); + EXPECT_EQ(31, exploded.day_of_month); + EXPECT_EQ(23, exploded.hour); + EXPECT_EQ(59, exploded.minute); + EXPECT_EQ(58, exploded.second); + EXPECT_EQ(999, exploded.millisecond); + + // Make sure we still handle at/after Unix epoch correctly. + t = Time::UnixEpoch(); + t.UTCExplode(&exploded); + EXPECT_TRUE(exploded.HasValidValues()); + // Should be 1970-12-31 00:00:00 0 milliseconds. + EXPECT_EQ(kUnixEpochYear, exploded.year); + EXPECT_EQ(1, exploded.month); + EXPECT_EQ(1, exploded.day_of_month); + EXPECT_EQ(0, exploded.hour); + EXPECT_EQ(0, exploded.minute); + EXPECT_EQ(0, exploded.second); + EXPECT_EQ(0, exploded.millisecond); + + t = Time::UnixEpoch() + TimeDelta::FromMicroseconds(1); + t.UTCExplode(&exploded); + EXPECT_TRUE(exploded.HasValidValues()); + // Should be 1970-01-01 00:00:00 0 milliseconds (and 1 microsecond). + EXPECT_EQ(kUnixEpochYear, exploded.year); + EXPECT_EQ(1, exploded.month); + EXPECT_EQ(1, exploded.day_of_month); + EXPECT_EQ(0, exploded.hour); + EXPECT_EQ(0, exploded.minute); + EXPECT_EQ(0, exploded.second); + EXPECT_EQ(0, exploded.millisecond); + + t = Time::UnixEpoch() + TimeDelta::FromMicroseconds(1000); + t.UTCExplode(&exploded); + EXPECT_TRUE(exploded.HasValidValues()); + // Should be 1970-01-01 00:00:00 1 millisecond. + EXPECT_EQ(kUnixEpochYear, exploded.year); + EXPECT_EQ(1, exploded.month); + EXPECT_EQ(1, exploded.day_of_month); + EXPECT_EQ(0, exploded.hour); + EXPECT_EQ(0, exploded.minute); + EXPECT_EQ(0, exploded.second); + EXPECT_EQ(1, exploded.millisecond); + + t = Time::UnixEpoch() + TimeDelta::FromMilliseconds(1000); + t.UTCExplode(&exploded); + EXPECT_TRUE(exploded.HasValidValues()); + // Should be 1970-01-01 00:00:01. + EXPECT_EQ(kUnixEpochYear, exploded.year); + EXPECT_EQ(1, exploded.month); + EXPECT_EQ(1, exploded.day_of_month); + EXPECT_EQ(0, exploded.hour); + EXPECT_EQ(0, exploded.minute); + EXPECT_EQ(1, exploded.second); + EXPECT_EQ(0, exploded.millisecond); + + t = Time::UnixEpoch() + TimeDelta::FromMilliseconds(1001); + t.UTCExplode(&exploded); + EXPECT_TRUE(exploded.HasValidValues()); + // Should be 1970-01-01 00:00:01 1 millisecond. + EXPECT_EQ(kUnixEpochYear, exploded.year); + EXPECT_EQ(1, exploded.month); + EXPECT_EQ(1, exploded.day_of_month); + EXPECT_EQ(0, exploded.hour); + EXPECT_EQ(0, exploded.minute); + EXPECT_EQ(1, exploded.second); + EXPECT_EQ(1, exploded.millisecond); +} + +TEST_F(TimeTest, TimeDeltaMax) { + TimeDelta max = TimeDelta::Max(); + EXPECT_TRUE(max.is_max()); + EXPECT_EQ(max, TimeDelta::Max()); + EXPECT_GT(max, TimeDelta::FromDays(100 * 365)); + EXPECT_GT(max, TimeDelta()); +} + +TEST_F(TimeTest, TimeDeltaMaxConversions) { + TimeDelta t = TimeDelta::Max(); + EXPECT_EQ(std::numeric_limits<int64>::max(), t.ToInternalValue()); + + EXPECT_EQ(std::numeric_limits<int>::max(), t.InDays()); + EXPECT_EQ(std::numeric_limits<int>::max(), t.InHours()); + EXPECT_EQ(std::numeric_limits<int>::max(), t.InMinutes()); + EXPECT_EQ(std::numeric_limits<double>::infinity(), t.InSecondsF()); + EXPECT_EQ(std::numeric_limits<int64>::max(), t.InSeconds()); + EXPECT_EQ(std::numeric_limits<double>::infinity(), t.InMillisecondsF()); + EXPECT_EQ(std::numeric_limits<int64>::max(), t.InMilliseconds()); + EXPECT_EQ(std::numeric_limits<int64>::max(), t.InMillisecondsRoundedUp()); + + t = TimeDelta::FromDays(std::numeric_limits<int>::max()); + EXPECT_TRUE(t.is_max()); + + t = TimeDelta::FromHours(std::numeric_limits<int>::max()); + EXPECT_TRUE(t.is_max()); + + t = TimeDelta::FromMinutes(std::numeric_limits<int>::max()); + EXPECT_TRUE(t.is_max()); + + t = TimeDelta::FromSeconds(std::numeric_limits<int64>::max()); + EXPECT_TRUE(t.is_max()); + + t = TimeDelta::FromMilliseconds(std::numeric_limits<int64>::max()); + EXPECT_TRUE(t.is_max()); + + t = TimeDelta::FromSecondsD(std::numeric_limits<double>::infinity()); + EXPECT_TRUE(t.is_max()); + + t = TimeDelta::FromMillisecondsD(std::numeric_limits<double>::infinity()); + EXPECT_TRUE(t.is_max()); + + t = TimeDelta::FromMicroseconds(std::numeric_limits<int64>::max()); + EXPECT_TRUE(t.is_max()); +} + +TEST_F(TimeTest, Max) { + Time max = Time::Max(); + EXPECT_TRUE(max.is_max()); + EXPECT_EQ(max, Time::Max()); + EXPECT_GT(max, Time::Now()); + EXPECT_GT(max, Time()); +} + +TEST_F(TimeTest, MaxConversions) { + Time t = Time::Max(); + EXPECT_EQ(std::numeric_limits<int64>::max(), t.ToInternalValue()); + + t = Time::FromDoubleT(std::numeric_limits<double>::infinity()); + EXPECT_TRUE(t.is_max()); + EXPECT_EQ(std::numeric_limits<double>::infinity(), t.ToDoubleT()); + + t = Time::FromJsTime(std::numeric_limits<double>::infinity()); + EXPECT_TRUE(t.is_max()); + EXPECT_EQ(std::numeric_limits<double>::infinity(), t.ToJsTime()); + + t = Time::FromTimeT(std::numeric_limits<time_t>::max()); + EXPECT_TRUE(t.is_max()); + EXPECT_EQ(std::numeric_limits<time_t>::max(), t.ToTimeT()); + +#if defined(OS_POSIX) + struct timeval tval; + tval.tv_sec = std::numeric_limits<time_t>::max(); + tval.tv_usec = static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1; + t = Time::FromTimeVal(tval); + EXPECT_TRUE(t.is_max()); + tval = t.ToTimeVal(); + EXPECT_EQ(std::numeric_limits<time_t>::max(), tval.tv_sec); + EXPECT_EQ(static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1, + tval.tv_usec); +#endif + +#if defined(OS_MACOSX) + t = Time::FromCFAbsoluteTime(std::numeric_limits<CFAbsoluteTime>::infinity()); + EXPECT_TRUE(t.is_max()); + EXPECT_EQ(std::numeric_limits<CFAbsoluteTime>::infinity(), + t.ToCFAbsoluteTime()); +#endif + +#if defined(OS_WIN) + FILETIME ftime; + ftime.dwHighDateTime = std::numeric_limits<DWORD>::max(); + ftime.dwLowDateTime = std::numeric_limits<DWORD>::max(); + t = Time::FromFileTime(ftime); + EXPECT_TRUE(t.is_max()); + ftime = t.ToFileTime(); + EXPECT_EQ(std::numeric_limits<DWORD>::max(), ftime.dwHighDateTime); + EXPECT_EQ(std::numeric_limits<DWORD>::max(), ftime.dwLowDateTime); +#endif +} + +#if defined(OS_MACOSX) +TEST_F(TimeTest, TimeTOverflow) { + Time t = Time::FromInternalValue(std::numeric_limits<int64>::max() - 1); + EXPECT_FALSE(t.is_max()); + EXPECT_EQ(std::numeric_limits<time_t>::max(), t.ToTimeT()); +} +#endif + +#if defined(OS_ANDROID) +TEST_F(TimeTest, FromLocalExplodedCrashOnAndroid) { + // This crashed inside Time:: FromLocalExploded() on Android 4.1.2. + // See http://crbug.com/287821 + Time::Exploded midnight = {2013, // year + 10, // month + 0, // day_of_week + 13, // day_of_month + 0, // hour + 0, // minute + 0, // second + }; + // The string passed to putenv() must be a char* and the documentation states + // that it 'becomes part of the environment', so use a static buffer. + static char buffer[] = "TZ=America/Santiago"; + putenv(buffer); + tzset(); + Time t = Time::FromLocalExploded(midnight); + EXPECT_EQ(1381633200, t.ToTimeT()); +} +#endif // OS_ANDROID + +static void HighResClockTest(TimeTicks (*GetTicks)()) { + // IsHighResolution() is false on some systems. Since the product still works + // even if it's false, it makes this entire test questionable. + if (!TimeTicks::IsHighResolution()) + return; + + // Why do we loop here? + // We're trying to measure that intervals increment in a VERY small amount + // of time -- less than 15ms. Unfortunately, if we happen to have a + // context switch in the middle of our test, the context switch could easily + // exceed our limit. So, we iterate on this several times. As long as we're + // able to detect the fine-granularity timers at least once, then the test + // has succeeded. + + const int kTargetGranularityUs = 15000; // 15ms + + bool success = false; + int retries = 100; // Arbitrary. + TimeDelta delta; + while (!success && retries--) { + TimeTicks ticks_start = GetTicks(); + // Loop until we can detect that the clock has changed. Non-HighRes timers + // will increment in chunks, e.g. 15ms. By spinning until we see a clock + // change, we detect the minimum time between measurements. + do { + delta = GetTicks() - ticks_start; + } while (delta.InMilliseconds() == 0); + + if (delta.InMicroseconds() <= kTargetGranularityUs) + success = true; + } + + // In high resolution mode, we expect to see the clock increment + // in intervals less than 15ms. + EXPECT_TRUE(success); +} + +TEST(TimeTicks, HighRes) { + HighResClockTest(&TimeTicks::Now); +} + +TEST(TraceTicks, NowFromSystemTraceTime) { + // Re-use HighRes test for now since clock properties are identical. + using NowFunction = TimeTicks (*)(void); + HighResClockTest(reinterpret_cast<NowFunction>(&TraceTicks::Now)); +} + +TEST(TimeTicks, SnappedToNextTickBasic) { + base::TimeTicks phase = base::TimeTicks::FromInternalValue(4000); + base::TimeDelta interval = base::TimeDelta::FromMicroseconds(1000); + base::TimeTicks timestamp; + + // Timestamp in previous interval. + timestamp = base::TimeTicks::FromInternalValue(3500); + EXPECT_EQ(4000, + timestamp.SnappedToNextTick(phase, interval).ToInternalValue()); + + // Timestamp in next interval. + timestamp = base::TimeTicks::FromInternalValue(4500); + EXPECT_EQ(5000, + timestamp.SnappedToNextTick(phase, interval).ToInternalValue()); + + // Timestamp multiple intervals before. + timestamp = base::TimeTicks::FromInternalValue(2500); + EXPECT_EQ(3000, + timestamp.SnappedToNextTick(phase, interval).ToInternalValue()); + + // Timestamp multiple intervals after. + timestamp = base::TimeTicks::FromInternalValue(6500); + EXPECT_EQ(7000, + timestamp.SnappedToNextTick(phase, interval).ToInternalValue()); + + // Timestamp on previous interval. + timestamp = base::TimeTicks::FromInternalValue(3000); + EXPECT_EQ(3000, + timestamp.SnappedToNextTick(phase, interval).ToInternalValue()); + + // Timestamp on next interval. + timestamp = base::TimeTicks::FromInternalValue(5000); + EXPECT_EQ(5000, + timestamp.SnappedToNextTick(phase, interval).ToInternalValue()); + + // Timestamp equal to phase. + timestamp = base::TimeTicks::FromInternalValue(4000); + EXPECT_EQ(4000, + timestamp.SnappedToNextTick(phase, interval).ToInternalValue()); +} + +TEST(TimeTicks, SnappedToNextTickOverflow) { + // int(big_timestamp / interval) < 0, so this causes a crash if the number of + // intervals elapsed is attempted to be stored in an int. + base::TimeTicks phase = base::TimeTicks::FromInternalValue(0); + base::TimeDelta interval = base::TimeDelta::FromMicroseconds(4000); + base::TimeTicks big_timestamp = + base::TimeTicks::FromInternalValue(8635916564000); + + EXPECT_EQ(8635916564000, + big_timestamp.SnappedToNextTick(phase, interval).ToInternalValue()); + EXPECT_EQ(8635916564000, + big_timestamp.SnappedToNextTick(big_timestamp, interval) + .ToInternalValue()); +} + +TEST(TimeDelta, FromAndIn) { + EXPECT_TRUE(TimeDelta::FromDays(2) == TimeDelta::FromHours(48)); + EXPECT_TRUE(TimeDelta::FromHours(3) == TimeDelta::FromMinutes(180)); + EXPECT_TRUE(TimeDelta::FromMinutes(2) == TimeDelta::FromSeconds(120)); + EXPECT_TRUE(TimeDelta::FromSeconds(2) == TimeDelta::FromMilliseconds(2000)); + EXPECT_TRUE(TimeDelta::FromMilliseconds(2) == + TimeDelta::FromMicroseconds(2000)); + EXPECT_TRUE(TimeDelta::FromSecondsD(2.3) == + TimeDelta::FromMilliseconds(2300)); + EXPECT_TRUE(TimeDelta::FromMillisecondsD(2.5) == + TimeDelta::FromMicroseconds(2500)); + EXPECT_EQ(13, TimeDelta::FromDays(13).InDays()); + EXPECT_EQ(13, TimeDelta::FromHours(13).InHours()); + EXPECT_EQ(13, TimeDelta::FromMinutes(13).InMinutes()); + EXPECT_EQ(13, TimeDelta::FromSeconds(13).InSeconds()); + EXPECT_EQ(13.0, TimeDelta::FromSeconds(13).InSecondsF()); + EXPECT_EQ(13, TimeDelta::FromMilliseconds(13).InMilliseconds()); + EXPECT_EQ(13.0, TimeDelta::FromMilliseconds(13).InMillisecondsF()); + EXPECT_EQ(13, TimeDelta::FromSecondsD(13.1).InSeconds()); + EXPECT_EQ(13.1, TimeDelta::FromSecondsD(13.1).InSecondsF()); + EXPECT_EQ(13, TimeDelta::FromMillisecondsD(13.3).InMilliseconds()); + EXPECT_EQ(13.3, TimeDelta::FromMillisecondsD(13.3).InMillisecondsF()); + EXPECT_EQ(13, TimeDelta::FromMicroseconds(13).InMicroseconds()); +} + +#if defined(OS_POSIX) +TEST(TimeDelta, TimeSpecConversion) { + struct timespec result = TimeDelta::FromSeconds(0).ToTimeSpec(); + EXPECT_EQ(result.tv_sec, 0); + EXPECT_EQ(result.tv_nsec, 0); + + result = TimeDelta::FromSeconds(1).ToTimeSpec(); + EXPECT_EQ(result.tv_sec, 1); + EXPECT_EQ(result.tv_nsec, 0); + + result = TimeDelta::FromMicroseconds(1).ToTimeSpec(); + EXPECT_EQ(result.tv_sec, 0); + EXPECT_EQ(result.tv_nsec, 1000); + + result = TimeDelta::FromMicroseconds( + Time::kMicrosecondsPerSecond + 1).ToTimeSpec(); + EXPECT_EQ(result.tv_sec, 1); + EXPECT_EQ(result.tv_nsec, 1000); +} +#endif // OS_POSIX + +// Our internal time format is serialized in things like databases, so it's +// important that it's consistent across all our platforms. We use the 1601 +// Windows epoch as the internal format across all platforms. +TEST(TimeDelta, WindowsEpoch) { + Time::Exploded exploded; + exploded.year = 1970; + exploded.month = 1; + exploded.day_of_week = 0; // Should be unusued. + exploded.day_of_month = 1; + exploded.hour = 0; + exploded.minute = 0; + exploded.second = 0; + exploded.millisecond = 0; + Time t = Time::FromUTCExploded(exploded); + // Unix 1970 epoch. + EXPECT_EQ(INT64_C(11644473600000000), t.ToInternalValue()); + + // We can't test 1601 epoch, since the system time functions on Linux + // only compute years starting from 1900. +} + +// We could define this separately for Time, TimeTicks and TimeDelta but the +// definitions would be identical anyway. +template <class Any> +std::string AnyToString(Any any) { + std::ostringstream oss; + oss << any; + return oss.str(); +} + +TEST(TimeDelta, Magnitude) { + const int64 zero = 0; + EXPECT_EQ(TimeDelta::FromMicroseconds(zero), + TimeDelta::FromMicroseconds(zero).magnitude()); + + const int64 one = 1; + const int64 negative_one = -1; + EXPECT_EQ(TimeDelta::FromMicroseconds(one), + TimeDelta::FromMicroseconds(one).magnitude()); + EXPECT_EQ(TimeDelta::FromMicroseconds(one), + TimeDelta::FromMicroseconds(negative_one).magnitude()); + + const int64 max_int64_minus_one = std::numeric_limits<int64>::max() - 1; + const int64 min_int64_plus_two = std::numeric_limits<int64>::min() + 2; + EXPECT_EQ(TimeDelta::FromMicroseconds(max_int64_minus_one), + TimeDelta::FromMicroseconds(max_int64_minus_one).magnitude()); + EXPECT_EQ(TimeDelta::FromMicroseconds(max_int64_minus_one), + TimeDelta::FromMicroseconds(min_int64_plus_two).magnitude()); +} + + +TEST(TimeDelta, NumericOperators) { + double d = 0.5; + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + TimeDelta::FromMilliseconds(1000) * d); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + TimeDelta::FromMilliseconds(1000) / d); + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + TimeDelta::FromMilliseconds(1000) *= d); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + TimeDelta::FromMilliseconds(1000) /= d); + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + d * TimeDelta::FromMilliseconds(1000)); + + float f = 0.5; + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + TimeDelta::FromMilliseconds(1000) * f); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + TimeDelta::FromMilliseconds(1000) / f); + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + TimeDelta::FromMilliseconds(1000) *= f); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + TimeDelta::FromMilliseconds(1000) /= f); + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + f * TimeDelta::FromMilliseconds(1000)); + + + int i = 2; + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + TimeDelta::FromMilliseconds(1000) * i); + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + TimeDelta::FromMilliseconds(1000) / i); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + TimeDelta::FromMilliseconds(1000) *= i); + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + TimeDelta::FromMilliseconds(1000) /= i); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + i * TimeDelta::FromMilliseconds(1000)); + + int64_t i64 = 2; + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + TimeDelta::FromMilliseconds(1000) * i64); + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + TimeDelta::FromMilliseconds(1000) / i64); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + TimeDelta::FromMilliseconds(1000) *= i64); + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + TimeDelta::FromMilliseconds(1000) /= i64); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + i64 * TimeDelta::FromMilliseconds(1000)); + + + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + TimeDelta::FromMilliseconds(1000) * 0.5); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + TimeDelta::FromMilliseconds(1000) / 0.5); + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + TimeDelta::FromMilliseconds(1000) *= 0.5); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + TimeDelta::FromMilliseconds(1000) /= 0.5); + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + 0.5 * TimeDelta::FromMilliseconds(1000)); + + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + TimeDelta::FromMilliseconds(1000) * 2); + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + TimeDelta::FromMilliseconds(1000) / 2); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + TimeDelta::FromMilliseconds(1000) *= 2); + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + TimeDelta::FromMilliseconds(1000) /= 2); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + 2 * TimeDelta::FromMilliseconds(1000)); +} + +bool IsMin(TimeDelta delta) { + return (-delta).is_max(); +} + +TEST(TimeDelta, Overflows) { + // Some sanity checks. + EXPECT_TRUE(TimeDelta::Max().is_max()); + EXPECT_TRUE(IsMin(-TimeDelta::Max())); + EXPECT_GT(TimeDelta(), -TimeDelta::Max()); + + TimeDelta large_delta = TimeDelta::Max() - TimeDelta::FromMilliseconds(1); + TimeDelta large_negative = -large_delta; + EXPECT_GT(TimeDelta(), large_negative); + EXPECT_FALSE(large_delta.is_max()); + EXPECT_FALSE(IsMin(-large_negative)); + TimeDelta one_second = TimeDelta::FromSeconds(1); + + // Test +, -, * and / operators. + EXPECT_TRUE((large_delta + one_second).is_max()); + EXPECT_TRUE(IsMin(large_negative + (-one_second))); + EXPECT_TRUE(IsMin(large_negative - one_second)); + EXPECT_TRUE((large_delta - (-one_second)).is_max()); + EXPECT_TRUE((large_delta * 2).is_max()); + EXPECT_TRUE(IsMin(large_delta * -2)); + EXPECT_TRUE((large_delta / 0.5).is_max()); + EXPECT_TRUE(IsMin(large_delta / -0.5)); + + // Test +=, -=, *= and /= operators. + TimeDelta delta = large_delta; + delta += one_second; + EXPECT_TRUE(delta.is_max()); + delta = large_negative; + delta += -one_second; + EXPECT_TRUE(IsMin(delta)); + + delta = large_negative; + delta -= one_second; + EXPECT_TRUE(IsMin(delta)); + delta = large_delta; + delta -= -one_second; + EXPECT_TRUE(delta.is_max()); + + delta = large_delta; + delta *= 2; + EXPECT_TRUE(delta.is_max()); + delta = large_negative; + delta *= 1.5; + EXPECT_TRUE(IsMin(delta)); + + delta = large_delta; + delta /= 0.5; + EXPECT_TRUE(delta.is_max()); + delta = large_negative; + delta /= 0.5; + EXPECT_TRUE(IsMin(delta)); + + // Test operations with Time and TimeTicks. + EXPECT_TRUE((large_delta + Time::Now()).is_max()); + EXPECT_TRUE((large_delta + TimeTicks::Now()).is_max()); + EXPECT_TRUE((Time::Now() + large_delta).is_max()); + EXPECT_TRUE((TimeTicks::Now() + large_delta).is_max()); + + Time time_now = Time::Now(); + EXPECT_EQ(one_second, (time_now + one_second) - time_now); + EXPECT_EQ(-one_second, (time_now - one_second) - time_now); + + TimeTicks ticks_now = TimeTicks::Now(); + EXPECT_EQ(-one_second, (ticks_now - one_second) - ticks_now); + EXPECT_EQ(one_second, (ticks_now + one_second) - ticks_now); +} + +TEST(TimeDeltaLogging, DCheckEqCompiles) { + DCHECK_EQ(TimeDelta(), TimeDelta()); +} + +TEST(TimeDeltaLogging, EmptyIsZero) { + TimeDelta zero; + EXPECT_EQ("0s", AnyToString(zero)); +} + +TEST(TimeDeltaLogging, FiveHundredMs) { + TimeDelta five_hundred_ms = TimeDelta::FromMilliseconds(500); + EXPECT_EQ("0.5s", AnyToString(five_hundred_ms)); +} + +TEST(TimeDeltaLogging, MinusTenSeconds) { + TimeDelta minus_ten_seconds = TimeDelta::FromSeconds(-10); + EXPECT_EQ("-10s", AnyToString(minus_ten_seconds)); +} + +TEST(TimeDeltaLogging, DoesNotMessUpFormattingFlags) { + std::ostringstream oss; + std::ios_base::fmtflags flags_before = oss.flags(); + oss << TimeDelta(); + EXPECT_EQ(flags_before, oss.flags()); +} + +TEST(TimeDeltaLogging, DoesNotMakeStreamBad) { + std::ostringstream oss; + oss << TimeDelta(); + EXPECT_TRUE(oss.good()); +} + +TEST(TimeLogging, DCheckEqCompiles) { + DCHECK_EQ(Time(), Time()); +} + +TEST(TimeLogging, DoesNotMessUpFormattingFlags) { + std::ostringstream oss; + std::ios_base::fmtflags flags_before = oss.flags(); + oss << Time(); + EXPECT_EQ(flags_before, oss.flags()); +} + +TEST(TimeLogging, DoesNotMakeStreamBad) { + std::ostringstream oss; + oss << Time(); + EXPECT_TRUE(oss.good()); +} + +TEST(TimeTicksLogging, DCheckEqCompiles) { + DCHECK_EQ(TimeTicks(), TimeTicks()); +} + +TEST(TimeTicksLogging, ZeroTime) { + TimeTicks zero; + EXPECT_EQ("0 bogo-microseconds", AnyToString(zero)); +} + +TEST(TimeTicksLogging, FortyYearsLater) { + TimeTicks forty_years_later = + TimeTicks() + TimeDelta::FromDays(365.25 * 40); + EXPECT_EQ("1262304000000000 bogo-microseconds", + AnyToString(forty_years_later)); +} + +TEST(TimeTicksLogging, DoesNotMessUpFormattingFlags) { + std::ostringstream oss; + std::ios_base::fmtflags flags_before = oss.flags(); + oss << TimeTicks(); + EXPECT_EQ(flags_before, oss.flags()); +} + +TEST(TimeTicksLogging, DoesNotMakeStreamBad) { + std::ostringstream oss; + oss << TimeTicks(); + EXPECT_TRUE(oss.good()); +} + +} // namespace + +} // namespace base |