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 #include <sys/timeb.h>
27 #endif
28 
29 #include "rtc_base/checks.h"
30 #include "rtc_base/timeutils.h"
31 
32 namespace rtc {
33 
34 ClockInterface* g_clock = nullptr;
35 
SetClockForTesting(ClockInterface * clock)36 ClockInterface* SetClockForTesting(ClockInterface* clock) {
37   ClockInterface* prev = g_clock;
38   g_clock = clock;
39   return prev;
40 }
41 
GetClockForTesting()42 ClockInterface* GetClockForTesting() {
43   return g_clock;
44 }
45 
SystemTimeNanos()46 int64_t SystemTimeNanos() {
47   int64_t ticks;
48 #if defined(WEBRTC_MAC)
49   static mach_timebase_info_data_t timebase;
50   if (timebase.denom == 0) {
51     // Get the timebase if this is the first time we run.
52     // Recommended by Apple's QA1398.
53     if (mach_timebase_info(&timebase) != KERN_SUCCESS) {
54       RTC_NOTREACHED();
55     }
56   }
57   // Use timebase to convert absolute time tick units into nanoseconds.
58   ticks = mach_absolute_time() * timebase.numer / timebase.denom;
59 #elif defined(WEBRTC_POSIX)
60   struct timespec ts;
61   // TODO(deadbeef): Do we need to handle the case when CLOCK_MONOTONIC is not
62   // supported?
63   clock_gettime(CLOCK_MONOTONIC, &ts);
64   ticks = kNumNanosecsPerSec * static_cast<int64_t>(ts.tv_sec) +
65           static_cast<int64_t>(ts.tv_nsec);
66 #elif defined(WEBRTC_WIN)
67   static volatile LONG last_timegettime = 0;
68   static volatile int64_t num_wrap_timegettime = 0;
69   volatile LONG* last_timegettime_ptr = &last_timegettime;
70   DWORD now = timeGetTime();
71   // Atomically update the last gotten time
72   DWORD old = InterlockedExchange(last_timegettime_ptr, now);
73   if (now < old) {
74     // If now is earlier than old, there may have been a race between threads.
75     // 0x0fffffff ~3.1 days, the code will not take that long to execute
76     // so it must have been a wrap around.
77     if (old > 0xf0000000 && now < 0x0fffffff) {
78       num_wrap_timegettime++;
79     }
80   }
81   ticks = now + (num_wrap_timegettime << 32);
82   // TODO(deadbeef): Calculate with nanosecond precision. Otherwise, we're
83   // just wasting a multiply and divide when doing Time() on Windows.
84   ticks = ticks * kNumNanosecsPerMillisec;
85 #else
86 #error Unsupported platform.
87 #endif
88   return ticks;
89 }
90 
SystemTimeMillis()91 int64_t SystemTimeMillis() {
92   return static_cast<int64_t>(SystemTimeNanos() / kNumNanosecsPerMillisec);
93 }
94 
TimeNanos()95 int64_t TimeNanos() {
96   if (g_clock) {
97     return g_clock->TimeNanos();
98   }
99   return SystemTimeNanos();
100 }
101 
Time32()102 uint32_t Time32() {
103   return static_cast<uint32_t>(TimeNanos() / kNumNanosecsPerMillisec);
104 }
105 
TimeMillis()106 int64_t TimeMillis() {
107   return TimeNanos() / kNumNanosecsPerMillisec;
108 }
109 
TimeMicros()110 int64_t TimeMicros() {
111   return TimeNanos() / kNumNanosecsPerMicrosec;
112 }
113 
TimeAfter(int64_t elapsed)114 int64_t TimeAfter(int64_t elapsed) {
115   RTC_DCHECK_GE(elapsed, 0);
116   return TimeMillis() + elapsed;
117 }
118 
TimeDiff32(uint32_t later,uint32_t earlier)119 int32_t TimeDiff32(uint32_t later, uint32_t earlier) {
120   return later - earlier;
121 }
122 
TimeDiff(int64_t later,int64_t earlier)123 int64_t TimeDiff(int64_t later, int64_t earlier) {
124   return later - earlier;
125 }
126 
TimestampWrapAroundHandler()127 TimestampWrapAroundHandler::TimestampWrapAroundHandler()
128     : last_ts_(0), num_wrap_(-1) {}
129 
Unwrap(uint32_t ts)130 int64_t TimestampWrapAroundHandler::Unwrap(uint32_t ts) {
131   if (num_wrap_ == -1) {
132     last_ts_ = ts;
133     num_wrap_ = 0;
134     return ts;
135   }
136 
137   if (ts < last_ts_) {
138     if (last_ts_ >= 0xf0000000 && ts < 0x0fffffff)
139       ++num_wrap_;
140   } else if ((ts - last_ts_) > 0xf0000000) {
141     // Backwards wrap. Unwrap with last wrap count and don't update last_ts_.
142     return ts + (num_wrap_ - 1)*((int64_t)1 << 32);
143   }
144 
145   last_ts_ = ts;
146   return ts + (num_wrap_ << 32);
147 }
148 
TmToSeconds(const std::tm & tm)149 int64_t TmToSeconds(const std::tm& tm) {
150   static short int mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
151   static short int cumul_mdays[12] = {0,   31,  59,  90,  120, 151,
152                                       181, 212, 243, 273, 304, 334};
153   int year = tm.tm_year + 1900;
154   int month = tm.tm_mon;
155   int day = tm.tm_mday - 1;  // Make 0-based like the rest.
156   int hour = tm.tm_hour;
157   int min = tm.tm_min;
158   int sec = tm.tm_sec;
159 
160   bool expiry_in_leap_year = (year % 4 == 0 &&
161                               (year % 100 != 0 || year % 400 == 0));
162 
163   if (year < 1970)
164     return -1;
165   if (month < 0 || month > 11)
166     return -1;
167   if (day < 0 || day >= mdays[month] + (expiry_in_leap_year && month == 2 - 1))
168     return -1;
169   if (hour < 0 || hour > 23)
170     return -1;
171   if (min < 0 || min > 59)
172     return -1;
173   if (sec < 0 || sec > 59)
174     return -1;
175 
176   day += cumul_mdays[month];
177 
178   // Add number of leap days between 1970 and the expiration year, inclusive.
179   day += ((year / 4 - 1970 / 4) - (year / 100 - 1970 / 100) +
180           (year / 400 - 1970 / 400));
181 
182   // We will have added one day too much above if expiration is during a leap
183   // year, and expiration is in January or February.
184   if (expiry_in_leap_year && month <= 2 - 1) // |month| is zero based.
185     day -= 1;
186 
187   // Combine all variables into seconds from 1970-01-01 00:00 (except |month|
188   // which was accumulated into |day| above).
189   return (((static_cast<int64_t>
190             (year - 1970) * 365 + day) * 24 + hour) * 60 + min) * 60 + sec;
191 }
192 
TimeUTCMicros()193 int64_t TimeUTCMicros() {
194 #if defined(WEBRTC_POSIX)
195   struct timeval time;
196   gettimeofday(&time, nullptr);
197   // Convert from second (1.0) and microsecond (1e-6).
198   return (static_cast<int64_t>(time.tv_sec) * rtc::kNumMicrosecsPerSec +
199           time.tv_usec);
200 
201 #elif defined(WEBRTC_WIN)
202   struct _timeb time;
203   _ftime(&time);
204   // Convert from second (1.0) and milliseconds (1e-3).
205   return (static_cast<int64_t>(time.time) * rtc::kNumMicrosecsPerSec +
206           static_cast<int64_t>(time.millitm) * rtc::kNumMicrosecsPerMillisec);
207 #endif
208 }
209 
210 } // namespace rtc
211