diff options
Diffstat (limited to 'indra/llcommon/lltimer.cpp')
-rw-r--r-- | indra/llcommon/lltimer.cpp | 229 |
1 files changed, 114 insertions, 115 deletions
diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp index 9786d44899..38054b636e 100644 --- a/indra/llcommon/lltimer.cpp +++ b/indra/llcommon/lltimer.cpp @@ -2,30 +2,25 @@ * @file lltimer.cpp * @brief Cross-platform objects for doing timing * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -39,10 +34,8 @@ # define WIN32_LEAN_AND_MEAN # include <winsock2.h> # include <windows.h> -#elif LL_LINUX || LL_SOLARIS -# include <sys/time.h> -# include <sched.h> -#elif LL_DARWIN +#elif LL_LINUX || LL_SOLARIS || LL_DARWIN +# include <errno.h> # include <sys/time.h> #else # error "architecture not supported" @@ -81,42 +74,98 @@ U64 gLastTotalTimeClockCount = 0; //--------------------------------------------------------------------------- #if LL_WINDOWS -void ms_sleep(long ms) +void ms_sleep(U32 ms) { - Sleep((U32)ms); + Sleep(ms); } -void llyield() +U32 micro_sleep(U64 us, U32 max_yields) { - SleepEx(0, TRUE); // Relinquishes time slice to any thread of equal priority, can be woken up by extended IO functions + // max_yields is unused; just fiddle with it to avoid warnings. + max_yields = 0; + ms_sleep(us / 1000); + return 0; } -#elif LL_LINUX || LL_SOLARIS -void ms_sleep(long ms) +#elif LL_LINUX || LL_SOLARIS || LL_DARWIN +static void _sleep_loop(struct timespec& thiswait) { - struct timespec t; - t.tv_sec = ms / 1000; - t.tv_nsec = (ms % 1000) * 1000000l; - nanosleep(&t, NULL); -} + struct timespec nextwait; + bool sleep_more = false; -void llyield() -{ - sched_yield(); -} -#elif LL_DARWIN -void ms_sleep(long ms) -{ - struct timespec t; - t.tv_sec = ms / 1000; - t.tv_nsec = (ms % 1000) * 1000000l; - nanosleep(&t, NULL); -} + do { + int result = nanosleep(&thiswait, &nextwait); -void llyield() -{ -// sched_yield(); -} -#else + // check if sleep was interrupted by a signal; unslept + // remainder was written back into 't' and we just nanosleep + // again. + sleep_more = (result == -1 && EINTR == errno); + + if (sleep_more) + { + if ( nextwait.tv_sec > thiswait.tv_sec || + (nextwait.tv_sec == thiswait.tv_sec && + nextwait.tv_nsec >= thiswait.tv_nsec) ) + { + // if the remaining time isn't actually going + // down then we're being shafted by low clock + // resolution - manually massage the sleep time + // downward. + if (nextwait.tv_nsec > 1000000) { + // lose 1ms + nextwait.tv_nsec -= 1000000; + } else { + if (nextwait.tv_sec == 0) { + // already so close to finished + sleep_more = false; + } else { + // lose up to 1ms + nextwait.tv_nsec = 0; + } + } + } + thiswait = nextwait; + } + } while (sleep_more); +} + +U32 micro_sleep(U64 us, U32 max_yields) +{ + U64 start = get_clock_count(); + // This is kernel dependent. Currently, our kernel generates software clock + // interrupts at 250 Hz (every 4,000 microseconds). + const U64 KERNEL_SLEEP_INTERVAL_US = 4000; + + S32 num_sleep_intervals = (us - (KERNEL_SLEEP_INTERVAL_US >> 1)) / KERNEL_SLEEP_INTERVAL_US; + if (num_sleep_intervals > 0) + { + U64 sleep_time = (num_sleep_intervals * KERNEL_SLEEP_INTERVAL_US) - (KERNEL_SLEEP_INTERVAL_US >> 1); + struct timespec thiswait; + thiswait.tv_sec = sleep_time / 1000000; + thiswait.tv_nsec = (sleep_time % 1000000) * 1000l; + _sleep_loop(thiswait); + } + + U64 current_clock = get_clock_count(); + U32 yields = 0; + while ( (yields < max_yields) + && (current_clock - start < us) ) + { + sched_yield(); + ++yields; + current_clock = get_clock_count(); + } + return yields; +} + +void ms_sleep(U32 ms) +{ + long mslong = ms; // tv_nsec is a long + struct timespec thiswait; + thiswait.tv_sec = ms / 1000; + thiswait.tv_nsec = (mslong % 1000) * 1000000l; + _sleep_loop(thiswait); +} +#else # error "architecture not supported" #endif @@ -154,7 +203,7 @@ F64 calc_clock_frequency(U32 uiMeasureMSecs) // Both Linux and Mac use gettimeofday for accurate time F64 calc_clock_frequency(unsigned int uiMeasureMSecs) { - return 1000000.0; // microseconds, so 1 Mhz. + return 1000000.0; // microseconds, so 1 MHz. } U64 get_clock_count() @@ -323,7 +372,7 @@ void LLTimer::setTimerExpirySec(F32 expiration) + (U64)((F32)(expiration * gClockFrequency)); } -F32 LLTimer::getRemainingTimeF32() +F32 LLTimer::getRemainingTimeF32() const { U64 cur_ticks = get_clock_count(); if (cur_ticks > mExpirationTicks) @@ -348,7 +397,7 @@ BOOL LLTimer::checkExpirationAndReset(F32 expiration) } -BOOL LLTimer::hasExpired() +BOOL LLTimer::hasExpired() const { return (get_clock_count() >= mExpirationTicks) ? TRUE : FALSE; @@ -418,10 +467,9 @@ BOOL LLTimer::knownBadTimer() // /////////////////////////////////////////////////////////////////////////////// -U32 time_corrected() +time_t time_corrected() { - U32 corrected_time = (U32)time(NULL) + gUTCOffset; - return corrected_time; + return time(NULL) + gUTCOffset; } @@ -441,27 +489,25 @@ BOOL is_daylight_savings() } -struct tm* utc_to_pacific_time(S32 utc_time, BOOL pacific_daylight_time) +struct tm* utc_to_pacific_time(time_t utc_time, BOOL pacific_daylight_time) { - time_t unix_time = (time_t)utc_time; - S32 pacific_offset_hours; if (pacific_daylight_time) { - pacific_offset_hours = -7; + pacific_offset_hours = 7; } else { - pacific_offset_hours = -8; + pacific_offset_hours = 8; } // We subtract off the PST/PDT offset _before_ getting // "UTC" time, because this will handle wrapping around // for 5 AM UTC -> 10 PM PDT of the previous day. - unix_time += pacific_offset_hours * MIN_PER_HOUR * SEC_PER_MIN; + utc_time -= pacific_offset_hours * MIN_PER_HOUR * SEC_PER_MIN; // Internal buffer to PST/PDT (see above) - struct tm* internal_time = gmtime(&unix_time); + struct tm* internal_time = gmtime(&utc_time); /* // Don't do this, this won't correctly tell you if daylight savings is active in CA or not. @@ -475,7 +521,7 @@ struct tm* utc_to_pacific_time(S32 utc_time, BOOL pacific_daylight_time) } -void microsecondsToTimecodeString(U64 current_time, char *tcstring) +void microsecondsToTimecodeString(U64 current_time, std::string& tcstring) { U64 hours; U64 minutes; @@ -493,60 +539,13 @@ void microsecondsToTimecodeString(U64 current_time, char *tcstring) subframes = current_time / (U64)42; subframes %= 100; - sprintf(tcstring,"%3.3d:%2.2d:%2.2d:%2.2d.%2.2d",(int)hours,(int)minutes,(int)seconds,(int)frames,(int)subframes); /* Flawfinder: ignore */ + tcstring = llformat("%3.3d:%2.2d:%2.2d:%2.2d.%2.2d",(int)hours,(int)minutes,(int)seconds,(int)frames,(int)subframes); } -void secondsToTimecodeString(F32 current_time, char *tcstring) +void secondsToTimecodeString(F32 current_time, std::string& tcstring) { microsecondsToTimecodeString((U64)((F64)(SEC_TO_MICROSEC*current_time)), tcstring); } -////////////////////////////////////////////////////////////////////////////// -// -// LLEventTimer Implementation -// -////////////////////////////////////////////////////////////////////////////// - -std::list<LLEventTimer*> LLEventTimer::sActiveList; - -LLEventTimer::LLEventTimer(F32 period) -: mEventTimer() -{ - mPeriod = period; - sActiveList.push_back(this); -} - -LLEventTimer::~LLEventTimer() -{ - sActiveList.remove(this); -} - -void LLEventTimer::updateClass() -{ - std::list<LLEventTimer*> completed_timers; - for (std::list<LLEventTimer*>::iterator iter = sActiveList.begin(); iter != sActiveList.end(); ) - { - LLEventTimer* timer = *iter++; - F32 et = timer->mEventTimer.getElapsedTimeF32(); - if (et > timer->mPeriod) { - timer->mEventTimer.reset(); - if ( timer->tick() ) - { - completed_timers.push_back( timer ); - } - } - } - - if ( completed_timers.size() > 0 ) - { - for (std::list<LLEventTimer*>::iterator completed_iter = completed_timers.begin(); - completed_iter != completed_timers.end(); - completed_iter++ ) - { - delete *completed_iter; - } - } -} - |