tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

time.cc (11263B)


      1 // Copyright 2012 The Chromium Authors
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/time/time.h"
      6 
      7 #include <atomic>
      8 #include <cmath>
      9 #include <limits>
     10 #include <ostream>
     11 #include <tuple>
     12 #include <utility>
     13 
     14 #include "base/check.h"
     15 #include "base/format_macros.h"
     16 #include "base/strings/stringprintf.h"
     17 #include "base/third_party/nspr/prtime.h"
     18 #include "base/time/time_override.h"
     19 #include "build/build_config.h"
     20 #include "third_party/abseil-cpp/absl/types/optional.h"
     21 
     22 namespace base {
     23 
     24 namespace {
     25 
     26 TimeTicks g_shared_time_ticks_at_unix_epoch;
     27 
     28 }  // namespace
     29 
     30 namespace internal {
     31 
     32 std::atomic<TimeNowFunction> g_time_now_function{
     33    &subtle::TimeNowIgnoringOverride};
     34 
     35 std::atomic<TimeNowFunction> g_time_now_from_system_time_function{
     36    &subtle::TimeNowFromSystemTimeIgnoringOverride};
     37 
     38 std::atomic<TimeTicksNowFunction> g_time_ticks_now_function{
     39    &subtle::TimeTicksNowIgnoringOverride};
     40 
     41 #if !defined(MOZ_SANDBOX)
     42 std::atomic<LiveTicksNowFunction> g_live_ticks_now_function{
     43    &subtle::LiveTicksNowIgnoringOverride};
     44 #endif
     45 
     46 std::atomic<ThreadTicksNowFunction> g_thread_ticks_now_function{
     47    &subtle::ThreadTicksNowIgnoringOverride};
     48 
     49 }  // namespace internal
     50 
     51 // TimeDelta ------------------------------------------------------------------
     52 
     53 TimeDelta TimeDelta::CeilToMultiple(TimeDelta interval) const {
     54  if (is_inf() || interval.is_zero())
     55    return *this;
     56  const TimeDelta remainder = *this % interval;
     57  if (delta_ < 0)
     58    return *this - remainder;
     59  return remainder.is_zero() ? *this
     60                             : (*this - remainder + interval.magnitude());
     61 }
     62 
     63 TimeDelta TimeDelta::FloorToMultiple(TimeDelta interval) const {
     64  if (is_inf() || interval.is_zero())
     65    return *this;
     66  const TimeDelta remainder = *this % interval;
     67  if (delta_ < 0) {
     68    return remainder.is_zero() ? *this
     69                               : (*this - remainder - interval.magnitude());
     70  }
     71  return *this - remainder;
     72 }
     73 
     74 TimeDelta TimeDelta::RoundToMultiple(TimeDelta interval) const {
     75  if (is_inf() || interval.is_zero())
     76    return *this;
     77  if (interval.is_inf())
     78    return TimeDelta();
     79  const TimeDelta half = interval.magnitude() / 2;
     80  return (delta_ < 0) ? (*this - half).CeilToMultiple(interval)
     81                      : (*this + half).FloorToMultiple(interval);
     82 }
     83 
     84 std::ostream& operator<<(std::ostream& os, TimeDelta time_delta) {
     85  return os << time_delta.InSecondsF() << " s";
     86 }
     87 
     88 // Time -----------------------------------------------------------------------
     89 
     90 // static
     91 Time Time::Now() {
     92  return internal::g_time_now_function.load(std::memory_order_relaxed)();
     93 }
     94 
     95 // static
     96 Time Time::NowFromSystemTime() {
     97  // Just use g_time_now_function because it returns the system time.
     98  return internal::g_time_now_from_system_time_function.load(
     99      std::memory_order_relaxed)();
    100 }
    101 
    102 #if !defined(MOZ_SANDBOX)
    103 Time Time::Midnight(bool is_local) const {
    104  Exploded exploded;
    105  Explode(is_local, &exploded);
    106  exploded.hour = 0;
    107  exploded.minute = 0;
    108  exploded.second = 0;
    109  exploded.millisecond = 0;
    110  Time out_time;
    111  if (FromExploded(is_local, exploded, &out_time))
    112    return out_time;
    113 
    114  // Reaching here means 00:00:00am of the current day does not exist (due to
    115  // Daylight Saving Time in some countries where clocks are shifted at
    116  // midnight). In this case, midnight should be defined as 01:00:00am.
    117  DCHECK(is_local);
    118  exploded.hour = 1;
    119  [[maybe_unused]] const bool result =
    120      FromExploded(is_local, exploded, &out_time);
    121 #if BUILDFLAG(IS_CHROMEOS_ASH) && defined(ARCH_CPU_ARM_FAMILY)
    122  // TODO(crbug.com/1263873): DCHECKs have limited coverage during automated
    123  // testing on CrOS and this check failed when tested on an experimental
    124  // builder. Testing for ARCH_CPU_ARM_FAMILY prevents regressing coverage on
    125  // x86_64, which is already enabled. See go/chrome-dcheck-on-cros or
    126  // http://crbug.com/1113456 for more details.
    127 #else
    128  DCHECK(result);  // This function must not fail.
    129 #endif
    130  return out_time;
    131 }
    132 
    133 // static
    134 bool Time::FromStringInternal(const char* time_string,
    135                              bool is_local,
    136                              Time* parsed_time) {
    137  DCHECK(time_string);
    138  DCHECK(parsed_time);
    139 
    140  if (time_string[0] == '\0')
    141    return false;
    142 
    143  PRTime result_time = 0;
    144  PRStatus result = PR_ParseTimeString(time_string,
    145                                       is_local ? PR_FALSE : PR_TRUE,
    146                                       &result_time);
    147  if (result != PR_SUCCESS)
    148    return false;
    149 
    150  *parsed_time = UnixEpoch() + Microseconds(result_time);
    151  return true;
    152 }
    153 #endif
    154 
    155 // static
    156 bool Time::ExplodedMostlyEquals(const Exploded& lhs, const Exploded& rhs) {
    157  return std::tie(lhs.year, lhs.month, lhs.day_of_month, lhs.hour, lhs.minute,
    158                  lhs.second, lhs.millisecond) ==
    159         std::tie(rhs.year, rhs.month, rhs.day_of_month, rhs.hour, rhs.minute,
    160                  rhs.second, rhs.millisecond);
    161 }
    162 
    163 // static
    164 bool Time::FromMillisecondsSinceUnixEpoch(int64_t unix_milliseconds,
    165                                          Time* time) {
    166  // Adjust the provided time from milliseconds since the Unix epoch (1970) to
    167  // microseconds since the Windows epoch (1601), avoiding overflows.
    168  CheckedNumeric<int64_t> checked_microseconds_win_epoch = unix_milliseconds;
    169  checked_microseconds_win_epoch *= kMicrosecondsPerMillisecond;
    170  checked_microseconds_win_epoch += kTimeTToMicrosecondsOffset;
    171  *time = Time(checked_microseconds_win_epoch.ValueOrDefault(0));
    172  return checked_microseconds_win_epoch.IsValid();
    173 }
    174 
    175 int64_t Time::ToRoundedDownMillisecondsSinceUnixEpoch() const {
    176  constexpr int64_t kEpochOffsetMillis =
    177      kTimeTToMicrosecondsOffset / kMicrosecondsPerMillisecond;
    178  static_assert(kTimeTToMicrosecondsOffset % kMicrosecondsPerMillisecond == 0,
    179                "assumption: no epoch offset sub-milliseconds");
    180 
    181  // Compute the milliseconds since UNIX epoch without the possibility of
    182  // under/overflow. Round the result towards -infinity.
    183  //
    184  // If |us_| is negative and includes fractions of a millisecond, subtract one
    185  // more to effect the round towards -infinity. C-style integer truncation
    186  // takes care of all other cases.
    187  const int64_t millis = us_ / kMicrosecondsPerMillisecond;
    188  const int64_t submillis = us_ % kMicrosecondsPerMillisecond;
    189  return millis - kEpochOffsetMillis - (submillis < 0);
    190 }
    191 
    192 #if !defined(MOZ_SANDBOX)
    193 std::ostream& operator<<(std::ostream& os, Time time) {
    194  Time::Exploded exploded;
    195  time.UTCExplode(&exploded);
    196  // Can't call `UnlocalizedTimeFormatWithPattern()`/`TimeFormatAsIso8601()`
    197  // since `//base` can't depend on `//base:i18n`.
    198  //
    199  // TODO(pkasting): Consider whether `operator<<()` should move to
    200  // `base/i18n/time_formatting.h` -- would let us implement in terms of
    201  // existing time formatting, but might be confusing.
    202  return os << StringPrintf("%04d-%02d-%02d %02d:%02d:%02d.%06" PRId64 " UTC",
    203                            exploded.year, exploded.month,
    204                            exploded.day_of_month, exploded.hour,
    205                            exploded.minute, exploded.second,
    206                            time.ToDeltaSinceWindowsEpoch().InMicroseconds() %
    207                                Time::kMicrosecondsPerSecond);
    208 }
    209 #endif
    210 
    211 // TimeTicks ------------------------------------------------------------------
    212 
    213 // static
    214 TimeTicks TimeTicks::Now() {
    215  return internal::g_time_ticks_now_function.load(std::memory_order_relaxed)();
    216 }
    217 
    218 // static
    219 // This method should be called once at process start and before
    220 // TimeTicks::UnixEpoch is accessed. It is intended to make the offset between
    221 // unix time and monotonic time consistent across processes.
    222 void TimeTicks::SetSharedUnixEpoch(TimeTicks ticks_at_epoch) {
    223  DCHECK(g_shared_time_ticks_at_unix_epoch.is_null());
    224  g_shared_time_ticks_at_unix_epoch = ticks_at_epoch;
    225 }
    226 
    227 // static
    228 TimeTicks TimeTicks::UnixEpoch() {
    229  struct StaticUnixEpoch {
    230    StaticUnixEpoch()
    231        : epoch(
    232              g_shared_time_ticks_at_unix_epoch.is_null()
    233                  ? subtle::TimeTicksNowIgnoringOverride() -
    234                        (subtle::TimeNowIgnoringOverride() - Time::UnixEpoch())
    235                  : g_shared_time_ticks_at_unix_epoch) {
    236      // Prevent future usage of `g_shared_time_ticks_at_unix_epoch`.
    237      g_shared_time_ticks_at_unix_epoch = TimeTicks::Max();
    238    }
    239 
    240    const TimeTicks epoch;
    241  };
    242 
    243  static StaticUnixEpoch static_epoch;
    244  return static_epoch.epoch;
    245 }
    246 
    247 TimeTicks TimeTicks::SnappedToNextTick(TimeTicks tick_phase,
    248                                       TimeDelta tick_interval) const {
    249  // |interval_offset| is the offset from |this| to the next multiple of
    250  // |tick_interval| after |tick_phase|, possibly negative if in the past.
    251  TimeDelta interval_offset = (tick_phase - *this) % tick_interval;
    252  // If |this| is exactly on the interval (i.e. offset==0), don't adjust.
    253  // Otherwise, if |tick_phase| was in the past, adjust forward to the next
    254  // tick after |this|.
    255  if (!interval_offset.is_zero() && tick_phase < *this)
    256    interval_offset += tick_interval;
    257  return *this + interval_offset;
    258 }
    259 
    260 std::ostream& operator<<(std::ostream& os, TimeTicks time_ticks) {
    261  // This function formats a TimeTicks object as "bogo-microseconds".
    262  // The origin and granularity of the count are platform-specific, and may very
    263  // from run to run. Although bogo-microseconds usually roughly correspond to
    264  // real microseconds, the only real guarantee is that the number never goes
    265  // down during a single run.
    266  const TimeDelta as_time_delta = time_ticks - TimeTicks();
    267  return os << as_time_delta.InMicroseconds() << " bogo-microseconds";
    268 }
    269 
    270 // LiveTicks ------------------------------------------------------------------
    271 
    272 #if !defined(MOZ_SANDBOX)
    273 // static
    274 LiveTicks LiveTicks::Now() {
    275  return internal::g_live_ticks_now_function.load(std::memory_order_relaxed)();
    276 }
    277 #endif
    278 
    279 #if !BUILDFLAG(IS_WIN)
    280 namespace subtle {
    281 LiveTicks LiveTicksNowIgnoringOverride() {
    282  // On non-windows platforms LiveTicks is equivalent to TimeTicks already.
    283  // Subtract the empty `TimeTicks` from `TimeTicks::Now()` to get a `TimeDelta`
    284  // that can be added to the empty `LiveTicks`.
    285  return LiveTicks() + (TimeTicks::Now() - TimeTicks());
    286 }
    287 }  // namespace subtle
    288 
    289 #endif
    290 
    291 // ThreadTicks ----------------------------------------------------------------
    292 
    293 // static
    294 ThreadTicks ThreadTicks::Now() {
    295  return internal::g_thread_ticks_now_function.load(
    296      std::memory_order_relaxed)();
    297 }
    298 
    299 std::ostream& operator<<(std::ostream& os, ThreadTicks thread_ticks) {
    300  const TimeDelta as_time_delta = thread_ticks - ThreadTicks();
    301  return os << as_time_delta.InMicroseconds() << " bogo-thread-microseconds";
    302 }
    303 
    304 // Time::Exploded -------------------------------------------------------------
    305 
    306 bool Time::Exploded::HasValidValues() const {
    307  // clang-format off
    308  return (1 <= month) && (month <= 12) &&
    309         (0 <= day_of_week) && (day_of_week <= 6) &&
    310         (1 <= day_of_month) && (day_of_month <= 31) &&
    311         (0 <= hour) && (hour <= 23) &&
    312         (0 <= minute) && (minute <= 59) &&
    313         (0 <= second) && (second <= 60) &&
    314         (0 <= millisecond) && (millisecond <= 999);
    315  // clang-format on
    316 }
    317 
    318 }  // namespace base