1 /* 2 * libjingle 3 * Copyright 2008, 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 "talk/base/timing.h" 29 #include "talk/base/timeutils.h" 30 31 #if defined(POSIX) 32 #include <errno.h> 33 #include <math.h> 34 #include <sys/time.h> 35 #if defined(OSX) 36 #include <mach/mach.h> 37 #include <mach/clock.h> 38 #endif 39 #elif defined(WIN32) 40 #include <sys/timeb.h> 41 #include "talk/base/win32.h" 42 #endif 43 44 namespace talk_base { 45 46 Timing::Timing() { 47 #if defined(WIN32) 48 // This may fail, but we handle failure gracefully in the methods 49 // that use it (use alternative sleep method). 50 // 51 // TODO: Make it possible for user to tell if IdleWait will 52 // be done at lesser resolution because of this. 53 timer_handle_ = CreateWaitableTimer(NULL, // Security attributes. 54 FALSE, // Manual reset? 55 NULL); // Timer name. 56 #endif 57 } 58 59 Timing::~Timing() { 60 #if defined(WIN32) 61 if (timer_handle_ != NULL) 62 CloseHandle(timer_handle_); 63 #endif 64 } 65 66 double Timing::WallTimeNow() { 67 #if defined(POSIX) 68 struct timeval time; 69 gettimeofday(&time, NULL); 70 // Convert from second (1.0) and microsecond (1e-6). 71 return (static_cast<double>(time.tv_sec) + 72 static_cast<double>(time.tv_usec) * 1.0e-6); 73 74 #elif defined(WIN32) 75 struct _timeb time; 76 _ftime(&time); 77 // Convert from second (1.0) and milliseconds (1e-3). 78 return (static_cast<double>(time.time) + 79 static_cast<double>(time.millitm) * 1.0e-3); 80 #endif 81 } 82 83 double Timing::TimerNow() { 84 return (static_cast<double>(TimeNanos()) / kNumNanosecsPerSec); 85 } 86 87 double Timing::BusyWait(double period) { 88 double start_time = TimerNow(); 89 while (TimerNow() - start_time < period) { 90 } 91 return TimerNow() - start_time; 92 } 93 94 double Timing::IdleWait(double period) { 95 double start_time = TimerNow(); 96 97 #if defined(POSIX) 98 double sec_int, sec_frac = modf(period, &sec_int); 99 struct timespec ts; 100 ts.tv_sec = static_cast<time_t>(sec_int); 101 ts.tv_nsec = static_cast<long>(sec_frac * 1.0e9); // NOLINT 102 103 // NOTE(liulk): for the NOLINT above, long is the appropriate POSIX 104 // type. 105 106 // POSIX nanosleep may be interrupted by signals. 107 while (nanosleep(&ts, &ts) == -1 && errno == EINTR) { 108 } 109 110 #elif defined(WIN32) 111 if (timer_handle_ != NULL) { 112 LARGE_INTEGER due_time; 113 114 // Negative indicates relative time. The unit is 100 nanoseconds. 115 due_time.QuadPart = -LONGLONG(period * 1.0e7); 116 117 SetWaitableTimer(timer_handle_, &due_time, 0, NULL, NULL, TRUE); 118 WaitForSingleObject(timer_handle_, INFINITE); 119 } else { 120 // Still attempts to sleep with lesser resolution. 121 // The unit is in milliseconds. 122 Sleep(DWORD(period * 1.0e3)); 123 } 124 #endif 125 126 return TimerNow() - start_time; 127 } 128 129 } // namespace talk_base 130