/* * libjingle * Copyright 2008, Google Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "talk/base/timing.h" #include "talk/base/timeutils.h" #if defined(POSIX) #include #include #include #if defined(OSX) #include #include #endif #elif defined(WIN32) #include #include "talk/base/win32.h" #endif namespace talk_base { Timing::Timing() { #if defined(WIN32) // This may fail, but we handle failure gracefully in the methods // that use it (use alternative sleep method). // // TODO: Make it possible for user to tell if IdleWait will // be done at lesser resolution because of this. timer_handle_ = CreateWaitableTimer(NULL, // Security attributes. FALSE, // Manual reset? NULL); // Timer name. #endif } Timing::~Timing() { #if defined(WIN32) if (timer_handle_ != NULL) CloseHandle(timer_handle_); #endif } // static double Timing::WallTimeNow() { #if defined(POSIX) struct timeval time; gettimeofday(&time, NULL); // Convert from second (1.0) and microsecond (1e-6). return (static_cast(time.tv_sec) + static_cast(time.tv_usec) * 1.0e-6); #elif defined(WIN32) struct _timeb time; _ftime(&time); // Convert from second (1.0) and milliseconds (1e-3). return (static_cast(time.time) + static_cast(time.millitm) * 1.0e-3); #endif } double Timing::TimerNow() { return (static_cast(TimeNanos()) / kNumNanosecsPerSec); } double Timing::BusyWait(double period) { double start_time = TimerNow(); while (TimerNow() - start_time < period) { } return TimerNow() - start_time; } double Timing::IdleWait(double period) { double start_time = TimerNow(); #if defined(POSIX) double sec_int, sec_frac = modf(period, &sec_int); struct timespec ts; ts.tv_sec = static_cast(sec_int); ts.tv_nsec = static_cast(sec_frac * 1.0e9); // NOLINT // NOTE(liulk): for the NOLINT above, long is the appropriate POSIX // type. // POSIX nanosleep may be interrupted by signals. while (nanosleep(&ts, &ts) == -1 && errno == EINTR) { } #elif defined(WIN32) if (timer_handle_ != NULL) { LARGE_INTEGER due_time; // Negative indicates relative time. The unit is 100 nanoseconds. due_time.QuadPart = -LONGLONG(period * 1.0e7); SetWaitableTimer(timer_handle_, &due_time, 0, NULL, NULL, TRUE); WaitForSingleObject(timer_handle_, INFINITE); } else { // Still attempts to sleep with lesser resolution. // The unit is in milliseconds. Sleep(DWORD(period * 1.0e3)); } #endif return TimerNow() - start_time; } } // namespace talk_base