diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /security/sandbox/chromium/base/time | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'security/sandbox/chromium/base/time')
-rw-r--r-- | security/sandbox/chromium/base/time/time.cc | 349 | ||||
-rw-r--r-- | security/sandbox/chromium/base/time/time.h | 768 | ||||
-rw-r--r-- | security/sandbox/chromium/base/time/time_posix.cc | 363 | ||||
-rw-r--r-- | security/sandbox/chromium/base/time/time_win.cc | 616 |
4 files changed, 2096 insertions, 0 deletions
diff --git a/security/sandbox/chromium/base/time/time.cc b/security/sandbox/chromium/base/time/time.cc new file mode 100644 index 000000000..9188887e2 --- /dev/null +++ b/security/sandbox/chromium/base/time/time.cc @@ -0,0 +1,349 @@ +// 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/lazy_instance.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/strings/stringprintf.h" +#include "base/third_party/nspr/prtime.h" +#include "build/build_config.h" + +namespace base { + +// TimeDelta ------------------------------------------------------------------ + +// static +TimeDelta TimeDelta::Max() { + return TimeDelta(std::numeric_limits<int64_t>::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_t TimeDelta::InSeconds() const { + if (is_max()) { + // Preserve max to prevent overflow. + return std::numeric_limits<int64_t>::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_t TimeDelta::InMilliseconds() const { + if (is_max()) { + // Preserve max to prevent overflow. + return std::numeric_limits<int64_t>::max(); + } + return delta_ / Time::kMicrosecondsPerMillisecond; +} + +int64_t TimeDelta::InMillisecondsRoundedUp() const { + if (is_max()) { + // Preserve max to prevent overflow. + return std::numeric_limits<int64_t>::max(); + } + return (delta_ + Time::kMicrosecondsPerMillisecond - 1) / + Time::kMicrosecondsPerMillisecond; +} + +int64_t TimeDelta::InMicroseconds() const { + if (is_max()) { + // Preserve max to prevent overflow. + return std::numeric_limits<int64_t>::max(); + } + return delta_; +} + +namespace time_internal { + +int64_t SaturatedAdd(TimeDelta delta, int64_t value) { + CheckedNumeric<int64_t> rv(delta.delta_); + rv += value; + return FromCheckedNumeric(rv); +} + +int64_t SaturatedSub(TimeDelta delta, int64_t value) { + CheckedNumeric<int64_t> rv(delta.delta_); + rv -= value; + return FromCheckedNumeric(rv); +} + +int64_t FromCheckedNumeric(const CheckedNumeric<int64_t> 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_t limit = std::numeric_limits<int64_t>::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_t>::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(kTimeTToMicrosecondsOffset) + TimeDelta::FromSeconds(tt); +} + +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_t>::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. + return Time(kTimeTToMicrosecondsOffset) + TimeDelta::FromSecondsD(dt); +} + +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. + return Time(kTimeTToMicrosecondsOffset) + + TimeDelta::FromMillisecondsD(ms_since_epoch); +} + +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_t 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_t>::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); +} + +#if !defined(MOZ_SANDBOX) +// static +bool Time::FromStringInternal(const char* time_string, + bool is_local, + Time* parsed_time) { + DCHECK((time_string != NULL) && (parsed_time != NULL)); + + if (time_string[0] == '\0') + return false; + + PRTime result_time = 0; + PRStatus result = PR_ParseTimeString(time_string, + is_local ? PR_FALSE : PR_TRUE, + &result_time); + if (PR_SUCCESS != result) + return false; + + result_time += kTimeTToMicrosecondsOffset; + *parsed_time = Time(result_time); + return true; +} +#endif + +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); +}; + +static LazyInstance<UnixEpochSingleton>::Leaky + leaky_unix_epoch_singleton_instance = LAZY_INSTANCE_INITIALIZER; + +// Static +TimeTicks TimeTicks::UnixEpoch() { + return leaky_unix_epoch_singleton_instance.Get().unix_epoch(); +} + +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"; +} + +// 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/security/sandbox/chromium/base/time/time.h b/security/sandbox/chromium/base/time/time.h new file mode 100644 index 000000000..ea19d7ed9 --- /dev/null +++ b/security/sandbox/chromium/base/time/time.h @@ -0,0 +1,768 @@ +// 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 and ThreadTicks 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. + +#ifndef BASE_TIME_TIME_H_ +#define BASE_TIME_TIME_H_ + +#include <stdint.h> +#include <time.h> + +#include <iosfwd> +#include <limits> + +#include "base/base_export.h" +#include "base/numerics/safe_math.h" +#include "build/build_config.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> + +#include "base/gtest_prod_util.h" +#endif + +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_t argument and return +// value are in terms of a microsecond timebase. +BASE_EXPORT int64_t SaturatedAdd(TimeDelta delta, int64_t value); +BASE_EXPORT int64_t SaturatedSub(TimeDelta delta, int64_t value); + +// Clamp |value| on overflow and underflow conditions. The int64_t argument and +// return value are in terms of a microsecond timebase. +BASE_EXPORT int64_t FromCheckedNumeric(const CheckedNumeric<int64_t> 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_t secs); + static TimeDelta FromMilliseconds(int64_t ms); + static TimeDelta FromSecondsD(double secs); + static TimeDelta FromMillisecondsD(double ms); + static TimeDelta FromMicroseconds(int64_t 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_t 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_t 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_t overload for std::abs(). The following is a simple branchless + // implementation: + const int64_t 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_t>::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_t InSeconds() const; + double InMillisecondsF() const; + int64_t InMilliseconds() const; + int64_t InMillisecondsRoundedUp() const; + int64_t 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_t> rv(delta_); + rv *= a; + return TimeDelta(time_internal::FromCheckedNumeric(rv)); + } + template<typename T> + TimeDelta operator/(T a) const { + CheckedNumeric<int64_t> 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_t 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_t time_internal::SaturatedAdd(TimeDelta delta, int64_t value); + friend int64_t time_internal::SaturatedSub(TimeDelta delta, int64_t 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_t delta_us) : delta_(delta_us) {} + + // Private method to build a delta from a double. + static TimeDelta FromDouble(double value); + + // Delta in microseconds. + int64_t 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_t kHoursPerDay = 24; + static const int64_t kMillisecondsPerSecond = 1000; + static const int64_t kMillisecondsPerDay = + kMillisecondsPerSecond * 60 * 60 * kHoursPerDay; + static const int64_t kMicrosecondsPerMillisecond = 1000; + static const int64_t kMicrosecondsPerSecond = + kMicrosecondsPerMillisecond * kMillisecondsPerSecond; + static const int64_t kMicrosecondsPerMinute = kMicrosecondsPerSecond * 60; + static const int64_t kMicrosecondsPerHour = kMicrosecondsPerMinute * 60; + static const int64_t kMicrosecondsPerDay = + kMicrosecondsPerHour * kHoursPerDay; + static const int64_t kMicrosecondsPerWeek = kMicrosecondsPerDay * 7; + static const int64_t kNanosecondsPerMicrosecond = 1000; + static const int64_t 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_t>::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_t 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_t us) { return TimeClass(us); } + + protected: + explicit TimeBase(int64_t us) : us_(us) {} + + // Time value in a microsecond timebase. + int64_t 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_t 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_t 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. + enum : int64_t{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 BASE_EXPORT 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_t 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); + } + +#if !defined(MOZ_SANDBOX) + // Converts a string representation of time to a Time object. + // An example of a time string which is converted is as below:- + // "Tue, 15 Nov 1994 12:45:26 GMT". If the timezone is not specified + // in the input string, FromString assumes local time and FromUTCString + // assumes UTC. A timezone that cannot be parsed (e.g. "UTC" which is not + // specified in RFC822) is treated as if the timezone is not specified. + // TODO(iyengar) Move the FromString/FromTimeT/ToTimeT/FromFileTime to + // a new time converter class. + static bool FromString(const char* time_string, Time* parsed_time) { + return FromStringInternal(time_string, true, parsed_time); + } + static bool FromUTCString(const char* time_string, Time* parsed_time) { + return FromStringInternal(time_string, false, parsed_time); + } +#endif + + // 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_t 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); + +#if !defined(MOZ_SANDBOX) + // Converts a string representation of time to a Time object. + // An example of a time string which is converted is as below:- + // "Tue, 15 Nov 1994 12:45:26 GMT". If the timezone is not specified + // in the input string, local time |is_local = true| or + // UTC |is_local = false| is assumed. A timezone that cannot be parsed + // (e.g. "UTC" which is not specified in RFC822) is treated as if the + // timezone is not specified. + static bool FromStringInternal(const char* time_string, + bool is_local, + Time* parsed_time); +#endif +}; + +// Inline the TimeDelta factory methods, for fast TimeDelta construction. + +// static +inline TimeDelta TimeDelta::FromDays(int days) { + if (days == std::numeric_limits<int>::max()) + return Max(); + return TimeDelta(days * Time::kMicrosecondsPerDay); +} + +// static +inline TimeDelta TimeDelta::FromHours(int hours) { + if (hours == std::numeric_limits<int>::max()) + return Max(); + return TimeDelta(hours * Time::kMicrosecondsPerHour); +} + +// static +inline TimeDelta TimeDelta::FromMinutes(int minutes) { + if (minutes == std::numeric_limits<int>::max()) + return Max(); + return TimeDelta(minutes * Time::kMicrosecondsPerMinute); +} + +// static +inline TimeDelta TimeDelta::FromSeconds(int64_t secs) { + return TimeDelta(secs) * Time::kMicrosecondsPerSecond; +} + +// static +inline TimeDelta TimeDelta::FromMilliseconds(int64_t ms) { + return TimeDelta(ms) * Time::kMicrosecondsPerMillisecond; +} + +// static +inline TimeDelta TimeDelta::FromSecondsD(double secs) { + return FromDouble(secs * Time::kMicrosecondsPerSecond); +} + +// static +inline TimeDelta TimeDelta::FromMillisecondsD(double ms) { + return FromDouble(ms * Time::kMicrosecondsPerMillisecond); +} + +// static +inline TimeDelta TimeDelta::FromMicroseconds(int64_t us) { + return TimeDelta(us); +} + +// static +inline TimeDelta TimeDelta::FromDouble(double value) { + double max_magnitude = std::numeric_limits<int64_t>::max(); + TimeDelta delta = TimeDelta(static_cast<int64_t>(value)); + if (value > max_magnitude) + delta = Max(); + else if (value < -max_magnitude) + delta = -Max(); + return delta; +} + +// For logging use only. +BASE_EXPORT std::ostream& operator<<(std::ostream& os, Time time); + +// TimeTicks ------------------------------------------------------------------ + +// Represents monotonically non-decreasing clock time. +class BASE_EXPORT 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 an estimate of the TimeTick value at the time of the UnixEpoch. Because + // Time and TimeTicks respond differently to user-set time and NTP + // adjustments, this number is only an estimate. Nevertheless, this can be + // 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_t us) : TimeBase(us) {} +}; + +// For logging use only. +BASE_EXPORT 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 BASE_EXPORT 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; +#elif defined(OS_WIN) + return IsSupportedWin(); +#else + return false; +#endif + } + + // Waits until the initialization is completed. Needs to be guarded with a + // call to IsSupported(). + static void WaitUntilInitialized() { +#if defined(OS_WIN) + WaitUntilInitializedWin(); +#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. Returns an empty ThreadTicks + // object until the initialization is completed. If a clock reading is + // absolutely needed, call WaitUntilInitialized() before this method. + 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_t us) : TimeBase(us) {} + +#if defined(OS_WIN) + FRIEND_TEST_ALL_PREFIXES(TimeTicks, TSCTicksPerSecond); + + // Returns the frequency of the TSC in ticks per second, or 0 if it hasn't + // been measured yet. Needs to be guarded with a call to IsSupported(). + // This method is declared here rather than in the anonymous namespace to + // allow testing. + static double TSCTicksPerSecond(); + + static bool IsSupportedWin(); + static void WaitUntilInitializedWin(); +#endif +}; + +// For logging use only. +BASE_EXPORT std::ostream& operator<<(std::ostream& os, ThreadTicks time_ticks); + +} // namespace base + +#endif // BASE_TIME_TIME_H_ diff --git a/security/sandbox/chromium/base/time/time_posix.cc b/security/sandbox/chromium/base/time/time_posix.cc new file mode 100644 index 000000000..4aadee618 --- /dev/null +++ b/security/sandbox/chromium/base/time/time_posix.cc @@ -0,0 +1,363 @@ +// 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/logging.h" +#include "build/build_config.h" + +#if defined(OS_ANDROID) +#include "base/os_compat_android.h" +#elif defined(OS_NACL) +#include "base/os_compat_nacl.h" +#endif + +#if !defined(OS_MACOSX) +#include "base/lazy_instance.h" +#include "base/synchronization/lock.h" +#endif + +namespace { + +#if !defined(OS_MACOSX) +// This prevents a crash on traversing the environment global and looking up +// the 'TZ' variable in libc. See: crbug.com/390567. +base::LazyInstance<base::Lock>::Leaky + g_sys_time_to_time_struct_lock = LAZY_INSTANCE_INITIALIZER; + +// 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) { + base::AutoLock locked(g_sys_time_to_time_struct_lock.Get()); + if (is_local) + return mktime64(timestruct); + else + return timegm64(timestruct); +} + +void SysTimeToTimeStruct(SysTime t, struct tm* timestruct, bool is_local) { + base::AutoLock locked(g_sys_time_to_time_struct_lock.Get()); + 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) { + base::AutoLock locked(g_sys_time_to_time_struct_lock.Get()); + if (is_local) + return mktime(timestruct); + else + return timegm(timestruct); +} + +void SysTimeToTimeStruct(SysTime t, struct tm* timestruct, bool is_local) { + base::AutoLock locked(g_sys_time_to_time_struct_lock.Get()); + if (is_local) + localtime_r(&t, timestruct); + else + gmtime_r(&t, timestruct); +} +#endif // OS_ANDROID + +int64_t ConvertTimespecToMicros(const struct timespec& ts) { + base::CheckedNumeric<int64_t> 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_t 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_t 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_t kWindowsEpochDeltaSeconds = INT64_C(11644473600); + +// static +const int64_t 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_t 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"; + PLOG(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_t microseconds = us_ - kWindowsEpochDeltaMicroseconds; + // The following values are all rounded towards -infinity. + int64_t 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_t 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_t seconds_isdst0 = SysTimeFromTimeStruct(×truct, is_local); + + timestruct = timestruct0; + timestruct.tm_isdst = 1; + int64_t 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_t, special care must be taken to avoid + // overflows. + const int64_t min_seconds = (sizeof(SysTime) < sizeof(int64_t)) + ? std::numeric_limits<SysTime>::min() + : std::numeric_limits<int32_t>::min(); + const int64_t max_seconds = (sizeof(SysTime) < sizeof(int64_t)) + ? 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 +} + +#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>(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_t us = us_ - kTimeTToMicrosecondsOffset; + result.tv_sec = us / Time::kMicrosecondsPerSecond; + result.tv_usec = us % Time::kMicrosecondsPerSecond; + return result; +} + +} // namespace base diff --git a/security/sandbox/chromium/base/time/time_win.cc b/security/sandbox/chromium/base/time/time_win.cc new file mode 100644 index 000000000..dc968ad63 --- /dev/null +++ b/security/sandbox/chromium/base/time/time_win.cc @@ -0,0 +1,616 @@ +// 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. + + +// Windows Timer Primer +// +// A good article: http://www.ddj.com/windows/184416651 +// A good mozilla bug: http://bugzilla.mozilla.org/show_bug.cgi?id=363258 +// +// The default windows timer, GetSystemTimeAsFileTime is not very precise. +// It is only good to ~15.5ms. +// +// QueryPerformanceCounter is the logical choice for a high-precision timer. +// However, it is known to be buggy on some hardware. Specifically, it can +// sometimes "jump". On laptops, QPC can also be very expensive to call. +// It's 3-4x slower than timeGetTime() on desktops, but can be 10x slower +// on laptops. A unittest exists which will show the relative cost of various +// timers on any system. +// +// The next logical choice is timeGetTime(). timeGetTime has a precision of +// 1ms, but only if you call APIs (timeBeginPeriod()) which affect all other +// applications on the system. By default, precision is only 15.5ms. +// Unfortunately, we don't want to call timeBeginPeriod because we don't +// want to affect other applications. Further, on mobile platforms, use of +// faster multimedia timers can hurt battery life. See the intel +// article about this here: +// http://softwarecommunity.intel.com/articles/eng/1086.htm +// +// To work around all this, we're going to generally use timeGetTime(). We +// will only increase the system-wide timer if we're not running on battery +// power. + +#include "base/time/time.h" + +#pragma comment(lib, "winmm.lib") +#include <windows.h> +#include <mmsystem.h> +#include <stdint.h> + +#include "base/bit_cast.h" +#include "base/cpu.h" +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/synchronization/lock.h" + +using base::ThreadTicks; +using base::Time; +using base::TimeDelta; +using base::TimeTicks; + +namespace { + +// From MSDN, FILETIME "Contains a 64-bit value representing the number of +// 100-nanosecond intervals since January 1, 1601 (UTC)." +int64_t FileTimeToMicroseconds(const FILETIME& ft) { + // Need to bit_cast to fix alignment, then divide by 10 to convert + // 100-nanoseconds to microseconds. This only works on little-endian + // machines. + return bit_cast<int64_t, FILETIME>(ft) / 10; +} + +void MicrosecondsToFileTime(int64_t us, FILETIME* ft) { + DCHECK_GE(us, 0LL) << "Time is less than 0, negative values are not " + "representable in FILETIME"; + + // Multiply by 10 to convert microseconds to 100-nanoseconds. Bit_cast will + // handle alignment problems. This only works on little-endian machines. + *ft = bit_cast<FILETIME, int64_t>(us * 10); +} + +int64_t CurrentWallclockMicroseconds() { + FILETIME ft; + ::GetSystemTimeAsFileTime(&ft); + return FileTimeToMicroseconds(ft); +} + +// Time between resampling the un-granular clock for this API. 60 seconds. +const int kMaxMillisecondsToAvoidDrift = 60 * Time::kMillisecondsPerSecond; + +int64_t initial_time = 0; +TimeTicks initial_ticks; + +void InitializeClock() { + initial_ticks = TimeTicks::Now(); + initial_time = CurrentWallclockMicroseconds(); +} + +// The two values that ActivateHighResolutionTimer uses to set the systemwide +// timer interrupt frequency on Windows. It controls how precise timers are +// but also has a big impact on battery life. +const int kMinTimerIntervalHighResMs = 1; +const int kMinTimerIntervalLowResMs = 4; +// Track if kMinTimerIntervalHighResMs or kMinTimerIntervalLowResMs is active. +bool g_high_res_timer_enabled = false; +// How many times the high resolution timer has been called. +uint32_t g_high_res_timer_count = 0; +// The lock to control access to the above two variables. +base::LazyInstance<base::Lock>::Leaky g_high_res_lock = + LAZY_INSTANCE_INITIALIZER; + +// Returns a pointer to the QueryThreadCycleTime() function from Windows. +// Can't statically link to it because it is not available on XP. +using QueryThreadCycleTimePtr = decltype(::QueryThreadCycleTime)*; +QueryThreadCycleTimePtr GetQueryThreadCycleTimeFunction() { + static const QueryThreadCycleTimePtr query_thread_cycle_time_fn = + reinterpret_cast<QueryThreadCycleTimePtr>(::GetProcAddress( + ::GetModuleHandle(L"kernel32.dll"), "QueryThreadCycleTime")); + return query_thread_cycle_time_fn; +} + +// Returns the current value of the performance counter. +uint64_t QPCNowRaw() { + LARGE_INTEGER perf_counter_now = {}; + // According to the MSDN documentation for QueryPerformanceCounter(), this + // will never fail on systems that run XP or later. + // https://msdn.microsoft.com/library/windows/desktop/ms644904.aspx + ::QueryPerformanceCounter(&perf_counter_now); + return perf_counter_now.QuadPart; +} + +} // namespace + +// Time ----------------------------------------------------------------------- + +// The internal representation of Time uses FILETIME, whose epoch is 1601-01-01 +// 00:00:00 UTC. ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the +// number of leap year days between 1601 and 1970: (1970-1601)/4 excluding +// 1700, 1800, and 1900. +// static +const int64_t Time::kTimeTToMicrosecondsOffset = INT64_C(11644473600000000); + +// static +Time Time::Now() { + if (initial_time == 0) + InitializeClock(); + + // We implement time using the high-resolution timers so that we can get + // timeouts which are smaller than 10-15ms. If we just used + // CurrentWallclockMicroseconds(), we'd have the less-granular timer. + // + // To make this work, we initialize the clock (initial_time) and the + // counter (initial_ctr). To compute the initial time, we can check + // the number of ticks that have elapsed, and compute the delta. + // + // To avoid any drift, we periodically resync the counters to the system + // clock. + while (true) { + TimeTicks ticks = TimeTicks::Now(); + + // Calculate the time elapsed since we started our timer + TimeDelta elapsed = ticks - initial_ticks; + + // Check if enough time has elapsed that we need to resync the clock. + if (elapsed.InMilliseconds() > kMaxMillisecondsToAvoidDrift) { + InitializeClock(); + continue; + } + + return Time(elapsed + Time(initial_time)); + } +} + +// static +Time Time::NowFromSystemTime() { + // Force resync. + InitializeClock(); + return Time(initial_time); +} + +// static +Time Time::FromFileTime(FILETIME ft) { + if (bit_cast<int64_t, FILETIME>(ft) == 0) + return Time(); + if (ft.dwHighDateTime == std::numeric_limits<DWORD>::max() && + ft.dwLowDateTime == std::numeric_limits<DWORD>::max()) + return Max(); + return Time(FileTimeToMicroseconds(ft)); +} + +FILETIME Time::ToFileTime() const { + if (is_null()) + return bit_cast<FILETIME, int64_t>(0); + if (is_max()) { + FILETIME result; + result.dwHighDateTime = std::numeric_limits<DWORD>::max(); + result.dwLowDateTime = std::numeric_limits<DWORD>::max(); + return result; + } + FILETIME utc_ft; + MicrosecondsToFileTime(us_, &utc_ft); + return utc_ft; +} + +// static +void Time::EnableHighResolutionTimer(bool enable) { + base::AutoLock lock(g_high_res_lock.Get()); + if (g_high_res_timer_enabled == enable) + return; + g_high_res_timer_enabled = enable; + if (!g_high_res_timer_count) + return; + // Since g_high_res_timer_count != 0, an ActivateHighResolutionTimer(true) + // was called which called timeBeginPeriod with g_high_res_timer_enabled + // with a value which is the opposite of |enable|. With that information we + // call timeEndPeriod with the same value used in timeBeginPeriod and + // therefore undo the period effect. + if (enable) { + timeEndPeriod(kMinTimerIntervalLowResMs); + timeBeginPeriod(kMinTimerIntervalHighResMs); + } else { + timeEndPeriod(kMinTimerIntervalHighResMs); + timeBeginPeriod(kMinTimerIntervalLowResMs); + } +} + +// static +bool Time::ActivateHighResolutionTimer(bool activating) { + // We only do work on the transition from zero to one or one to zero so we + // can easily undo the effect (if necessary) when EnableHighResolutionTimer is + // called. + const uint32_t max = std::numeric_limits<uint32_t>::max(); + + base::AutoLock lock(g_high_res_lock.Get()); + UINT period = g_high_res_timer_enabled ? kMinTimerIntervalHighResMs + : kMinTimerIntervalLowResMs; + if (activating) { + DCHECK_NE(g_high_res_timer_count, max); + ++g_high_res_timer_count; + if (g_high_res_timer_count == 1) + timeBeginPeriod(period); + } else { + DCHECK_NE(g_high_res_timer_count, 0u); + --g_high_res_timer_count; + if (g_high_res_timer_count == 0) + timeEndPeriod(period); + } + return (period == kMinTimerIntervalHighResMs); +} + +// static +bool Time::IsHighResolutionTimerInUse() { + base::AutoLock lock(g_high_res_lock.Get()); + return g_high_res_timer_enabled && g_high_res_timer_count > 0; +} + +// static +Time Time::FromExploded(bool is_local, const Exploded& exploded) { + // Create the system struct representing our exploded time. It will either be + // in local time or UTC. + SYSTEMTIME st; + st.wYear = static_cast<WORD>(exploded.year); + st.wMonth = static_cast<WORD>(exploded.month); + st.wDayOfWeek = static_cast<WORD>(exploded.day_of_week); + st.wDay = static_cast<WORD>(exploded.day_of_month); + st.wHour = static_cast<WORD>(exploded.hour); + st.wMinute = static_cast<WORD>(exploded.minute); + st.wSecond = static_cast<WORD>(exploded.second); + st.wMilliseconds = static_cast<WORD>(exploded.millisecond); + + FILETIME ft; + bool success = true; + // Ensure that it's in UTC. + if (is_local) { + SYSTEMTIME utc_st; + success = TzSpecificLocalTimeToSystemTime(NULL, &st, &utc_st) && + SystemTimeToFileTime(&utc_st, &ft); + } else { + success = !!SystemTimeToFileTime(&st, &ft); + } + + if (!success) { + NOTREACHED() << "Unable to convert time"; + return Time(0); + } + return Time(FileTimeToMicroseconds(ft)); +} + +void Time::Explode(bool is_local, Exploded* exploded) const { + if (us_ < 0LL) { + // We are not able to convert it to FILETIME. + ZeroMemory(exploded, sizeof(*exploded)); + return; + } + + // FILETIME in UTC. + FILETIME utc_ft; + MicrosecondsToFileTime(us_, &utc_ft); + + // FILETIME in local time if necessary. + bool success = true; + // FILETIME in SYSTEMTIME (exploded). + SYSTEMTIME st = {0}; + if (is_local) { + SYSTEMTIME utc_st; + // We don't use FileTimeToLocalFileTime here, since it uses the current + // settings for the time zone and daylight saving time. Therefore, if it is + // daylight saving time, it will take daylight saving time into account, + // even if the time you are converting is in standard time. + success = FileTimeToSystemTime(&utc_ft, &utc_st) && + SystemTimeToTzSpecificLocalTime(NULL, &utc_st, &st); + } else { + success = !!FileTimeToSystemTime(&utc_ft, &st); + } + + if (!success) { + NOTREACHED() << "Unable to convert time, don't know why"; + ZeroMemory(exploded, sizeof(*exploded)); + return; + } + + exploded->year = st.wYear; + exploded->month = st.wMonth; + exploded->day_of_week = st.wDayOfWeek; + exploded->day_of_month = st.wDay; + exploded->hour = st.wHour; + exploded->minute = st.wMinute; + exploded->second = st.wSecond; + exploded->millisecond = st.wMilliseconds; +} + +// TimeTicks ------------------------------------------------------------------ +namespace { + +// We define a wrapper to adapt between the __stdcall and __cdecl call of the +// mock function, and to avoid a static constructor. Assigning an import to a +// function pointer directly would require setup code to fetch from the IAT. +DWORD timeGetTimeWrapper() { + return timeGetTime(); +} + +DWORD (*g_tick_function)(void) = &timeGetTimeWrapper; + +// Accumulation of time lost due to rollover (in milliseconds). +int64_t g_rollover_ms = 0; + +// The last timeGetTime value we saw, to detect rollover. +DWORD g_last_seen_now = 0; + +// Lock protecting rollover_ms and last_seen_now. +// Note: this is a global object, and we usually avoid these. However, the time +// code is low-level, and we don't want to use Singletons here (it would be too +// easy to use a Singleton without even knowing it, and that may lead to many +// gotchas). Its impact on startup time should be negligible due to low-level +// nature of time code. +base::Lock g_rollover_lock; + +// We use timeGetTime() to implement TimeTicks::Now(). This can be problematic +// because it returns the number of milliseconds since Windows has started, +// which will roll over the 32-bit value every ~49 days. We try to track +// rollover ourselves, which works if TimeTicks::Now() is called at least every +// 49 days. +TimeDelta RolloverProtectedNow() { + base::AutoLock locked(g_rollover_lock); + // We should hold the lock while calling tick_function to make sure that + // we keep last_seen_now stay correctly in sync. + DWORD now = g_tick_function(); + if (now < g_last_seen_now) + g_rollover_ms += 0x100000000I64; // ~49.7 days. + g_last_seen_now = now; + return TimeDelta::FromMilliseconds(now + g_rollover_ms); +} + +// Discussion of tick counter options on Windows: +// +// (1) CPU cycle counter. (Retrieved via RDTSC) +// The CPU counter provides the highest resolution time stamp and is the least +// expensive to retrieve. However, on older CPUs, two issues can affect its +// reliability: First it is maintained per processor and not synchronized +// between processors. Also, the counters will change frequency due to thermal +// and power changes, and stop in some states. +// +// (2) QueryPerformanceCounter (QPC). The QPC counter provides a high- +// resolution (<1 microsecond) time stamp. On most hardware running today, it +// auto-detects and uses the constant-rate RDTSC counter to provide extremely +// efficient and reliable time stamps. +// +// On older CPUs where RDTSC is unreliable, it falls back to using more +// expensive (20X to 40X more costly) alternate clocks, such as HPET or the ACPI +// PM timer, and can involve system calls; and all this is up to the HAL (with +// some help from ACPI). According to +// http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx, in the +// worst case, it gets the counter from the rollover interrupt on the +// programmable interrupt timer. In best cases, the HAL may conclude that the +// RDTSC counter runs at a constant frequency, then it uses that instead. On +// multiprocessor machines, it will try to verify the values returned from +// RDTSC on each processor are consistent with each other, and apply a handful +// of workarounds for known buggy hardware. In other words, QPC is supposed to +// give consistent results on a multiprocessor computer, but for older CPUs it +// can be unreliable due bugs in BIOS or HAL. +// +// (3) System time. The system time provides a low-resolution (from ~1 to ~15.6 +// milliseconds) time stamp but is comparatively less expensive to retrieve and +// more reliable. Time::EnableHighResolutionTimer() and +// Time::ActivateHighResolutionTimer() can be called to alter the resolution of +// this timer; and also other Windows applications can alter it, affecting this +// one. + +using NowFunction = TimeDelta (*)(void); + +TimeDelta InitialNowFunction(); + +// See "threading notes" in InitializeNowFunctionPointer() for details on how +// concurrent reads/writes to these globals has been made safe. +NowFunction g_now_function = &InitialNowFunction; +int64_t g_qpc_ticks_per_second = 0; + +// As of January 2015, use of <atomic> is forbidden in Chromium code. This is +// what std::atomic_thread_fence does on Windows on all Intel architectures when +// the memory_order argument is anything but std::memory_order_seq_cst: +#define ATOMIC_THREAD_FENCE(memory_order) _ReadWriteBarrier(); + +TimeDelta QPCValueToTimeDelta(LONGLONG qpc_value) { + // Ensure that the assignment to |g_qpc_ticks_per_second|, made in + // InitializeNowFunctionPointer(), has happened by this point. + ATOMIC_THREAD_FENCE(memory_order_acquire); + + DCHECK_GT(g_qpc_ticks_per_second, 0); + + // If the QPC Value is below the overflow threshold, we proceed with + // simple multiply and divide. + if (qpc_value < Time::kQPCOverflowThreshold) { + return TimeDelta::FromMicroseconds( + qpc_value * Time::kMicrosecondsPerSecond / g_qpc_ticks_per_second); + } + // Otherwise, calculate microseconds in a round about manner to avoid + // overflow and precision issues. + int64_t whole_seconds = qpc_value / g_qpc_ticks_per_second; + int64_t leftover_ticks = qpc_value - (whole_seconds * g_qpc_ticks_per_second); + return TimeDelta::FromMicroseconds( + (whole_seconds * Time::kMicrosecondsPerSecond) + + ((leftover_ticks * Time::kMicrosecondsPerSecond) / + g_qpc_ticks_per_second)); +} + +TimeDelta QPCNow() { + return QPCValueToTimeDelta(QPCNowRaw()); +} + +bool IsBuggyAthlon(const base::CPU& cpu) { + // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable. + return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15; +} + +void InitializeNowFunctionPointer() { + LARGE_INTEGER ticks_per_sec = {}; + if (!QueryPerformanceFrequency(&ticks_per_sec)) + ticks_per_sec.QuadPart = 0; + + // If Windows cannot provide a QPC implementation, TimeTicks::Now() must use + // the low-resolution clock. + // + // If the QPC implementation is expensive and/or unreliable, TimeTicks::Now() + // will still use the low-resolution clock. A CPU lacking a non-stop time + // counter will cause Windows to provide an alternate QPC implementation that + // works, but is expensive to use. Certain Athlon CPUs are known to make the + // QPC implementation unreliable. + // + // Otherwise, Now uses the high-resolution QPC clock. As of 21 August 2015, + // ~72% of users fall within this category. + NowFunction now_function; + base::CPU cpu; + if (ticks_per_sec.QuadPart <= 0 || + !cpu.has_non_stop_time_stamp_counter() || IsBuggyAthlon(cpu)) { + now_function = &RolloverProtectedNow; + } else { + now_function = &QPCNow; + } + + // Threading note 1: In an unlikely race condition, it's possible for two or + // more threads to enter InitializeNowFunctionPointer() in parallel. This is + // not a problem since all threads should end up writing out the same values + // to the global variables. + // + // Threading note 2: A release fence is placed here to ensure, from the + // perspective of other threads using the function pointers, that the + // assignment to |g_qpc_ticks_per_second| happens before the function pointers + // are changed. + g_qpc_ticks_per_second = ticks_per_sec.QuadPart; + ATOMIC_THREAD_FENCE(memory_order_release); + g_now_function = now_function; +} + +TimeDelta InitialNowFunction() { + InitializeNowFunctionPointer(); + return g_now_function(); +} + +} // namespace + +// static +TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( + TickFunctionType ticker) { + base::AutoLock locked(g_rollover_lock); + TickFunctionType old = g_tick_function; + g_tick_function = ticker; + g_rollover_ms = 0; + g_last_seen_now = 0; + return old; +} + +// static +TimeTicks TimeTicks::Now() { + return TimeTicks() + g_now_function(); +} + +// static +bool TimeTicks::IsHighResolution() { + if (g_now_function == &InitialNowFunction) + InitializeNowFunctionPointer(); + return g_now_function == &QPCNow; +} + +// static +ThreadTicks ThreadTicks::Now() { + DCHECK(IsSupported()); + + // Get the number of TSC ticks used by the current thread. + ULONG64 thread_cycle_time = 0; + GetQueryThreadCycleTimeFunction()(::GetCurrentThread(), &thread_cycle_time); + + // Get the frequency of the TSC. + double tsc_ticks_per_second = TSCTicksPerSecond(); + if (tsc_ticks_per_second == 0) + return ThreadTicks(); + + // Return the CPU time of the current thread. + double thread_time_seconds = thread_cycle_time / tsc_ticks_per_second; + return ThreadTicks( + static_cast<int64_t>(thread_time_seconds * Time::kMicrosecondsPerSecond)); +} + +// static +bool ThreadTicks::IsSupportedWin() { + static bool is_supported = GetQueryThreadCycleTimeFunction() && + base::CPU().has_non_stop_time_stamp_counter() && + !IsBuggyAthlon(base::CPU()); + return is_supported; +} + +// static +void ThreadTicks::WaitUntilInitializedWin() { + while (TSCTicksPerSecond() == 0) + ::Sleep(10); +} + +double ThreadTicks::TSCTicksPerSecond() { + DCHECK(IsSupported()); + + // The value returned by QueryPerformanceFrequency() cannot be used as the TSC + // frequency, because there is no guarantee that the TSC frequency is equal to + // the performance counter frequency. + + // The TSC frequency is cached in a static variable because it takes some time + // to compute it. + static double tsc_ticks_per_second = 0; + if (tsc_ticks_per_second != 0) + return tsc_ticks_per_second; + + // Increase the thread priority to reduces the chances of having a context + // switch during a reading of the TSC and the performance counter. + int previous_priority = ::GetThreadPriority(::GetCurrentThread()); + ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_HIGHEST); + + // The first time that this function is called, make an initial reading of the + // TSC and the performance counter. + static const uint64_t tsc_initial = __rdtsc(); + static const uint64_t perf_counter_initial = QPCNowRaw(); + + // Make a another reading of the TSC and the performance counter every time + // that this function is called. + uint64_t tsc_now = __rdtsc(); + uint64_t perf_counter_now = QPCNowRaw(); + + // Reset the thread priority. + ::SetThreadPriority(::GetCurrentThread(), previous_priority); + + // Make sure that at least 50 ms elapsed between the 2 readings. The first + // time that this function is called, we don't expect this to be the case. + // Note: The longer the elapsed time between the 2 readings is, the more + // accurate the computed TSC frequency will be. The 50 ms value was + // chosen because local benchmarks show that it allows us to get a + // stddev of less than 1 tick/us between multiple runs. + // Note: According to the MSDN documentation for QueryPerformanceFrequency(), + // this will never fail on systems that run XP or later. + // https://msdn.microsoft.com/library/windows/desktop/ms644905.aspx + LARGE_INTEGER perf_counter_frequency = {}; + ::QueryPerformanceFrequency(&perf_counter_frequency); + DCHECK_GE(perf_counter_now, perf_counter_initial); + uint64_t perf_counter_ticks = perf_counter_now - perf_counter_initial; + double elapsed_time_seconds = + perf_counter_ticks / static_cast<double>(perf_counter_frequency.QuadPart); + + const double kMinimumEvaluationPeriodSeconds = 0.05; + if (elapsed_time_seconds < kMinimumEvaluationPeriodSeconds) + return 0; + + // Compute the frequency of the TSC. + DCHECK_GE(tsc_now, tsc_initial); + uint64_t tsc_ticks = tsc_now - tsc_initial; + tsc_ticks_per_second = tsc_ticks / elapsed_time_seconds; + + return tsc_ticks_per_second; +} + +// static +TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { + return TimeTicks() + QPCValueToTimeDelta(qpc_value); +} + +// TimeDelta ------------------------------------------------------------------ + +// static +TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { + return QPCValueToTimeDelta(qpc_value); +} |