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#ifndef WIN32_LEAN_AND_MEAN
22#define WIN32_LEAN_AND_MEAN
23#endif
24#include <windows.h>
25#include <mmsystem.h>
26#endif
27
28#include "webrtc/base/checks.h"
29#include "webrtc/base/timeutils.h"
30
31#define EFFICIENT_IMPLEMENTATION 1
32
33namespace rtc {
34
35const uint32_t HALF = 0x80000000;
36
37uint64_t TimeNanos() {
38  int64_t ticks = 0;
39#if defined(WEBRTC_MAC)
40  static mach_timebase_info_data_t timebase;
41  if (timebase.denom == 0) {
42    // Get the timebase if this is the first time we run.
43    // Recommended by Apple's QA1398.
44    if (mach_timebase_info(&timebase) != KERN_SUCCESS) {
45      RTC_DCHECK(false);
46    }
47  }
48  // Use timebase to convert absolute time tick units into nanoseconds.
49  ticks = mach_absolute_time() * timebase.numer / timebase.denom;
50#elif defined(WEBRTC_POSIX)
51  struct timespec ts;
52  // TODO: Do we need to handle the case when CLOCK_MONOTONIC
53  // is not supported?
54  clock_gettime(CLOCK_MONOTONIC, &ts);
55  ticks = kNumNanosecsPerSec * static_cast<int64_t>(ts.tv_sec) +
56          static_cast<int64_t>(ts.tv_nsec);
57#elif defined(WEBRTC_WIN)
58  static volatile LONG last_timegettime = 0;
59  static volatile int64_t num_wrap_timegettime = 0;
60  volatile LONG* last_timegettime_ptr = &last_timegettime;
61  DWORD now = timeGetTime();
62  // Atomically update the last gotten time
63  DWORD old = InterlockedExchange(last_timegettime_ptr, now);
64  if (now < old) {
65    // If now is earlier than old, there may have been a race between
66    // threads.
67    // 0x0fffffff ~3.1 days, the code will not take that long to execute
68    // so it must have been a wrap around.
69    if (old > 0xf0000000 && now < 0x0fffffff) {
70      num_wrap_timegettime++;
71    }
72  }
73  ticks = now + (num_wrap_timegettime << 32);
74  // TODO: Calculate with nanosecond precision.  Otherwise, we're just
75  // wasting a multiply and divide when doing Time() on Windows.
76  ticks = ticks * kNumNanosecsPerMillisec;
77#endif
78  return ticks;
79}
80
81uint32_t Time() {
82  return static_cast<uint32_t>(TimeNanos() / kNumNanosecsPerMillisec);
83}
84
85uint64_t TimeMicros() {
86  return static_cast<uint64_t>(TimeNanos() / kNumNanosecsPerMicrosec);
87}
88
89#if defined(WEBRTC_WIN)
90static const uint64_t kFileTimeToUnixTimeEpochOffset = 116444736000000000ULL;
91
92struct timeval {
93  long tv_sec, tv_usec;  // NOLINT
94};
95
96// Emulate POSIX gettimeofday().
97// Based on breakpad/src/third_party/glog/src/utilities.cc
98static int gettimeofday(struct timeval *tv, void *tz) {
99  // FILETIME is measured in tens of microseconds since 1601-01-01 UTC.
100  FILETIME ft;
101  GetSystemTimeAsFileTime(&ft);
102
103  LARGE_INTEGER li;
104  li.LowPart = ft.dwLowDateTime;
105  li.HighPart = ft.dwHighDateTime;
106
107  // Convert to seconds and microseconds since Unix time Epoch.
108  int64_t micros = (li.QuadPart - kFileTimeToUnixTimeEpochOffset) / 10;
109  tv->tv_sec = static_cast<long>(micros / kNumMicrosecsPerSec);  // NOLINT
110  tv->tv_usec = static_cast<long>(micros % kNumMicrosecsPerSec); // NOLINT
111
112  return 0;
113}
114
115// Emulate POSIX gmtime_r().
116static struct tm *gmtime_r(const time_t *timep, struct tm *result) {
117  // On Windows, gmtime is thread safe.
118  struct tm *tm = gmtime(timep);  // NOLINT
119  if (tm == NULL) {
120    return NULL;
121  }
122  *result = *tm;
123  return result;
124}
125#endif  // WEBRTC_WIN
126
127void CurrentTmTime(struct tm *tm, int *microseconds) {
128  struct timeval timeval;
129  if (gettimeofday(&timeval, NULL) < 0) {
130    // Incredibly unlikely code path.
131    timeval.tv_sec = timeval.tv_usec = 0;
132  }
133  time_t secs = timeval.tv_sec;
134  gmtime_r(&secs, tm);
135  *microseconds = timeval.tv_usec;
136}
137
138uint32_t TimeAfter(int32_t elapsed) {
139  RTC_DCHECK_GE(elapsed, 0);
140  RTC_DCHECK_LT(static_cast<uint32_t>(elapsed), HALF);
141  return Time() + elapsed;
142}
143
144bool TimeIsBetween(uint32_t earlier, uint32_t middle, uint32_t later) {
145  if (earlier <= later) {
146    return ((earlier <= middle) && (middle <= later));
147  } else {
148    return !((later < middle) && (middle < earlier));
149  }
150}
151
152bool TimeIsLaterOrEqual(uint32_t earlier, uint32_t later) {
153#if EFFICIENT_IMPLEMENTATION
154  int32_t diff = later - earlier;
155  return (diff >= 0 && static_cast<uint32_t>(diff) < HALF);
156#else
157  const bool later_or_equal = TimeIsBetween(earlier, later, earlier + HALF);
158  return later_or_equal;
159#endif
160}
161
162bool TimeIsLater(uint32_t earlier, uint32_t later) {
163#if EFFICIENT_IMPLEMENTATION
164  int32_t diff = later - earlier;
165  return (diff > 0 && static_cast<uint32_t>(diff) < HALF);
166#else
167  const bool earlier_or_equal = TimeIsBetween(later, earlier, later + HALF);
168  return !earlier_or_equal;
169#endif
170}
171
172int32_t TimeDiff(uint32_t later, uint32_t earlier) {
173#if EFFICIENT_IMPLEMENTATION
174  return later - earlier;
175#else
176  const bool later_or_equal = TimeIsBetween(earlier, later, earlier + HALF);
177  if (later_or_equal) {
178    if (earlier <= later) {
179      return static_cast<long>(later - earlier);
180    } else {
181      return static_cast<long>(later + (UINT32_MAX - earlier) + 1);
182    }
183  } else {
184    if (later <= earlier) {
185      return -static_cast<long>(earlier - later);
186    } else {
187      return -static_cast<long>(earlier + (UINT32_MAX - later) + 1);
188    }
189  }
190#endif
191}
192
193TimestampWrapAroundHandler::TimestampWrapAroundHandler()
194    : last_ts_(0), num_wrap_(0) {}
195
196int64_t TimestampWrapAroundHandler::Unwrap(uint32_t ts) {
197  if (ts < last_ts_) {
198    if (last_ts_ > 0xf0000000 && ts < 0x0fffffff) {
199      ++num_wrap_;
200    }
201  }
202  last_ts_ = ts;
203  int64_t unwrapped_ts = ts + (num_wrap_ << 32);
204  return unwrapped_ts;
205}
206
207int64_t TmToSeconds(const std::tm& tm) {
208  static short int mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
209  static short int cumul_mdays[12] = {0,   31,  59,  90,  120, 151,
210                                      181, 212, 243, 273, 304, 334};
211  int year = tm.tm_year + 1900;
212  int month = tm.tm_mon;
213  int day = tm.tm_mday - 1;  // Make 0-based like the rest.
214  int hour = tm.tm_hour;
215  int min = tm.tm_min;
216  int sec = tm.tm_sec;
217
218  bool expiry_in_leap_year = (year % 4 == 0 &&
219                              (year % 100 != 0 || year % 400 == 0));
220
221  if (year < 1970)
222    return -1;
223  if (month < 0 || month > 11)
224    return -1;
225  if (day < 0 || day >= mdays[month] + (expiry_in_leap_year && month == 2 - 1))
226    return -1;
227  if (hour < 0 || hour > 23)
228    return -1;
229  if (min < 0 || min > 59)
230    return -1;
231  if (sec < 0 || sec > 59)
232    return -1;
233
234  day += cumul_mdays[month];
235
236  // Add number of leap days between 1970 and the expiration year, inclusive.
237  day += ((year / 4 - 1970 / 4) - (year / 100 - 1970 / 100) +
238          (year / 400 - 1970 / 400));
239
240  // We will have added one day too much above if expiration is during a leap
241  // year, and expiration is in January or February.
242  if (expiry_in_leap_year && month <= 2 - 1) // |month| is zero based.
243    day -= 1;
244
245  // Combine all variables into seconds from 1970-01-01 00:00 (except |month|
246  // which was accumulated into |day| above).
247  return (((static_cast<int64_t>
248            (year - 1970) * 365 + day) * 24 + hour) * 60 + min) * 60 + sec;
249}
250
251} // namespace rtc
252