1/* 2 * libjingle 3 * Copyright 2004--2005, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include <stdint.h> 29 30#ifdef POSIX 31#include <sys/time.h> 32#if defined(OSX) || defined(IOS) 33#include <mach/mach_time.h> 34#endif 35#endif 36 37#ifdef WIN32 38#define WIN32_LEAN_AND_MEAN 39#include <windows.h> 40#include <mmsystem.h> 41#endif 42 43#include "talk/base/common.h" 44#include "talk/base/timeutils.h" 45 46#define EFFICIENT_IMPLEMENTATION 1 47 48namespace talk_base { 49 50const uint32 HALF = 0x80000000; 51 52uint64 TimeNanos() { 53 int64 ticks = 0; 54#if defined(OSX) || defined(IOS) 55 static mach_timebase_info_data_t timebase; 56 if (timebase.denom == 0) { 57 // Get the timebase if this is the first time we run. 58 // Recommended by Apple's QA1398. 59 VERIFY(KERN_SUCCESS == mach_timebase_info(&timebase)); 60 } 61 // Use timebase to convert absolute time tick units into nanoseconds. 62 ticks = mach_absolute_time() * timebase.numer / timebase.denom; 63#elif defined(POSIX) 64 struct timespec ts; 65 // TODO: Do we need to handle the case when CLOCK_MONOTONIC 66 // is not supported? 67 clock_gettime(CLOCK_MONOTONIC, &ts); 68 ticks = kNumNanosecsPerSec * static_cast<int64>(ts.tv_sec) + 69 static_cast<int64>(ts.tv_nsec); 70#elif defined(WIN32) 71 static volatile LONG last_timegettime = 0; 72 static volatile int64 num_wrap_timegettime = 0; 73 volatile LONG* last_timegettime_ptr = &last_timegettime; 74 DWORD now = timeGetTime(); 75 // Atomically update the last gotten time 76 DWORD old = InterlockedExchange(last_timegettime_ptr, now); 77 if (now < old) { 78 // If now is earlier than old, there may have been a race between 79 // threads. 80 // 0x0fffffff ~3.1 days, the code will not take that long to execute 81 // so it must have been a wrap around. 82 if (old > 0xf0000000 && now < 0x0fffffff) { 83 num_wrap_timegettime++; 84 } 85 } 86 ticks = now + (num_wrap_timegettime << 32); 87 // TODO: Calculate with nanosecond precision. Otherwise, we're just 88 // wasting a multiply and divide when doing Time() on Windows. 89 ticks = ticks * kNumNanosecsPerMillisec; 90#endif 91 return ticks; 92} 93 94uint32 Time() { 95 return static_cast<uint32>(TimeNanos() / kNumNanosecsPerMillisec); 96} 97 98uint64 TimeMicros() { 99 return static_cast<uint64>(TimeNanos() / kNumNanosecsPerMicrosec); 100} 101 102#if defined(WIN32) 103static const uint64 kFileTimeToUnixTimeEpochOffset = 116444736000000000ULL; 104 105struct timeval { 106 long tv_sec, tv_usec; // NOLINT 107}; 108 109// Emulate POSIX gettimeofday(). 110// Based on breakpad/src/third_party/glog/src/utilities.cc 111static int gettimeofday(struct timeval *tv, void *tz) { 112 // FILETIME is measured in tens of microseconds since 1601-01-01 UTC. 113 FILETIME ft; 114 GetSystemTimeAsFileTime(&ft); 115 116 LARGE_INTEGER li; 117 li.LowPart = ft.dwLowDateTime; 118 li.HighPart = ft.dwHighDateTime; 119 120 // Convert to seconds and microseconds since Unix time Epoch. 121 int64 micros = (li.QuadPart - kFileTimeToUnixTimeEpochOffset) / 10; 122 tv->tv_sec = static_cast<long>(micros / kNumMicrosecsPerSec); // NOLINT 123 tv->tv_usec = static_cast<long>(micros % kNumMicrosecsPerSec); // NOLINT 124 125 return 0; 126} 127 128// Emulate POSIX gmtime_r(). 129static struct tm *gmtime_r(const time_t *timep, struct tm *result) { 130 // On Windows, gmtime is thread safe. 131 struct tm *tm = gmtime(timep); // NOLINT 132 if (tm == NULL) { 133 return NULL; 134 } 135 *result = *tm; 136 return result; 137} 138#endif // WIN32 139 140void CurrentTmTime(struct tm *tm, int *microseconds) { 141 struct timeval timeval; 142 if (gettimeofday(&timeval, NULL) < 0) { 143 // Incredibly unlikely code path. 144 timeval.tv_sec = timeval.tv_usec = 0; 145 } 146 time_t secs = timeval.tv_sec; 147 gmtime_r(&secs, tm); 148 *microseconds = timeval.tv_usec; 149} 150 151uint32 TimeAfter(int32 elapsed) { 152 ASSERT(elapsed >= 0); 153 ASSERT(static_cast<uint32>(elapsed) < HALF); 154 return Time() + elapsed; 155} 156 157bool TimeIsBetween(uint32 earlier, uint32 middle, uint32 later) { 158 if (earlier <= later) { 159 return ((earlier <= middle) && (middle <= later)); 160 } else { 161 return !((later < middle) && (middle < earlier)); 162 } 163} 164 165bool TimeIsLaterOrEqual(uint32 earlier, uint32 later) { 166#if EFFICIENT_IMPLEMENTATION 167 int32 diff = later - earlier; 168 return (diff >= 0 && static_cast<uint32>(diff) < HALF); 169#else 170 const bool later_or_equal = TimeIsBetween(earlier, later, earlier + HALF); 171 return later_or_equal; 172#endif 173} 174 175bool TimeIsLater(uint32 earlier, uint32 later) { 176#if EFFICIENT_IMPLEMENTATION 177 int32 diff = later - earlier; 178 return (diff > 0 && static_cast<uint32>(diff) < HALF); 179#else 180 const bool earlier_or_equal = TimeIsBetween(later, earlier, later + HALF); 181 return !earlier_or_equal; 182#endif 183} 184 185int32 TimeDiff(uint32 later, uint32 earlier) { 186#if EFFICIENT_IMPLEMENTATION 187 return later - earlier; 188#else 189 const bool later_or_equal = TimeIsBetween(earlier, later, earlier + HALF); 190 if (later_or_equal) { 191 if (earlier <= later) { 192 return static_cast<long>(later - earlier); 193 } else { 194 return static_cast<long>(later + (UINT32_MAX - earlier) + 1); 195 } 196 } else { 197 if (later <= earlier) { 198 return -static_cast<long>(earlier - later); 199 } else { 200 return -static_cast<long>(earlier + (UINT32_MAX - later) + 1); 201 } 202 } 203#endif 204} 205 206TimestampWrapAroundHandler::TimestampWrapAroundHandler() 207 : last_ts_(0), num_wrap_(0) {} 208 209int64 TimestampWrapAroundHandler::Unwrap(uint32 ts) { 210 if (ts < last_ts_) { 211 if (last_ts_ > 0xf0000000 && ts < 0x0fffffff) { 212 ++num_wrap_; 213 } 214 } 215 last_ts_ = ts; 216 int64_t unwrapped_ts = ts + (num_wrap_ << 32); 217 return unwrapped_ts; 218} 219 220} // namespace talk_base 221