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