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 #if defined(WIN32) 98 static const uint64 kFileTimeToUnixTimeEpochOffset = 116444736000000000ULL; 99 100 struct timeval { 101 long tv_sec, tv_usec; // NOLINT 102 }; 103 104 // Emulate POSIX gettimeofday(). 105 // Based on breakpad/src/third_party/glog/src/utilities.cc 106 static int gettimeofday(struct timeval *tv, void *tz) { 107 // FILETIME is measured in tens of microseconds since 1601-01-01 UTC. 108 FILETIME ft; 109 GetSystemTimeAsFileTime(&ft); 110 111 LARGE_INTEGER li; 112 li.LowPart = ft.dwLowDateTime; 113 li.HighPart = ft.dwHighDateTime; 114 115 // Convert to seconds and microseconds since Unix time Epoch. 116 int64 micros = (li.QuadPart - kFileTimeToUnixTimeEpochOffset) / 10; 117 tv->tv_sec = static_cast<long>(micros / kNumMicrosecsPerSec); // NOLINT 118 tv->tv_usec = static_cast<long>(micros % kNumMicrosecsPerSec); // NOLINT 119 120 return 0; 121 } 122 123 // Emulate POSIX gmtime_r(). 124 static struct tm *gmtime_r(const time_t *timep, struct tm *result) { 125 // On Windows, gmtime is thread safe. 126 struct tm *tm = gmtime(timep); // NOLINT 127 if (tm == NULL) { 128 return NULL; 129 } 130 *result = *tm; 131 return result; 132 } 133 #endif // WIN32 134 135 void CurrentTmTime(struct tm *tm, int *microseconds) { 136 struct timeval timeval; 137 if (gettimeofday(&timeval, NULL) < 0) { 138 // Incredibly unlikely code path. 139 timeval.tv_sec = timeval.tv_usec = 0; 140 } 141 time_t secs = timeval.tv_sec; 142 gmtime_r(&secs, tm); 143 *microseconds = timeval.tv_usec; 144 } 145 146 uint32 TimeAfter(int32 elapsed) { 147 ASSERT(elapsed >= 0); 148 ASSERT(static_cast<uint32>(elapsed) < HALF); 149 return Time() + elapsed; 150 } 151 152 bool TimeIsBetween(uint32 earlier, uint32 middle, uint32 later) { 153 if (earlier <= later) { 154 return ((earlier <= middle) && (middle <= later)); 155 } else { 156 return !((later < middle) && (middle < earlier)); 157 } 158 } 159 160 bool TimeIsLaterOrEqual(uint32 earlier, uint32 later) { 161 #if EFFICIENT_IMPLEMENTATION 162 int32 diff = later - earlier; 163 return (diff >= 0 && static_cast<uint32>(diff) < HALF); 164 #else 165 const bool later_or_equal = TimeIsBetween(earlier, later, earlier + HALF); 166 return later_or_equal; 167 #endif 168 } 169 170 bool TimeIsLater(uint32 earlier, uint32 later) { 171 #if EFFICIENT_IMPLEMENTATION 172 int32 diff = later - earlier; 173 return (diff > 0 && static_cast<uint32>(diff) < HALF); 174 #else 175 const bool earlier_or_equal = TimeIsBetween(later, earlier, later + HALF); 176 return !earlier_or_equal; 177 #endif 178 } 179 180 int32 TimeDiff(uint32 later, uint32 earlier) { 181 #if EFFICIENT_IMPLEMENTATION 182 return later - earlier; 183 #else 184 const bool later_or_equal = TimeIsBetween(earlier, later, earlier + HALF); 185 if (later_or_equal) { 186 if (earlier <= later) { 187 return static_cast<long>(later - earlier); 188 } else { 189 return static_cast<long>(later + (LAST - earlier) + 1); 190 } 191 } else { 192 if (later <= earlier) { 193 return -static_cast<long>(earlier - later); 194 } else { 195 return -static_cast<long>(earlier + (LAST - later) + 1); 196 } 197 } 198 #endif 199 } 200 201 } // namespace talk_base 202