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 #ifdef POSIX 29 #include <sys/time.h> 30 #if defined(OSX) || defined(IOS) 31 #include <mach/mach_time.h> 32 #endif 33 #endif 34 35 #ifdef WIN32 36 #define WIN32_LEAN_AND_MEAN 37 #include <windows.h> 38 #include <mmsystem.h> 39 #endif 40 41 #include "talk/base/common.h" 42 #include "talk/base/timeutils.h" 43 44 #define EFFICIENT_IMPLEMENTATION 1 45 46 namespace talk_base { 47 48 const uint32 LAST = 0xFFFFFFFF; 49 const uint32 HALF = 0x80000000; 50 51 uint64 TimeNanos() { 52 int64 ticks = 0; 53 #if defined(OSX) || defined(IOS) 54 static mach_timebase_info_data_t timebase; 55 if (timebase.denom == 0) { 56 // Get the timebase if this is the first time we run. 57 // Recommended by Apple's QA1398. 58 VERIFY(KERN_SUCCESS == mach_timebase_info(&timebase)); 59 } 60 // Use timebase to convert absolute time tick units into nanoseconds. 61 ticks = mach_absolute_time() * timebase.numer / timebase.denom; 62 #elif defined(POSIX) 63 struct timespec ts; 64 // TODO: Do we need to handle the case when CLOCK_MONOTONIC 65 // is not supported? 66 clock_gettime(CLOCK_MONOTONIC, &ts); 67 ticks = kNumNanosecsPerSec * static_cast<int64>(ts.tv_sec) + 68 static_cast<int64>(ts.tv_nsec); 69 #elif defined(WIN32) 70 static volatile LONG last_timegettime = 0; 71 static volatile int64 num_wrap_timegettime = 0; 72 volatile LONG* last_timegettime_ptr = &last_timegettime; 73 DWORD now = timeGetTime(); 74 // Atomically update the last gotten time 75 DWORD old = InterlockedExchange(last_timegettime_ptr, now); 76 if (now < old) { 77 // If now is earlier than old, there may have been a race between 78 // threads. 79 // 0x0fffffff ~3.1 days, the code will not take that long to execute 80 // so it must have been a wrap around. 81 if (old > 0xf0000000 && now < 0x0fffffff) { 82 num_wrap_timegettime++; 83 } 84 } 85 ticks = now + (num_wrap_timegettime << 32); 86 // TODO: Calculate with nanosecond precision. Otherwise, we're just 87 // wasting a multiply and divide when doing Time() on Windows. 88 ticks = ticks * kNumNanosecsPerMillisec; 89 #endif 90 return ticks; 91 } 92 93 uint32 Time() { 94 return static_cast<uint32>(TimeNanos() / kNumNanosecsPerMillisec); 95 } 96 97 uint64 TimeMicros() { 98 return static_cast<uint64>(TimeNanos() / kNumNanosecsPerMicrosec); 99 } 100 101 #if defined(WIN32) 102 static const uint64 kFileTimeToUnixTimeEpochOffset = 116444736000000000ULL; 103 104 struct timeval { 105 long tv_sec, tv_usec; // NOLINT 106 }; 107 108 // Emulate POSIX gettimeofday(). 109 // Based on breakpad/src/third_party/glog/src/utilities.cc 110 static int gettimeofday(struct timeval *tv, void *tz) { 111 // FILETIME is measured in tens of microseconds since 1601-01-01 UTC. 112 FILETIME ft; 113 GetSystemTimeAsFileTime(&ft); 114 115 LARGE_INTEGER li; 116 li.LowPart = ft.dwLowDateTime; 117 li.HighPart = ft.dwHighDateTime; 118 119 // Convert to seconds and microseconds since Unix time Epoch. 120 int64 micros = (li.QuadPart - kFileTimeToUnixTimeEpochOffset) / 10; 121 tv->tv_sec = static_cast<long>(micros / kNumMicrosecsPerSec); // NOLINT 122 tv->tv_usec = static_cast<long>(micros % kNumMicrosecsPerSec); // NOLINT 123 124 return 0; 125 } 126 127 // Emulate POSIX gmtime_r(). 128 static struct tm *gmtime_r(const time_t *timep, struct tm *result) { 129 // On Windows, gmtime is thread safe. 130 struct tm *tm = gmtime(timep); // NOLINT 131 if (tm == NULL) { 132 return NULL; 133 } 134 *result = *tm; 135 return result; 136 } 137 #endif // WIN32 138 139 void CurrentTmTime(struct tm *tm, int *microseconds) { 140 struct timeval timeval; 141 if (gettimeofday(&timeval, NULL) < 0) { 142 // Incredibly unlikely code path. 143 timeval.tv_sec = timeval.tv_usec = 0; 144 } 145 time_t secs = timeval.tv_sec; 146 gmtime_r(&secs, tm); 147 *microseconds = timeval.tv_usec; 148 } 149 150 uint32 TimeAfter(int32 elapsed) { 151 ASSERT(elapsed >= 0); 152 ASSERT(static_cast<uint32>(elapsed) < HALF); 153 return Time() + elapsed; 154 } 155 156 bool TimeIsBetween(uint32 earlier, uint32 middle, uint32 later) { 157 if (earlier <= later) { 158 return ((earlier <= middle) && (middle <= later)); 159 } else { 160 return !((later < middle) && (middle < earlier)); 161 } 162 } 163 164 bool TimeIsLaterOrEqual(uint32 earlier, uint32 later) { 165 #if EFFICIENT_IMPLEMENTATION 166 int32 diff = later - earlier; 167 return (diff >= 0 && static_cast<uint32>(diff) < HALF); 168 #else 169 const bool later_or_equal = TimeIsBetween(earlier, later, earlier + HALF); 170 return later_or_equal; 171 #endif 172 } 173 174 bool TimeIsLater(uint32 earlier, uint32 later) { 175 #if EFFICIENT_IMPLEMENTATION 176 int32 diff = later - earlier; 177 return (diff > 0 && static_cast<uint32>(diff) < HALF); 178 #else 179 const bool earlier_or_equal = TimeIsBetween(later, earlier, later + HALF); 180 return !earlier_or_equal; 181 #endif 182 } 183 184 int32 TimeDiff(uint32 later, uint32 earlier) { 185 #if EFFICIENT_IMPLEMENTATION 186 return later - earlier; 187 #else 188 const bool later_or_equal = TimeIsBetween(earlier, later, earlier + HALF); 189 if (later_or_equal) { 190 if (earlier <= later) { 191 return static_cast<long>(later - earlier); 192 } else { 193 return static_cast<long>(later + (LAST - earlier) + 1); 194 } 195 } else { 196 if (later <= earlier) { 197 return -static_cast<long>(earlier - later); 198 } else { 199 return -static_cast<long>(earlier + (LAST - later) + 1); 200 } 201 } 202 #endif 203 } 204 205 } // namespace talk_base 206