summaryrefslogtreecommitdiff
path: root/indra/llcommon/lltimer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon/lltimer.cpp')
-rw-r--r--indra/llcommon/lltimer.cpp229
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;
- }
- }
-}
-