• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3   *
4   *  Use of this source code is governed by a BSD-style license
5   *  that can be found in the LICENSE file in the root of the source
6   *  tree. An additional intellectual property rights grant can be found
7   *  in the file PATENTS.  All contributing project authors may
8   *  be found in the AUTHORS file in the root of the source tree.
9   */
10  
11  #include <stdint.h>
12  
13  #if defined(WEBRTC_POSIX)
14  #include <sys/time.h>
15  #if defined(WEBRTC_MAC)
16  #include <mach/mach_time.h>
17  #endif
18  #endif
19  
20  #if defined(WEBRTC_WIN)
21  // clang-format off
22  // clang formatting would put <windows.h> last,
23  // which leads to compilation failure.
24  #include <windows.h>
25  #include <mmsystem.h>
26  #include <sys/timeb.h>
27  // clang-format on
28  #endif
29  
30  #include "rtc_base/checks.h"
31  #include "rtc_base/numerics/safe_conversions.h"
32  #include "rtc_base/time_utils.h"
33  
34  namespace rtc {
35  
36  ClockInterface* g_clock = nullptr;
37  
SetClockForTesting(ClockInterface * clock)38  ClockInterface* SetClockForTesting(ClockInterface* clock) {
39    ClockInterface* prev = g_clock;
40    g_clock = clock;
41    return prev;
42  }
43  
GetClockForTesting()44  ClockInterface* GetClockForTesting() {
45    return g_clock;
46  }
47  
48  #if defined(WINUWP)
49  
50  namespace {
51  
52  class TimeHelper final {
53   public:
54    TimeHelper(const TimeHelper&) = delete;
55  
56    // Resets the clock based upon an NTP server. This routine must be called
57    // prior to the main system start-up to ensure all clocks are based upon
58    // an NTP server time if NTP synchronization is required. No critical
59    // section is used thus this method must be called prior to any clock
60    // routines being used.
SyncWithNtp(int64_t ntp_server_time_ms)61    static void SyncWithNtp(int64_t ntp_server_time_ms) {
62      auto& singleton = Singleton();
63      TIME_ZONE_INFORMATION time_zone;
64      GetTimeZoneInformation(&time_zone);
65      int64_t time_zone_bias_ns =
66          rtc::dchecked_cast<int64_t>(time_zone.Bias) * 60 * 1000 * 1000 * 1000;
67      singleton.app_start_time_ns_ =
68          (ntp_server_time_ms - kNTPTimeToUnixTimeEpochOffset) * 1000000 -
69          time_zone_bias_ns;
70      singleton.UpdateReferenceTime();
71    }
72  
73    // Returns the number of nanoseconds that have passed since unix epoch.
TicksNs()74    static int64_t TicksNs() {
75      auto& singleton = Singleton();
76      int64_t result = 0;
77      LARGE_INTEGER qpcnt;
78      QueryPerformanceCounter(&qpcnt);
79      result = rtc::dchecked_cast<int64_t>(
80          (rtc::dchecked_cast<uint64_t>(qpcnt.QuadPart) * 100000 /
81           rtc::dchecked_cast<uint64_t>(singleton.os_ticks_per_second_)) *
82          10000);
83      result = singleton.app_start_time_ns_ + result -
84               singleton.time_since_os_start_ns_;
85      return result;
86    }
87  
88   private:
TimeHelper()89    TimeHelper() {
90      TIME_ZONE_INFORMATION time_zone;
91      GetTimeZoneInformation(&time_zone);
92      int64_t time_zone_bias_ns =
93          rtc::dchecked_cast<int64_t>(time_zone.Bias) * 60 * 1000 * 1000 * 1000;
94      FILETIME ft;
95      // This will give us system file in UTC format.
96      GetSystemTimeAsFileTime(&ft);
97      LARGE_INTEGER li;
98      li.HighPart = ft.dwHighDateTime;
99      li.LowPart = ft.dwLowDateTime;
100  
101      app_start_time_ns_ = (li.QuadPart - kFileTimeToUnixTimeEpochOffset) * 100 -
102                           time_zone_bias_ns;
103  
104      UpdateReferenceTime();
105    }
106  
Singleton()107    static TimeHelper& Singleton() {
108      static TimeHelper singleton;
109      return singleton;
110    }
111  
UpdateReferenceTime()112    void UpdateReferenceTime() {
113      LARGE_INTEGER qpfreq;
114      QueryPerformanceFrequency(&qpfreq);
115      os_ticks_per_second_ = rtc::dchecked_cast<int64_t>(qpfreq.QuadPart);
116  
117      LARGE_INTEGER qpcnt;
118      QueryPerformanceCounter(&qpcnt);
119      time_since_os_start_ns_ = rtc::dchecked_cast<int64_t>(
120          (rtc::dchecked_cast<uint64_t>(qpcnt.QuadPart) * 100000 /
121           rtc::dchecked_cast<uint64_t>(os_ticks_per_second_)) *
122          10000);
123    }
124  
125   private:
126    static constexpr uint64_t kFileTimeToUnixTimeEpochOffset =
127        116444736000000000ULL;
128    static constexpr uint64_t kNTPTimeToUnixTimeEpochOffset = 2208988800000L;
129  
130    // The number of nanoseconds since unix system epoch
131    int64_t app_start_time_ns_;
132    // The number of nanoseconds since the OS started
133    int64_t time_since_os_start_ns_;
134    // The OS calculated ticks per second
135    int64_t os_ticks_per_second_;
136  };
137  
138  }  // namespace
139  
SyncWithNtp(int64_t time_from_ntp_server_ms)140  void SyncWithNtp(int64_t time_from_ntp_server_ms) {
141    TimeHelper::SyncWithNtp(time_from_ntp_server_ms);
142  }
143  
144  #endif  // defined(WINUWP)
145  
SystemTimeNanos()146  int64_t SystemTimeNanos() {
147    int64_t ticks;
148  #if defined(WEBRTC_MAC)
149    static mach_timebase_info_data_t timebase;
150    if (timebase.denom == 0) {
151      // Get the timebase if this is the first time we run.
152      // Recommended by Apple's QA1398.
153      if (mach_timebase_info(&timebase) != KERN_SUCCESS) {
154        RTC_NOTREACHED();
155      }
156    }
157    // Use timebase to convert absolute time tick units into nanoseconds.
158    const auto mul = [](uint64_t a, uint32_t b) -> int64_t {
159      RTC_DCHECK_NE(b, 0);
160      RTC_DCHECK_LE(a, std::numeric_limits<int64_t>::max() / b)
161          << "The multiplication " << a << " * " << b << " overflows";
162      return rtc::dchecked_cast<int64_t>(a * b);
163    };
164    ticks = mul(mach_absolute_time(), timebase.numer) / timebase.denom;
165  #elif defined(WEBRTC_POSIX)
166    struct timespec ts;
167    // TODO(deadbeef): Do we need to handle the case when CLOCK_MONOTONIC is not
168    // supported?
169    clock_gettime(CLOCK_MONOTONIC, &ts);
170    ticks = kNumNanosecsPerSec * static_cast<int64_t>(ts.tv_sec) +
171            static_cast<int64_t>(ts.tv_nsec);
172  #elif defined(WINUWP)
173    ticks = TimeHelper::TicksNs();
174  #elif defined(WEBRTC_WIN)
175    static volatile LONG last_timegettime = 0;
176    static volatile int64_t num_wrap_timegettime = 0;
177    volatile LONG* last_timegettime_ptr = &last_timegettime;
178    DWORD now = timeGetTime();
179    // Atomically update the last gotten time
180    DWORD old = InterlockedExchange(last_timegettime_ptr, now);
181    if (now < old) {
182      // If now is earlier than old, there may have been a race between threads.
183      // 0x0fffffff ~3.1 days, the code will not take that long to execute
184      // so it must have been a wrap around.
185      if (old > 0xf0000000 && now < 0x0fffffff) {
186        num_wrap_timegettime++;
187      }
188    }
189    ticks = now + (num_wrap_timegettime << 32);
190    // TODO(deadbeef): Calculate with nanosecond precision. Otherwise, we're
191    // just wasting a multiply and divide when doing Time() on Windows.
192    ticks = ticks * kNumNanosecsPerMillisec;
193  #else
194  #error Unsupported platform.
195  #endif
196    return ticks;
197  }
198  
SystemTimeMillis()199  int64_t SystemTimeMillis() {
200    return static_cast<int64_t>(SystemTimeNanos() / kNumNanosecsPerMillisec);
201  }
202  
TimeNanos()203  int64_t TimeNanos() {
204    if (g_clock) {
205      return g_clock->TimeNanos();
206    }
207    return SystemTimeNanos();
208  }
209  
Time32()210  uint32_t Time32() {
211    return static_cast<uint32_t>(TimeNanos() / kNumNanosecsPerMillisec);
212  }
213  
TimeMillis()214  int64_t TimeMillis() {
215    return TimeNanos() / kNumNanosecsPerMillisec;
216  }
217  
TimeMicros()218  int64_t TimeMicros() {
219    return TimeNanos() / kNumNanosecsPerMicrosec;
220  }
221  
TimeAfter(int64_t elapsed)222  int64_t TimeAfter(int64_t elapsed) {
223    RTC_DCHECK_GE(elapsed, 0);
224    return TimeMillis() + elapsed;
225  }
226  
TimeDiff32(uint32_t later,uint32_t earlier)227  int32_t TimeDiff32(uint32_t later, uint32_t earlier) {
228    return later - earlier;
229  }
230  
TimeDiff(int64_t later,int64_t earlier)231  int64_t TimeDiff(int64_t later, int64_t earlier) {
232    return later - earlier;
233  }
234  
TimestampWrapAroundHandler()235  TimestampWrapAroundHandler::TimestampWrapAroundHandler()
236      : last_ts_(0), num_wrap_(-1) {}
237  
Unwrap(uint32_t ts)238  int64_t TimestampWrapAroundHandler::Unwrap(uint32_t ts) {
239    if (num_wrap_ == -1) {
240      last_ts_ = ts;
241      num_wrap_ = 0;
242      return ts;
243    }
244  
245    if (ts < last_ts_) {
246      if (last_ts_ >= 0xf0000000 && ts < 0x0fffffff)
247        ++num_wrap_;
248    } else if ((ts - last_ts_) > 0xf0000000) {
249      // Backwards wrap. Unwrap with last wrap count and don't update last_ts_.
250      return ts + (num_wrap_ - 1) * (int64_t{1} << 32);
251    }
252  
253    last_ts_ = ts;
254    return ts + (num_wrap_ << 32);
255  }
256  
TmToSeconds(const tm & tm)257  int64_t TmToSeconds(const tm& tm) {
258    static short int mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
259    static short int cumul_mdays[12] = {0,   31,  59,  90,  120, 151,
260                                        181, 212, 243, 273, 304, 334};
261    int year = tm.tm_year + 1900;
262    int month = tm.tm_mon;
263    int day = tm.tm_mday - 1;  // Make 0-based like the rest.
264    int hour = tm.tm_hour;
265    int min = tm.tm_min;
266    int sec = tm.tm_sec;
267  
268    bool expiry_in_leap_year =
269        (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
270  
271    if (year < 1970)
272      return -1;
273    if (month < 0 || month > 11)
274      return -1;
275    if (day < 0 || day >= mdays[month] + (expiry_in_leap_year && month == 2 - 1))
276      return -1;
277    if (hour < 0 || hour > 23)
278      return -1;
279    if (min < 0 || min > 59)
280      return -1;
281    if (sec < 0 || sec > 59)
282      return -1;
283  
284    day += cumul_mdays[month];
285  
286    // Add number of leap days between 1970 and the expiration year, inclusive.
287    day += ((year / 4 - 1970 / 4) - (year / 100 - 1970 / 100) +
288            (year / 400 - 1970 / 400));
289  
290    // We will have added one day too much above if expiration is during a leap
291    // year, and expiration is in January or February.
292    if (expiry_in_leap_year && month <= 2 - 1)  // |month| is zero based.
293      day -= 1;
294  
295    // Combine all variables into seconds from 1970-01-01 00:00 (except |month|
296    // which was accumulated into |day| above).
297    return (((static_cast<int64_t>(year - 1970) * 365 + day) * 24 + hour) * 60 +
298            min) *
299               60 +
300           sec;
301  }
302  
TimeUTCMicros()303  int64_t TimeUTCMicros() {
304    if (g_clock) {
305      return g_clock->TimeNanos() / kNumNanosecsPerMicrosec;
306    }
307  #if defined(WEBRTC_POSIX)
308    struct timeval time;
309    gettimeofday(&time, nullptr);
310    // Convert from second (1.0) and microsecond (1e-6).
311    return (static_cast<int64_t>(time.tv_sec) * rtc::kNumMicrosecsPerSec +
312            time.tv_usec);
313  
314  #elif defined(WEBRTC_WIN)
315    struct _timeb time;
316    _ftime(&time);
317    // Convert from second (1.0) and milliseconds (1e-3).
318    return (static_cast<int64_t>(time.time) * rtc::kNumMicrosecsPerSec +
319            static_cast<int64_t>(time.millitm) * rtc::kNumMicrosecsPerMillisec);
320  #endif
321  }
322  
TimeUTCMillis()323  int64_t TimeUTCMillis() {
324    return TimeUTCMicros() / kNumMicrosecsPerMillisec;
325  }
326  
327  }  // namespace rtc
328