summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
authorOz Linden <oz@lindenlab.com>2014-03-04 13:15:43 -0500
committerOz Linden <oz@lindenlab.com>2014-03-04 13:15:43 -0500
commita373a7442c244712ab17d793072699ef82684816 (patch)
tree2ed20e24993c4bfbb4f943ed7794fcd06eeb8a23 /indra/llcommon
parentb0c255f4e6141246f3575cb3d5b671af19966de9 (diff)
parentde8fea13627cc5978b8a6135802a52864a11c39a (diff)
merge changes for 3.7.2-release
Diffstat (limited to 'indra/llcommon')
-rwxr-xr-xindra/llcommon/CMakeLists.txt8
-rw-r--r--indra/llcommon/llalignedarray.h139
-rwxr-xr-xindra/llcommon/llapr.cpp2
-rwxr-xr-xindra/llcommon/llapr.h8
-rwxr-xr-xindra/llcommon/llcommon.cpp1
-rwxr-xr-xindra/llcommon/llcriticaldamp.cpp1
-rw-r--r--indra/llcommon/lldeadmantimer.cpp188
-rw-r--r--indra/llcommon/lldeadmantimer.h214
-rwxr-xr-xindra/llcommon/lleventapi.h1
-rwxr-xr-xindra/llcommon/lleventtimer.h1
-rwxr-xr-xindra/llcommon/llfasttimer.cpp8
-rwxr-xr-xindra/llcommon/llfasttimer.h3
-rw-r--r--[-rwxr-xr-x]indra/llcommon/llfoldertype.h0
-rwxr-xr-xindra/llcommon/llinitparam.h2
-rwxr-xr-xindra/llcommon/llinstancetracker.cpp15
-rwxr-xr-xindra/llcommon/llinstancetracker.h36
-rwxr-xr-xindra/llcommon/llleap.h1
-rwxr-xr-xindra/llcommon/lllslconstants.h29
-rwxr-xr-xindra/llcommon/llmemory.h129
-rw-r--r--indra/llcommon/llprocinfo.cpp94
-rw-r--r--indra/llcommon/llprocinfo.h68
-rwxr-xr-xindra/llcommon/llsd.cpp5
-rwxr-xr-xindra/llcommon/llsd.h4
-rwxr-xr-xindra/llcommon/llsingleton.cpp1
-rwxr-xr-xindra/llcommon/llsingleton.h143
-rw-r--r--indra/llcommon/llstaticstringtable.h82
-rwxr-xr-xindra/llcommon/llstringtable.h8
-rwxr-xr-xindra/llcommon/llsys.cpp39
-rwxr-xr-xindra/llcommon/llthread.cpp43
-rwxr-xr-xindra/llcommon/llthread.h86
-rwxr-xr-xindra/llcommon/lltimer.h7
-rw-r--r--indra/llcommon/llversionviewer.h41
-rw-r--r--indra/llcommon/tests/lldeadmantimer_test.cpp628
-rw-r--r--indra/llcommon/tests/llprocinfo_test.cpp91
34 files changed, 1901 insertions, 225 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 3a4a8facc2..8767616a70 100755
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -43,6 +43,7 @@ set(llcommon_SOURCE_FILES
llcriticaldamp.cpp
llcursortypes.cpp
lldate.cpp
+ lldeadmantimer.cpp
lldependencies.cpp
lldictionary.cpp
llerror.cpp
@@ -79,6 +80,7 @@ set(llcommon_SOURCE_FILES
llptrto.cpp
llprocess.cpp
llprocessor.cpp
+ llprocinfo.cpp
llqueuedthread.cpp
llrand.cpp
llrefcount.cpp
@@ -122,6 +124,7 @@ set(llcommon_HEADER_FILES
linden_common.h
linked_lists.h
llaccountingcost.h
+ llalignedarray.h
llallocator.h
llallocator_heap_profile.h
llagentconstants.h
@@ -145,6 +148,7 @@ set(llcommon_HEADER_FILES
lldarray.h
lldarrayptr.h
lldate.h
+ lldeadmantimer.h
lldefs.h
lldependencies.h
lldeleteutils.h
@@ -206,6 +210,7 @@ set(llcommon_HEADER_FILES
llpriqueuemap.h
llprocess.h
llprocessor.h
+ llprocinfo.h
llptrskiplist.h
llptrskipmap.h
llptrto.h
@@ -237,6 +242,7 @@ set(llcommon_HEADER_FILES
llstrider.h
llstring.h
llstringtable.h
+ llstaticstringtable.h
llsys.h
llthread.h
llthreadsafequeue.h
@@ -322,12 +328,14 @@ if (LL_TESTS)
LL_ADD_INTEGRATION_TEST(bitpack "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llbase64 "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(lldate "" "${test_libs}")
+ LL_ADD_INTEGRATION_TEST(lldeadmantimer "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(lldependencies "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llerror "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llframetimer "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llinstancetracker "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(lllazy "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llprocessor "" "${test_libs}")
+ LL_ADD_INTEGRATION_TEST(llprocinfo "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llrand "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llsdserialize "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llsingleton "" "${test_libs}")
diff --git a/indra/llcommon/llalignedarray.h b/indra/llcommon/llalignedarray.h
new file mode 100644
index 0000000000..ed8fd31205
--- /dev/null
+++ b/indra/llcommon/llalignedarray.h
@@ -0,0 +1,139 @@
+/**
+ * @file llalignedarray.h
+ * @brief A static array which obeys alignment restrictions and mimics std::vector accessors.
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * 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.
+ *
+ * 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.
+ *
+ * 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
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLALIGNEDARRAY_H
+#define LL_LLALIGNEDARRAY_H
+
+#include "llmemory.h"
+
+template <class T, U32 alignment>
+class LLAlignedArray
+{
+public:
+ T* mArray;
+ U32 mElementCount;
+ U32 mCapacity;
+
+ LLAlignedArray();
+ ~LLAlignedArray();
+
+ void push_back(const T& elem);
+ U32 size() const { return mElementCount; }
+ void resize(U32 size);
+ T* append(S32 N);
+ T& operator[](int idx);
+ const T& operator[](int idx) const;
+};
+
+template <class T, U32 alignment>
+LLAlignedArray<T, alignment>::LLAlignedArray()
+{
+ llassert(alignment >= 16);
+ mArray = NULL;
+ mElementCount = 0;
+ mCapacity = 0;
+}
+
+template <class T, U32 alignment>
+LLAlignedArray<T, alignment>::~LLAlignedArray()
+{
+ ll_aligned_free(mArray);
+ mArray = NULL;
+ mElementCount = 0;
+ mCapacity = 0;
+}
+
+template <class T, U32 alignment>
+void LLAlignedArray<T, alignment>::push_back(const T& elem)
+{
+ T* old_buf = NULL;
+ if (mCapacity <= mElementCount)
+ {
+ mCapacity++;
+ mCapacity *= 2;
+ T* new_buf = (T*) ll_aligned_malloc(mCapacity*sizeof(T), alignment);
+ if (mArray)
+ {
+ ll_memcpy_nonaliased_aligned_16((char*)new_buf, (char*)mArray, sizeof(T)*mElementCount);
+ }
+ old_buf = mArray;
+ mArray = new_buf;
+ }
+
+ mArray[mElementCount++] = elem;
+
+ //delete old array here to prevent error on a.push_back(a[0])
+ ll_aligned_free(old_buf);
+}
+
+template <class T, U32 alignment>
+void LLAlignedArray<T, alignment>::resize(U32 size)
+{
+ if (mCapacity < size)
+ {
+ mCapacity = size+mCapacity*2;
+ T* new_buf = mCapacity > 0 ? (T*) ll_aligned_malloc(mCapacity*sizeof(T), alignment) : NULL;
+ if (mArray)
+ {
+ ll_memcpy_nonaliased_aligned_16((char*) new_buf, (char*) mArray, sizeof(T)*mElementCount);
+ ll_aligned_free(mArray);
+ }
+
+ /*for (U32 i = mElementCount; i < mCapacity; ++i)
+ {
+ new(new_buf+i) T();
+ }*/
+ mArray = new_buf;
+ }
+
+ mElementCount = size;
+}
+
+
+template <class T, U32 alignment>
+T& LLAlignedArray<T, alignment>::operator[](int idx)
+{
+ llassert(idx < mElementCount);
+ return mArray[idx];
+}
+
+template <class T, U32 alignment>
+const T& LLAlignedArray<T, alignment>::operator[](int idx) const
+{
+ llassert(idx < mElementCount);
+ return mArray[idx];
+}
+
+template <class T, U32 alignment>
+T* LLAlignedArray<T, alignment>::append(S32 N)
+{
+ U32 sz = size();
+ resize(sz+N);
+ return &((*this)[sz]);
+}
+
+#endif
+
diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp
index a0802c6adf..b7815b0e35 100755
--- a/indra/llcommon/llapr.cpp
+++ b/indra/llcommon/llapr.cpp
@@ -226,7 +226,7 @@ void LLVolatileAPRPool::clearVolatileAPRPool()
llassert_always(mNumActiveRef > 0) ;
}
- llassert(mNumTotalRef < (FULL_VOLATILE_APR_POOL << 2)) ;
+ llassert(mNumTotalRef <= (FULL_VOLATILE_APR_POOL << 2)) ;
}
BOOL LLVolatileAPRPool::isFull()
diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h
index 752574c65d..1fe7d98472 100755
--- a/indra/llcommon/llapr.h
+++ b/indra/llcommon/llapr.h
@@ -164,14 +164,20 @@ public:
~LLAtomic32<Type>() {};
operator const Type() { apr_uint32_t data = apr_atomic_read32(&mData); return Type(data); }
+
+ Type CurrentValue() const { apr_uint32_t data = apr_atomic_read32(const_cast< volatile apr_uint32_t* >(&mData)); return Type(data); }
+
Type operator =(const Type& x) { apr_atomic_set32(&mData, apr_uint32_t(x)); return Type(mData); }
void operator -=(Type x) { apr_atomic_sub32(&mData, apr_uint32_t(x)); }
void operator +=(Type x) { apr_atomic_add32(&mData, apr_uint32_t(x)); }
Type operator ++(int) { return apr_atomic_inc32(&mData); } // Type++
Type operator --(int) { return apr_atomic_dec32(&mData); } // approximately --Type (0 if final is 0, non-zero otherwise)
+
+ Type operator ++() { return apr_atomic_inc32(&mData); } // Type++
+ Type operator --() { return apr_atomic_dec32(&mData); } // approximately --Type (0 if final is 0, non-zero otherwise)
private:
- apr_uint32_t mData;
+ volatile apr_uint32_t mData;
};
typedef LLAtomic32<U32> LLAtomicU32;
diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp
index 8be9e4f4de..b938b0e65a 100755
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -44,6 +44,7 @@ void LLCommon::initClass()
}
LLTimer::initClass();
LLThreadSafeRefCount::initThreadSafeRefCount();
+ assert_main_thread(); // Make sure we record the main thread
// LLWorkerThread::initClass();
// LLFrameCallbackManager::initClass();
}
diff --git a/indra/llcommon/llcriticaldamp.cpp b/indra/llcommon/llcriticaldamp.cpp
index 87d79b1ee0..49aac9ce75 100755
--- a/indra/llcommon/llcriticaldamp.cpp
+++ b/indra/llcommon/llcriticaldamp.cpp
@@ -87,3 +87,4 @@ F32 LLCriticalDamp::getInterpolant(const F32 time_constant, BOOL use_cache)
return interpolant;
}
+
diff --git a/indra/llcommon/lldeadmantimer.cpp b/indra/llcommon/lldeadmantimer.cpp
new file mode 100644
index 0000000000..7d9097e344
--- /dev/null
+++ b/indra/llcommon/lldeadmantimer.cpp
@@ -0,0 +1,188 @@
+/**
+* @file lldeadmantimer.cpp
+* @brief Simple deadman-switch timer.
+* @author monty@lindenlab.com
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2013, 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.
+*
+* 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.
+*
+* 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
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+* $/LicenseInfo$
+*/
+
+
+#include "lldeadmantimer.h"
+
+
+// *TODO: Currently, this uses lltimer functions for its time
+// aspects and this leaks into the apis in the U64s/F64s. Would
+// like to perhaps switch this over to TSC register-based timers
+// sometime and drop the overhead some more.
+
+
+// Flag states and their meaning:
+// mActive mDone Meaning
+// false false Nothing running, no result available
+// true false Timer running, no result available
+// false true Timer finished, result can be read once
+// true true Not allowed
+//
+LLDeadmanTimer::LLDeadmanTimer(F64 horizon, bool inc_cpu)
+ : mHorizon(time_type(llmax(horizon, F64(0.0)) * gClockFrequency)),
+ mActive(false), // If true, a timer is running.
+ mDone(false), // If true, timer has completed and can be read (once)
+ mStarted(U64L(0)),
+ mExpires(U64L(0)),
+ mStopped(U64L(0)),
+ mCount(U64L(0)),
+ mIncCPU(inc_cpu),
+ mUStartCPU(LLProcInfo::time_type(U64L(0))),
+ mUEndCPU(LLProcInfo::time_type(U64L(0))),
+ mSStartCPU(LLProcInfo::time_type(U64L(0))),
+ mSEndCPU(LLProcInfo::time_type(U64L(0)))
+{}
+
+
+// static
+LLDeadmanTimer::time_type LLDeadmanTimer::getNow()
+{
+ return LLTimer::getCurrentClockCount();
+}
+
+
+void LLDeadmanTimer::start(time_type now)
+{
+ // *TODO: If active, let's complete an existing timer and save
+ // the result to the side. I think this will be useful later.
+ // For now, wipe out anything in progress, start fresh.
+
+ if (! now)
+ {
+ now = LLTimer::getCurrentClockCount();
+ }
+ mActive = true;
+ mDone = false;
+ mStarted = now;
+ mExpires = now + mHorizon;
+ mStopped = now;
+ mCount = U64L(0);
+ if (mIncCPU)
+ {
+ LLProcInfo::getCPUUsage(mUStartCPU, mSStartCPU);
+ }
+}
+
+
+void LLDeadmanTimer::stop(time_type now)
+{
+ if (! mActive)
+ {
+ return;
+ }
+
+ if (! now)
+ {
+ now = getNow();
+ }
+ mStopped = now;
+ mActive = false;
+ mDone = true;
+ if (mIncCPU)
+ {
+ LLProcInfo::getCPUUsage(mUEndCPU, mSEndCPU);
+ }
+}
+
+
+bool LLDeadmanTimer::isExpired(time_type now, F64 & started, F64 & stopped, U64 & count,
+ U64 & user_cpu, U64 & sys_cpu)
+{
+ const bool status(isExpired(now, started, stopped, count));
+ if (status)
+ {
+ user_cpu = U64(mUEndCPU - mUStartCPU);
+ sys_cpu = U64(mSEndCPU - mSStartCPU);
+ }
+ return status;
+}
+
+
+bool LLDeadmanTimer::isExpired(time_type now, F64 & started, F64 & stopped, U64 & count)
+{
+ if (mActive && ! mDone)
+ {
+ if (! now)
+ {
+ now = getNow();
+ }
+
+ if (now >= mExpires)
+ {
+ // mStopped from ringBell() is the value we want
+ mActive = false;
+ mDone = true;
+ }
+ }
+
+ if (! mDone)
+ {
+ return false;
+ }
+
+ started = mStarted * gClockFrequencyInv;
+ stopped = mStopped * gClockFrequencyInv;
+ count = mCount;
+ mDone = false;
+
+ return true;
+}
+
+
+void LLDeadmanTimer::ringBell(time_type now, unsigned int count)
+{
+ if (! mActive)
+ {
+ return;
+ }
+
+ if (! now)
+ {
+ now = getNow();
+ }
+
+ if (now >= mExpires)
+ {
+ // Timer has expired, this event will be dropped
+ mActive = false;
+ mDone = true;
+ }
+ else
+ {
+ // Timer renewed, keep going
+ mStopped = now;
+ mExpires = now + mHorizon;
+ mCount += count;
+ if (mIncCPU)
+ {
+ LLProcInfo::getCPUUsage(mUEndCPU, mSEndCPU);
+ }
+ }
+
+ return;
+}
+
diff --git a/indra/llcommon/lldeadmantimer.h b/indra/llcommon/lldeadmantimer.h
new file mode 100644
index 0000000000..980976e176
--- /dev/null
+++ b/indra/llcommon/lldeadmantimer.h
@@ -0,0 +1,214 @@
+/**
+* @file lldeadmantimer.h
+* @brief Interface to a simple event timer with a deadman's switch
+* @author monty@lindenlab.com
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2013, 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.
+*
+* 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.
+*
+* 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
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+* $/LicenseInfo$
+*/
+
+#ifndef LL_DEADMANTIMER_H
+#define LL_DEADMANTIMER_H
+
+
+#include "linden_common.h"
+
+#include "lltimer.h"
+#include "llprocinfo.h"
+
+
+/// @file lldeadmantimer.h
+///
+/// There are interesting user-experienced events in the viewer that
+/// would seem to have well-defined start and stop points but which
+/// actually lack such milestones in the code. Such events (like
+/// time to load meshes after logging in, initial inventory load,
+/// display name fetch) can be defined somewhat after-the-fact by
+/// noticing when we no longer perform operations towards their
+/// completion. This class is intended to help in such applications.
+///
+/// What it implements is a deadman's switch (also known as a
+/// keepalive switch and a doorbell switch). The basic operation is
+/// as follows:
+///
+/// * LLDeadmanTimer is instantiated with a horizon value in seconds,
+/// one for each event of interest.
+/// * When an event starts, @see start() is invoked to begin a
+/// timing operation.
+/// * As operations are performed in service of the event (issuing
+/// HTTP requests, receiving responses), @see ringBell() is invoked
+/// to inform the timer that the operation is still active.
+/// * If the operation is canceled or otherwise terminated, @see
+/// stop() can be called to end the timing operation.
+/// * Concurrent with the ringBell() calls, the program makes
+/// periodic (shorter than the horizon but not too short) calls
+/// to @see isExpired() to see if the event has expired due to
+/// either a stop() call or lack of activity (defined as a ringBell()
+/// call in the previous 'horizon' seconds). If it has expired,
+/// the caller also receives start, stop and count values for the
+/// event which the application can then report in whatever manner
+/// it sees fit.
+/// * The timer becomes passive after an isExpired() call that returns
+/// true. It can then be restarted with a new start() call.
+///
+/// Threading: Instances are not thread-safe. They also use
+/// timing code from lltimer.h which is also unsafe.
+///
+/// Allocation: Not refcounted, may be stack or heap allocated.
+///
+
+class LL_COMMON_API LLDeadmanTimer
+{
+public:
+ /// Public types
+
+ /// Low-level time type chosen for compatibility with
+ /// LLTimer::getCurrentClockCount() which is the basis
+ /// of time operations in this class. This is likely
+ /// to change in a future version in a move to TSC-based
+ /// timing.
+ typedef U64 time_type;
+
+public:
+ /// Construct and initialize an LLDeadmanTimer
+ ///
+ /// @param horizon Time, in seconds, after the last @see ringBell()
+ /// call at which point the timer will consider itself
+ /// expired.
+ ///
+ /// @param inc_cpu If true, gather system and user cpu stats while
+ /// running the timer. This does require more syscalls
+ /// during updates. If false, cpu usage data isn't
+ /// collected and will be zero if queried.
+ LLDeadmanTimer(F64 horizon, bool inc_cpu);
+
+ ~LLDeadmanTimer()
+ {}
+
+private:
+ LLDeadmanTimer(const LLDeadmanTimer &); // Not defined
+ void operator=(const LLDeadmanTimer &); // Not defined
+
+public:
+ /// Get the current time. Zero-basis for this time
+ /// representation is not defined and is different on
+ /// different platforms. Do not attempt to compute
+ /// negative times relative to the first value returned,
+ /// there may not be enough 'front porch' on the range
+ /// to prevent wraparound.
+ ///
+ /// Note: Implementation is expected to change in a
+ /// future release as well.
+ ///
+ static time_type getNow();
+
+ /// Begin timing. If the timer is already active, it is reset
+ /// and timing begins now.
+ ///
+ /// @param now Current time as returned by @see
+ /// LLTimer::getCurrentClockCount(). If zero,
+ /// method will lookup current time.
+ ///
+ void start(time_type now);
+
+ /// End timing. Actively declare the end of the event independent
+ /// of the deadman's switch operation. @see isExpired() will return
+ /// true and appropriate values will be returned.
+ ///
+ /// @param now Current time as returned by @see
+ /// LLTimer::getCurrentClockCount(). If zero,
+ /// method will lookup current time.
+ ///
+ void stop(time_type now);
+
+ /// Declare that something interesting happened. This has two
+ /// effects on an unexpired-timer. 1) The expiration time
+ /// is extended for 'horizon' seconds after the 'now' value.
+ /// 2) An internal counter associated with the event is incremented
+ /// by the @ref count parameter. This count is returned via the
+ /// @see isExpired() method.
+ ///
+ /// @param now Current time as returned by @see
+ /// LLTimer::getCurrentClockCount(). If zero,
+ /// method will lookup current time.
+ ///
+ /// @param count Count of events to be associated with
+ /// this bell ringing.
+ ///
+ void ringBell(time_type now, unsigned int count);
+
+ /// Checks the status of the timer. If the timer has expired,
+ /// also returns various timer-related stats. Unlike ringBell(),
+ /// does not extend the horizon, it only checks for expiration.
+ ///
+ /// @param now Current time as returned by @see
+ /// LLTimer::getCurrentClockCount(). If zero,
+ /// method will lookup current time.
+ ///
+ /// @param started If expired, the starting time of the event is
+ /// returned to the caller via this reference.
+ ///
+ /// @param stopped If expired, the ending time of the event is
+ /// returned to the caller via this reference.
+ /// Ending time will be that provided in the
+ /// stop() method or the last ringBell() call
+ /// leading to expiration, whichever (stop() call
+ /// or notice of expiration) happened first.
+ ///
+ /// @param count If expired, the number of ringBell() calls
+ /// made prior to expiration.
+ ///
+ /// @param user_cpu Amount of CPU spent in user mode by the process
+ /// during the event. Value in microseconds and will
+ /// read zero if not enabled by the constructor.
+ ///
+ /// @param sys_cpu Amount of CPU spent in system mode by the process.
+ ///
+ /// @return true if the timer has expired, false otherwise.
+ /// If true, it also returns the started,
+ /// stopped and count values otherwise these are
+ /// left unchanged.
+ ///
+ bool isExpired(time_type now, F64 & started, F64 & stopped, U64 & count,
+ U64 & user_cpu, U64 & sys_cpu);
+
+ /// Identical to the six-arugment form except it does without the
+ /// CPU time return if the caller isn't interested in it.
+ bool isExpired(time_type now, F64 & started, F64 & stopped, U64 & count);
+
+protected:
+ time_type mHorizon;
+ bool mActive;
+ bool mDone;
+ time_type mStarted;
+ time_type mExpires;
+ time_type mStopped;
+ time_type mCount;
+
+ const bool mIncCPU; // Include CPU metrics in timer
+ LLProcInfo::time_type mUStartCPU;
+ LLProcInfo::time_type mUEndCPU;
+ LLProcInfo::time_type mSStartCPU;
+ LLProcInfo::time_type mSEndCPU;
+};
+
+
+#endif // LL_DEADMANTIMER_H
diff --git a/indra/llcommon/lleventapi.h b/indra/llcommon/lleventapi.h
index 1a37d780b6..5991fe8fd5 100755
--- a/indra/llcommon/lleventapi.h
+++ b/indra/llcommon/lleventapi.h
@@ -47,6 +47,7 @@ class LL_COMMON_API LLEventAPI: public LLDispatchListener,
typedef LLInstanceTracker<LLEventAPI, std::string> ibase;
public:
+
/**
* @param name LLEventPump name on which this LLEventAPI will listen. This
* also serves as the LLInstanceTracker instance key.
diff --git a/indra/llcommon/lleventtimer.h b/indra/llcommon/lleventtimer.h
index 7f42623d01..dc918121e1 100755
--- a/indra/llcommon/lleventtimer.h
+++ b/indra/llcommon/lleventtimer.h
@@ -36,6 +36,7 @@
class LL_COMMON_API LLEventTimer : public LLInstanceTracker<LLEventTimer>
{
public:
+
LLEventTimer(F32 period); // period is the amount of time between each call to tick() in seconds
LLEventTimer(const LLDate& time);
virtual ~LLEventTimer();
diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp
index 024fdd1b4d..01b6e60d2b 100755
--- a/indra/llcommon/llfasttimer.cpp
+++ b/indra/llcommon/llfasttimer.cpp
@@ -107,17 +107,13 @@ class NamedTimerFactory : public LLSingleton<NamedTimerFactory>
{
public:
NamedTimerFactory()
- : mTimerRoot(NULL)
- {}
-
- /*virtual */ void initSingleton()
+ : mTimerRoot(new LLFastTimer::NamedTimer("root"))
{
- mTimerRoot = new LLFastTimer::NamedTimer("root");
mRootFrameState.setNamedTimer(mTimerRoot);
mTimerRoot->setFrameState(&mRootFrameState);
mTimerRoot->mParent = mTimerRoot;
mTimerRoot->setCollapsed(false);
- mRootFrameState.mParent = &mRootFrameState;
+ mRootFrameState.mParent = &mRootFrameState;
}
~NamedTimerFactory()
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index 81c4b78775..a99a1d88af 100755
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -139,10 +139,11 @@ public:
// used to statically declare a new named timer
class LL_COMMON_API DeclareTimer
- : public LLInstanceTracker<DeclareTimer>
+ : public LLInstanceTracker< DeclareTimer >
{
friend class LLFastTimer;
public:
+
DeclareTimer(const std::string& name, bool open);
DeclareTimer(const std::string& name);
diff --git a/indra/llcommon/llfoldertype.h b/indra/llcommon/llfoldertype.h
index a0c847914f..a0c847914f 100755..100644
--- a/indra/llcommon/llfoldertype.h
+++ b/indra/llcommon/llfoldertype.h
diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h
index ae836645b9..03ab0fb67f 100755
--- a/indra/llcommon/llinitparam.h
+++ b/indra/llcommon/llinitparam.h
@@ -1952,7 +1952,7 @@ namespace LLInitParam
class Mandatory : public TypedParam<T, NAME_VALUE_LOOKUP, false>
{
typedef TypedParam<T, NAME_VALUE_LOOKUP, false> super_t;
- typedef Mandatory<T, NAME_VALUE_LOOKUP> self_t;
+ typedef Mandatory<T, NAME_VALUE_LOOKUP> self_t;
typedef typename super_t::value_t value_t;
typedef typename super_t::default_value_t default_value_t;
diff --git a/indra/llcommon/llinstancetracker.cpp b/indra/llcommon/llinstancetracker.cpp
index 5dc3ea5d7b..64a313b5ff 100755
--- a/indra/llcommon/llinstancetracker.cpp
+++ b/indra/llcommon/llinstancetracker.cpp
@@ -32,18 +32,3 @@
// external library headers
// other Linden headers
-//static
-void * & LLInstanceTrackerBase::getInstances(std::type_info const & info)
-{
- typedef std::map<std::string, void *> InstancesMap;
- static InstancesMap instances;
-
- // std::map::insert() is just what we want here. You attempt to insert a
- // (key, value) pair. If the specified key doesn't yet exist, it inserts
- // the pair and returns a std::pair of (iterator, true). If the specified
- // key DOES exist, insert() simply returns (iterator, false). One lookup
- // handles both cases.
- return instances.insert(InstancesMap::value_type(info.name(),
- InstancesMap::mapped_type()))
- .first->second;
-}
diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h
index 1eab270e3c..55187d8325 100755
--- a/indra/llcommon/llinstancetracker.h
+++ b/indra/llcommon/llinstancetracker.h
@@ -46,21 +46,7 @@
class LL_COMMON_API LLInstanceTrackerBase
{
protected:
- /// Get a process-unique void* pointer slot for the specified type_info
- static void * & getInstances(std::type_info const & info);
- /// Find or create a STATICDATA instance for the specified TRACKED class.
- /// STATICDATA must be default-constructible.
- template<typename STATICDATA, class TRACKED>
- static STATICDATA& getStatic()
- {
- void *& instances = getInstances(typeid(TRACKED));
- if (! instances)
- {
- instances = new STATICDATA;
- }
- return *static_cast<STATICDATA*>(instances);
- }
/// It's not essential to derive your STATICDATA (for use with
/// getStatic()) from StaticBase; it's just that both known
@@ -74,6 +60,8 @@ protected:
};
};
+LL_COMMON_API void assert_main_thread();
+
/// This mix-in class adds support for tracking all instances of the specified class parameter T
/// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup
/// If KEY is not provided, then instances are stored in a simple set
@@ -81,14 +69,18 @@ protected:
template<typename T, typename KEY = T*>
class LLInstanceTracker : public LLInstanceTrackerBase
{
- typedef LLInstanceTracker<T, KEY> MyT;
+ typedef LLInstanceTracker<T, KEY> self_t;
typedef typename std::map<KEY, T*> InstanceMap;
struct StaticData: public StaticBase
{
InstanceMap sMap;
};
- static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); }
- static InstanceMap& getMap_() { return getStatic().sMap; }
+ static StaticData& getStatic() { static StaticData sData; return sData;}
+ static InstanceMap& getMap_()
+ {
+ // assert_main_thread(); fwiw this class is not thread safe, and it used by multiple threads. Bad things happen.
+ return getStatic().sMap;
+ }
public:
class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
@@ -220,7 +212,11 @@ private:
}
void remove_()
{
- getMap_().erase(mInstanceKey);
+ typename InstanceMap::iterator iter = getMap_().find(mInstanceKey);
+ if (iter != getMap_().end())
+ {
+ getMap_().erase(iter);
+ }
}
private:
@@ -232,13 +228,13 @@ private:
template<typename T>
class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase
{
- typedef LLInstanceTracker<T, T*> MyT;
+ typedef LLInstanceTracker<T, T*> self_t;
typedef typename std::set<T*> InstanceSet;
struct StaticData: public StaticBase
{
InstanceSet sSet;
};
- static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); }
+ static StaticData& getStatic() { static StaticData sData; return sData; }
static InstanceSet& getSet_() { return getStatic().sSet; }
public:
diff --git a/indra/llcommon/llleap.h b/indra/llcommon/llleap.h
index 1a1ad23d39..e33f25e530 100755
--- a/indra/llcommon/llleap.h
+++ b/indra/llcommon/llleap.h
@@ -32,6 +32,7 @@
class LL_COMMON_API LLLeap: public LLInstanceTracker<LLLeap>
{
public:
+
/**
* Pass a brief string description, mostly for logging purposes. The desc
* need not be unique, but obviously the clearer we can make it, the
diff --git a/indra/llcommon/lllslconstants.h b/indra/llcommon/lllslconstants.h
index 9f32598e61..926ce32d75 100755
--- a/indra/llcommon/lllslconstants.h
+++ b/indra/llcommon/lllslconstants.h
@@ -67,6 +67,19 @@ const S32 LSL_PRIM_TEXGEN = 22;
const S32 LSL_PRIM_POINT_LIGHT = 23;
const S32 LSL_PRIM_CAST_SHADOWS = 24;
const S32 LSL_PRIM_GLOW = 25;
+const S32 LSL_PRIM_TEXT = 26;
+const S32 LSL_PRIM_NAME = 27;
+const S32 LSL_PRIM_DESC = 28;
+const S32 LSL_PRIM_ROT_LOCAL = 29;
+const S32 LSL_PRIM_PHYSICS_SHAPE_TYPE = 30;
+const S32 LSL_PRIM_OMEGA = 32;
+const S32 LSL_PRIM_POS_LOCAL = 33;
+const S32 LSL_PRIM_LINK_TARGET = 34;
+const S32 LSL_PRIM_SLICE = 35;
+
+const S32 LSL_PRIM_PHYSICS_SHAPE_PRIM = 0;
+const S32 LSL_PRIM_PHYSICS_SHAPE_NONE = 1;
+const S32 LSL_PRIM_PHYSICS_SHAPE_CONVEX = 2;
const S32 LSL_PRIM_TYPE_BOX = 0;
const S32 LSL_PRIM_TYPE_CYLINDER= 1;
@@ -179,6 +192,22 @@ const S32 OBJECT_VELOCITY = 5;
const S32 OBJECT_OWNER = 6;
const S32 OBJECT_GROUP = 7;
const S32 OBJECT_CREATOR = 8;
+const S32 OBJECT_RUNNING_SCRIPT_COUNT = 9;
+const S32 OBJECT_TOTAL_SCRIPT_COUNT = 10;
+const S32 OBJECT_SCRIPT_MEMORY = 11;
+const S32 OBJECT_SCRIPT_TIME = 12;
+const S32 OBJECT_PRIM_EQUIVALENCE = 13;
+const S32 OBJECT_SERVER_COST = 14;
+const S32 OBJECT_STREAMING_COST = 15;
+const S32 OBJECT_PHYSICS_COST = 16;
+const S32 OBJECT_CHARACTER_TIME = 17;
+const S32 OBJECT_ROOT = 18;
+const S32 OBJECT_ATTACHED_POINT = 19;
+const S32 OBJECT_PATHFINDING_TYPE = 20;
+const S32 OBJECT_PHYSICS = 21;
+const S32 OBJECT_PHANTOM = 22;
+const S32 OBJECT_TEMP_ON_REZ = 23;
+const S32 OBJECT_RENDER_WEIGHT = 24;
// llTextBox() magic token string - yes this is a hack. sue me.
char const* const TEXTBOX_MAGIC_TOKEN = "!!llTextBox!!";
diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index e725bdd9fa..61e30f11cc 100755
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -36,19 +36,68 @@ class LLMutex ;
#define LL_CHECK_MEMORY
#endif
+LL_COMMON_API void ll_assert_aligned_func(uintptr_t ptr,U32 alignment);
+
+#ifdef SHOW_ASSERT
+#define ll_assert_aligned(ptr,alignment) ll_assert_aligned_func(reinterpret_cast<uintptr_t>(ptr),((U32)alignment))
+#else
+#define ll_assert_aligned(ptr,alignment)
+#endif
+
+#include <xmmintrin.h>
+
+template <typename T> T* LL_NEXT_ALIGNED_ADDRESS(T* address)
+{
+ return reinterpret_cast<T*>(
+ (reinterpret_cast<uintptr_t>(address) + 0xF) & ~0xF);
+}
+
+template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address)
+{
+ return reinterpret_cast<T*>(
+ (reinterpret_cast<uintptr_t>(address) + 0x3F) & ~0x3F);
+}
+
+#if LL_LINUX || LL_DARWIN
+
+#define LL_ALIGN_PREFIX(x)
+#define LL_ALIGN_POSTFIX(x) __attribute__((aligned(x)))
+
+#elif LL_WINDOWS
+
+#define LL_ALIGN_PREFIX(x) __declspec(align(x))
+#define LL_ALIGN_POSTFIX(x)
+
+#else
+#error "LL_ALIGN_PREFIX and LL_ALIGN_POSTFIX undefined"
+#endif
+
+#define LL_ALIGN_16(var) LL_ALIGN_PREFIX(16) var LL_ALIGN_POSTFIX(16)
+
inline void* ll_aligned_malloc( size_t size, int align )
{
+#if defined(LL_WINDOWS)
+ return _aligned_malloc(size, align);
+#else
void* mem = malloc( size + (align - 1) + sizeof(void*) );
char* aligned = ((char*)mem) + sizeof(void*);
aligned += align - ((uintptr_t)aligned & (align - 1));
((void**)aligned)[-1] = mem;
return aligned;
+#endif
}
inline void ll_aligned_free( void* ptr )
{
- free( ((void**)ptr)[-1] );
+#if defined(LL_WINDOWS)
+ _aligned_free(ptr);
+#else
+ if (ptr)
+ {
+ free( ((void**)ptr)[-1] );
+ }
+#endif
}
#if !LL_USE_TCMALLOC
@@ -133,6 +182,78 @@ inline void ll_aligned_free_32(void *p)
#endif
}
+
+// Copy words 16-byte blocks from src to dst. Source and destination MUST NOT OVERLAP.
+// Source and dest must be 16-byte aligned and size must be multiple of 16.
+//
+inline void ll_memcpy_nonaliased_aligned_16(char* __restrict dst, const char* __restrict src, size_t bytes)
+{
+ assert(src != NULL);
+ assert(dst != NULL);
+ assert(bytes > 0);
+ assert((bytes % sizeof(F32))== 0);
+ ll_assert_aligned(src,16);
+ ll_assert_aligned(dst,16);
+ assert((src < dst) ? ((src + bytes) < dst) : ((dst + bytes) < src));
+ assert(bytes%16==0);
+
+ char* end = dst + bytes;
+
+ if (bytes > 64)
+ {
+
+ // Find start of 64b aligned area within block
+ //
+ void* begin_64 = LL_NEXT_ALIGNED_ADDRESS_64(dst);
+
+ //at least 64 bytes before the end of the destination, switch to 16 byte copies
+ void* end_64 = end-64;
+
+ // Prefetch the head of the 64b area now
+ //
+ _mm_prefetch((char*)begin_64, _MM_HINT_NTA);
+ _mm_prefetch((char*)begin_64 + 64, _MM_HINT_NTA);
+ _mm_prefetch((char*)begin_64 + 128, _MM_HINT_NTA);
+ _mm_prefetch((char*)begin_64 + 192, _MM_HINT_NTA);
+
+ // Copy 16b chunks until we're 64b aligned
+ //
+ while (dst < begin_64)
+ {
+
+ _mm_store_ps((F32*)dst, _mm_load_ps((F32*)src));
+ dst += 16;
+ src += 16;
+ }
+
+ // Copy 64b chunks up to your tail
+ //
+ // might be good to shmoo the 512b prefetch offset
+ // (characterize performance for various values)
+ //
+ while (dst < end_64)
+ {
+ _mm_prefetch((char*)src + 512, _MM_HINT_NTA);
+ _mm_prefetch((char*)dst + 512, _MM_HINT_NTA);
+ _mm_store_ps((F32*)dst, _mm_load_ps((F32*)src));
+ _mm_store_ps((F32*)(dst + 16), _mm_load_ps((F32*)(src + 16)));
+ _mm_store_ps((F32*)(dst + 32), _mm_load_ps((F32*)(src + 32)));
+ _mm_store_ps((F32*)(dst + 48), _mm_load_ps((F32*)(src + 48)));
+ dst += 64;
+ src += 64;
+ }
+ }
+
+ // Copy remainder 16b tail chunks (or ALL 16b chunks for sub-64b copies)
+ //
+ while (dst < end)
+ {
+ _mm_store_ps((F32*)dst, _mm_load_ps((F32*)src));
+ dst += 16;
+ src += 16;
+ }
+}
+
#ifndef __DEBUG_PRIVATE_MEM__
#define __DEBUG_PRIVATE_MEM__ 0
#endif
@@ -541,13 +662,7 @@ void LLPrivateMemoryPoolTester::operator delete[](void* addr)
// LLSingleton moved to llsingleton.h
-LL_COMMON_API void ll_assert_aligned_func(uintptr_t ptr,U32 alignment);
-#ifdef SHOW_ASSERT
-#define ll_assert_aligned(ptr,alignment) ll_assert_aligned_func(reinterpret_cast<uintptr_t>(ptr),((U32)alignment))
-#else
-#define ll_assert_aligned(ptr,alignment)
-#endif
#endif
diff --git a/indra/llcommon/llprocinfo.cpp b/indra/llcommon/llprocinfo.cpp
new file mode 100644
index 0000000000..c00f979b0b
--- /dev/null
+++ b/indra/llcommon/llprocinfo.cpp
@@ -0,0 +1,94 @@
+/**
+* @file llprocinfo.cpp
+* @brief Process, cpu and resource usage information APIs.
+* @author monty@lindenlab.com
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2013, 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.
+*
+* 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.
+*
+* 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
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+* $/LicenseInfo$
+*/
+
+
+#include "llprocinfo.h"
+
+#if LL_WINDOWS
+
+#define PSAPI_VERSION 1
+#include "windows.h"
+#include "psapi.h"
+
+#elif LL_DARWIN
+
+#include <sys/resource.h>
+#include <mach/mach.h>
+
+#else
+
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#endif // LL_WINDOWS/LL_DARWIN
+
+
+// static
+void LLProcInfo::getCPUUsage(time_type & user_time, time_type & system_time)
+{
+#if LL_WINDOWS
+
+ HANDLE self(GetCurrentProcess()); // Does not have to be closed
+ FILETIME ft_dummy, ft_system, ft_user;
+
+ GetProcessTimes(self, &ft_dummy, &ft_dummy, &ft_system, &ft_user);
+ ULARGE_INTEGER uli;
+ uli.u.LowPart = ft_system.dwLowDateTime;
+ uli.u.HighPart = ft_system.dwHighDateTime;
+ system_time = uli.QuadPart / U64L(10); // Convert to uS
+ uli.u.LowPart = ft_user.dwLowDateTime;
+ uli.u.HighPart = ft_user.dwHighDateTime;
+ user_time = uli.QuadPart / U64L(10);
+
+#elif LL_DARWIN
+
+ struct rusage usage;
+
+ if (getrusage(RUSAGE_SELF, &usage))
+ {
+ user_time = system_time = time_type(0U);
+ return;
+ }
+ user_time = U64(usage.ru_utime.tv_sec) * U64L(1000000) + usage.ru_utime.tv_usec;
+ system_time = U64(usage.ru_stime.tv_sec) * U64L(1000000) + usage.ru_stime.tv_usec;
+
+#else // Linux
+
+ struct rusage usage;
+
+ if (getrusage(RUSAGE_SELF, &usage))
+ {
+ user_time = system_time = time_type(0U);
+ return;
+ }
+ user_time = U64(usage.ru_utime.tv_sec) * U64L(1000000) + usage.ru_utime.tv_usec;
+ system_time = U64(usage.ru_stime.tv_sec) * U64L(1000000) + usage.ru_stime.tv_usec;
+
+#endif // LL_WINDOWS/LL_DARWIN/Linux
+}
+
+
diff --git a/indra/llcommon/llprocinfo.h b/indra/llcommon/llprocinfo.h
new file mode 100644
index 0000000000..e78bcf490a
--- /dev/null
+++ b/indra/llcommon/llprocinfo.h
@@ -0,0 +1,68 @@
+/**
+* @file llprocinfo.h
+* @brief Interface to process/cpu/resource information services.
+* @author monty@lindenlab.com
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2013, 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.
+*
+* 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.
+*
+* 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
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+* $/LicenseInfo$
+*/
+
+#ifndef LL_PROCINFO_H
+#define LL_PROCINFO_H
+
+
+#include "linden_common.h"
+
+/// @file llprocinfo.h
+///
+/// Right now, this is really a namespace disguised as a class.
+/// It wraps some types and functions to return information about
+/// process resource consumption in a non-OS-specific manner.
+///
+/// Threading: No instances so that's thread-safe. Implementations
+/// of static functions should be thread-safe, they mostly involve
+/// direct syscall invocations.
+///
+/// Allocation: Not instantiatable.
+
+class LL_COMMON_API LLProcInfo
+{
+public:
+ /// Public types
+
+ typedef U64 time_type; /// Relative microseconds
+
+private:
+ LLProcInfo(); // Not defined
+ ~LLProcInfo(); // Not defined
+ LLProcInfo(const LLProcInfo &); // Not defined
+ void operator=(const LLProcInfo &); // Not defined
+
+public:
+ /// Get accumulated system and user CPU time in
+ /// microseconds. Syscalls involved in every invocation.
+ ///
+ /// Threading: expected to be safe.
+ static void getCPUUsage(time_type & user_time, time_type & system_time);
+};
+
+
+#endif // LL_PROCINFO_H
diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp
index 8276ec836a..f962485284 100755
--- a/indra/llcommon/llsd.cpp
+++ b/indra/llcommon/llsd.cpp
@@ -506,6 +506,8 @@ namespace
LLSD::array_iterator beginArray() { return mData.begin(); }
LLSD::array_iterator endArray() { return mData.end(); }
+ LLSD::reverse_array_iterator rbeginArray() { return mData.rbegin(); }
+ LLSD::reverse_array_iterator rendArray() { return mData.rend(); }
virtual LLSD::array_const_iterator beginArray() const { return mData.begin(); }
virtual LLSD::array_const_iterator endArray() const { return mData.end(); }
@@ -947,6 +949,9 @@ LLSD::array_iterator LLSD::endArray() { return makeArray(impl).endArray(); }
LLSD::array_const_iterator LLSD::beginArray() const{ return safe(impl).beginArray(); }
LLSD::array_const_iterator LLSD::endArray() const { return safe(impl).endArray(); }
+LLSD::reverse_array_iterator LLSD::rbeginArray() { return makeArray(impl).rbeginArray(); }
+LLSD::reverse_array_iterator LLSD::rendArray() { return makeArray(impl).rendArray(); }
+
namespace llsd
{
diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h
index 5eb69059ac..deb87d7497 100755
--- a/indra/llcommon/llsd.h
+++ b/indra/llcommon/llsd.h
@@ -320,11 +320,15 @@ public:
typedef std::vector<LLSD>::iterator array_iterator;
typedef std::vector<LLSD>::const_iterator array_const_iterator;
+ typedef std::vector<LLSD>::reverse_iterator reverse_array_iterator;
array_iterator beginArray();
array_iterator endArray();
array_const_iterator beginArray() const;
array_const_iterator endArray() const;
+
+ reverse_array_iterator rbeginArray();
+ reverse_array_iterator rendArray();
//@}
/** @name Type Testing */
diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp
index eb8e2c9456..9b49e52377 100755
--- a/indra/llcommon/llsingleton.cpp
+++ b/indra/llcommon/llsingleton.cpp
@@ -28,5 +28,4 @@
#include "llsingleton.h"
-std::map<std::string, void *> * LLSingletonRegistry::sSingletonMap = NULL;
diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 49d99f2cd0..40002313f1 100755
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -30,38 +30,6 @@
#include <typeinfo>
#include <boost/noncopyable.hpp>
-/// @brief A global registry of all singletons to prevent duplicate allocations
-/// across shared library boundaries
-class LL_COMMON_API LLSingletonRegistry {
- private:
- typedef std::map<std::string, void *> TypeMap;
- static TypeMap * sSingletonMap;
-
- static void checkInit()
- {
- if(sSingletonMap == NULL)
- {
- sSingletonMap = new TypeMap();
- }
- }
-
- public:
- template<typename T> static void * & get()
- {
- std::string name(typeid(T).name());
-
- checkInit();
-
- // the first entry of the pair returned by insert will be either the existing
- // iterator matching our key, or the newly inserted NULL initialized entry
- // see "Insert element" in http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
- TypeMap::iterator result =
- sSingletonMap->insert(std::make_pair(name, (void*)NULL)).first;
-
- return result->second;
- }
-};
-
// LLSingleton implements the getInstance() method part of the Singleton
// pattern. It can't make the derived class constructors protected, though, so
// you have to do that yourself.
@@ -101,20 +69,23 @@ private:
} EInitState;
// stores pointer to singleton instance
- // and tracks initialization state of singleton
- struct SingletonInstanceData
+ struct SingletonLifetimeManager
{
- EInitState mInitState;
- DERIVED_TYPE* mSingletonInstance;
-
- SingletonInstanceData()
- : mSingletonInstance(NULL),
- mInitState(UNINITIALIZED)
- {}
-
- ~SingletonInstanceData()
+ SingletonLifetimeManager()
+ {
+ construct();
+ }
+
+ static void construct()
{
- if (mInitState != DELETED)
+ sData.mInitState = CONSTRUCTING;
+ sData.mInstance = new DERIVED_TYPE();
+ sData.mInitState = INITIALIZING;
+ }
+
+ ~SingletonLifetimeManager()
+ {
+ if (sData.mInitState != DELETED)
{
deleteSingleton();
}
@@ -124,9 +95,8 @@ private:
public:
virtual ~LLSingleton()
{
- SingletonInstanceData& data = getData();
- data.mSingletonInstance = NULL;
- data.mInitState = DELETED;
+ sData.mInstance = NULL;
+ sData.mInitState = DELETED;
}
/**
@@ -151,50 +121,46 @@ public:
*/
static void deleteSingleton()
{
- delete getData().mSingletonInstance;
- getData().mSingletonInstance = NULL;
- getData().mInitState = DELETED;
+ delete sData.mInstance;
+ sData.mInstance = NULL;
+ sData.mInitState = DELETED;
}
- static SingletonInstanceData& getData()
- {
- // this is static to cache the lookup results
- static void * & registry = LLSingletonRegistry::get<DERIVED_TYPE>();
-
- // *TODO - look into making this threadsafe
- if(NULL == registry)
- {
- static SingletonInstanceData data;
- registry = &data;
- }
-
- return *static_cast<SingletonInstanceData *>(registry);
- }
static DERIVED_TYPE* getInstance()
{
- SingletonInstanceData& data = getData();
+ static SingletonLifetimeManager sLifeTimeMgr;
- if (data.mInitState == CONSTRUCTING)
+ switch (sData.mInitState)
{
+ case UNINITIALIZED:
+ // should never be uninitialized at this point
+ llassert(false);
+ return NULL;
+ case CONSTRUCTING:
llerrs << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << llendl;
- }
-
- if (data.mInitState == DELETED)
- {
+ return NULL;
+ case INITIALIZING:
+ // go ahead and flag ourselves as initialized so we can be reentrant during initialization
+ sData.mInitState = INITIALIZED;
+ sData.mInstance->initSingleton();
+ return sData.mInstance;
+ case INITIALIZED:
+ return sData.mInstance;
+ case DELETED:
llwarns << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << llendl;
+ SingletonLifetimeManager::construct();
+ sData.mInitState = INITIALIZED;
+ sData.mInstance->initSingleton();
+ return sData.mInstance;
}
-
- if (!data.mSingletonInstance)
- {
- data.mInitState = CONSTRUCTING;
- data.mSingletonInstance = new DERIVED_TYPE();
- data.mInitState = INITIALIZING;
- data.mSingletonInstance->initSingleton();
- data.mInitState = INITIALIZED;
- }
-
- return data.mSingletonInstance;
+
+ return NULL;
+ }
+
+ static DERIVED_TYPE* getIfExists()
+ {
+ return sData.mInstance;
}
// Reference version of getInstance()
@@ -208,18 +174,29 @@ public:
// Use this to avoid accessing singletons before the can safely be constructed
static bool instanceExists()
{
- return getData().mInitState == INITIALIZED;
+ return sData.mInitState == INITIALIZED;
}
// Has this singleton already been deleted?
// Use this to avoid accessing singletons from a static object's destructor
static bool destroyed()
{
- return getData().mInitState == DELETED;
+ return sData.mInitState == DELETED;
}
private:
+
virtual void initSingleton() {}
+
+ struct SingletonData
+ {
+ EInitState mInitState;
+ DERIVED_TYPE* mInstance;
+ };
+ static SingletonData sData;
};
+template<typename T>
+typename LLSingleton<T>::SingletonData LLSingleton<T>::sData;
+
#endif
diff --git a/indra/llcommon/llstaticstringtable.h b/indra/llcommon/llstaticstringtable.h
new file mode 100644
index 0000000000..d7e0e8a08d
--- /dev/null
+++ b/indra/llcommon/llstaticstringtable.h
@@ -0,0 +1,82 @@
+/**
+ * @file llstringtable.h
+ * @brief The LLStringTable class provides a _fast_ method for finding
+ * unique copies of strings.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * 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.
+ *
+ * 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.
+ *
+ * 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
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_STATIC_STRING_TABLE_H
+#define LL_STATIC_STRING_TABLE_H
+
+#include "lldefs.h"
+#include <boost/unordered_map.hpp>
+#include "llstl.h"
+
+class LLStaticHashedString
+{
+public:
+
+ LLStaticHashedString(const std::string& s)
+ {
+ string_hash = makehash(s);
+ string = s;
+ }
+
+ const std::string& String() const { return string; }
+ size_t Hash() const { return string_hash; }
+
+ bool operator==(const LLStaticHashedString& b) const { return Hash() == b.Hash(); }
+
+protected:
+
+ size_t makehash(const std::string& s)
+ {
+ size_t len = s.size();
+ const char* c = s.c_str();
+ size_t hashval = 0;
+ for (size_t i=0; i<len; i++)
+ {
+ hashval = ((hashval<<5) + hashval) + *c++;
+ }
+ return hashval;
+ }
+
+ std::string string;
+ size_t string_hash;
+};
+
+struct LLStaticStringHasher
+{
+ enum { bucket_size = 8 };
+ size_t operator()(const LLStaticHashedString& key_value) const { return key_value.Hash(); }
+ bool operator()(const LLStaticHashedString& left, const LLStaticHashedString& right) const { return left.Hash() < right.Hash(); }
+};
+
+template< typename MappedObject >
+class LL_COMMON_API LLStaticStringTable
+ : public boost::unordered_map< LLStaticHashedString, MappedObject, LLStaticStringHasher >
+{
+};
+
+#endif
+
diff --git a/indra/llcommon/llstringtable.h b/indra/llcommon/llstringtable.h
index 59d7372ed4..ff09e71677 100755
--- a/indra/llcommon/llstringtable.h
+++ b/indra/llcommon/llstringtable.h
@@ -42,14 +42,6 @@
//# define STRING_TABLE_HASH_MAP 1
#endif
-#if STRING_TABLE_HASH_MAP
-# if LL_WINDOWS
-# include <hash_map>
-# else
-# include <ext/hash_map>
-# endif
-#endif
-
const U32 MAX_STRINGS_LENGTH = 256;
class LL_COMMON_API LLStringTableEntry
diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp
index 0730b2ed8b..e63045659e 100755
--- a/indra/llcommon/llsys.cpp
+++ b/indra/llcommon/llsys.cpp
@@ -114,6 +114,9 @@ static const F32 MEM_INFO_THROTTLE = 20;
static const F32 MEM_INFO_WINDOW = 10*60;
#if LL_WINDOWS
+// We cannot trust GetVersionEx function on Win8.1 , we should check this value when creating OS string
+static const U32 WINNT_WINBLUE = 0x0603;
+
#ifndef DLLVERSIONINFO
typedef struct _DllVersionInfo
{
@@ -214,6 +217,26 @@ static bool regex_search_no_exc(const S& string, M& match, const R& regex)
}
}
+#if LL_WINDOWS
+// GetVersionEx should not works correct with Windows 8.1 and the later version. We need to check this case
+static bool check_for_version(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
+{
+ OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 };
+ DWORDLONG const dwlConditionMask = VerSetConditionMask(
+ VerSetConditionMask(
+ VerSetConditionMask(
+ 0, VER_MAJORVERSION, VER_GREATER_EQUAL),
+ VER_MINORVERSION, VER_GREATER_EQUAL),
+ VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
+
+ osvi.dwMajorVersion = wMajorVersion;
+ osvi.dwMinorVersion = wMinorVersion;
+ osvi.wServicePackMajor = wServicePackMajor;
+
+ return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
+}
+#endif
+
LLOSInfo::LLOSInfo() :
mMajorVer(0), mMinorVer(0), mBuild(0), mOSVersionString("")
@@ -222,6 +245,7 @@ LLOSInfo::LLOSInfo() :
#if LL_WINDOWS
OSVERSIONINFOEX osvi;
BOOL bOsVersionInfoEx;
+ BOOL bShouldUseShellVersion = false;
// Try calling GetVersionEx using the OSVERSIONINFOEX structure.
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
@@ -284,11 +308,19 @@ LLOSInfo::LLOSInfo() :
}
else if(osvi.dwMinorVersion == 2)
{
+ if (check_for_version(HIBYTE(WINNT_WINBLUE), LOBYTE(WINNT_WINBLUE), 0))
+ {
+ mOSStringSimple = "Microsoft Windows 8.1 ";
+ bShouldUseShellVersion = true; // GetVersionEx failed, going to use shell version
+ }
+ else
+ {
if(osvi.wProductType == VER_NT_WORKSTATION)
mOSStringSimple = "Microsoft Windows 8 ";
else
mOSStringSimple = "Windows Server 2012 ";
}
+ }
///get native system info if available..
typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); ///function pointer for loading GetNativeSystemInfo
@@ -354,9 +386,8 @@ LLOSInfo::LLOSInfo() :
}
else
{
- tmpstr = llformat("%s (Build %d)",
- csdversion.c_str(),
- (osvi.dwBuildNumber & 0xffff));
+ tmpstr = !bShouldUseShellVersion ? llformat("%s (Build %d)", csdversion.c_str(), (osvi.dwBuildNumber & 0xffff)):
+ llformat("%s (Build %d)", csdversion.c_str(), shell32_build);
}
mOSString = mOSStringSimple + tmpstr;
@@ -392,7 +423,7 @@ LLOSInfo::LLOSInfo() :
std::string compatibility_mode;
if(got_shell32_version)
{
- if(osvi.dwMajorVersion != shell32_major || osvi.dwMinorVersion != shell32_minor)
+ if((osvi.dwMajorVersion != shell32_major || osvi.dwMinorVersion != shell32_minor) && !bShouldUseShellVersion)
{
compatibility_mode = llformat(" compatibility mode. real ver: %d.%d (Build %d)",
shell32_major,
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index 1d56a52c32..e67d1bc57b 100755
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -3,7 +3,7 @@
*
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2010-2013, 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
@@ -67,7 +67,8 @@ LL_COMMON_API void assert_main_thread()
static U32 s_thread_id = LLThread::currentID();
if (LLThread::currentID() != s_thread_id)
{
- llerrs << "Illegal execution outside main thread." << llendl;
+ llwarns << "Illegal execution from thread id " << (S32) LLThread::currentID()
+ << " outside main thread " << (S32) s_thread_id << llendl;
}
}
@@ -372,6 +373,36 @@ void LLMutex::lock()
#endif
}
+bool LLMutex::trylock()
+{
+ if(isSelfLocked())
+ { //redundant lock
+ mCount++;
+ return true;
+ }
+
+ apr_status_t status(apr_thread_mutex_trylock(mAPRMutexp));
+ if (APR_STATUS_IS_EBUSY(status))
+ {
+ return false;
+ }
+
+#if MUTEX_DEBUG
+ // Have to have the lock before we can access the debug info
+ U32 id = LLThread::currentID();
+ if (mIsLocked[id] != FALSE)
+ llerrs << "Already locked in Thread: " << id << llendl;
+ mIsLocked[id] = TRUE;
+#endif
+
+#if LL_DARWIN
+ mLockingThread = LLThread::currentID();
+#else
+ mLockingThread = sThreadID;
+#endif
+ return true;
+}
+
void LLMutex::unlock()
{
if (mCount > 0)
@@ -495,15 +526,7 @@ LLThreadSafeRefCount::LLThreadSafeRefCount() :
LLThreadSafeRefCount::LLThreadSafeRefCount(const LLThreadSafeRefCount& src)
{
- if (sMutex)
- {
- sMutex->lock();
- }
mRef = 0;
- if (sMutex)
- {
- sMutex->unlock();
- }
}
LLThreadSafeRefCount::~LLThreadSafeRefCount()
diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index 0fb89c5613..8c7143304f 100755
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -4,7 +4,7 @@
*
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2010-2013, 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
@@ -156,7 +156,8 @@ public:
virtual ~LLMutex();
void lock(); // blocks
- void unlock();
+ bool trylock(); // non-blocking, returns true if lock held.
+ void unlock(); // undefined behavior when called on mutex not being held
bool isLocked(); // non-blocking, but does do a lock/unlock so not free
bool isSelfLocked(); //return true if locked in a same thread
U32 lockingThread() const; //get ID of locking thread
@@ -174,6 +175,8 @@ protected:
#endif
};
+//============================================================================
+
// Actually a condition/mutex pair (since each condition needs to be associated with a mutex).
class LL_COMMON_API LLCondition : public LLMutex
{
@@ -189,6 +192,8 @@ protected:
apr_thread_cond_t *mAPRCondp;
};
+//============================================================================
+
class LLMutexLock
{
public:
@@ -210,6 +215,43 @@ private:
//============================================================================
+// Scoped locking class similar in function to LLMutexLock but uses
+// the trylock() method to conditionally acquire lock without
+// blocking. Caller resolves the resulting condition by calling
+// the isLocked() method and either punts or continues as indicated.
+//
+// Mostly of interest to callers needing to avoid stalls who can
+// guarantee another attempt at a later time.
+
+class LLMutexTrylock
+{
+public:
+ LLMutexTrylock(LLMutex* mutex)
+ : mMutex(mutex),
+ mLocked(false)
+ {
+ if (mMutex)
+ mLocked = mMutex->trylock();
+ }
+
+ ~LLMutexTrylock()
+ {
+ if (mMutex && mLocked)
+ mMutex->unlock();
+ }
+
+ bool isLocked() const
+ {
+ return mLocked;
+ }
+
+private:
+ LLMutex* mMutex;
+ bool mLocked;
+};
+
+//============================================================================
+
void LLThread::lockData()
{
mDataLock->lock();
@@ -242,49 +284,39 @@ public:
LLThreadSafeRefCount(const LLThreadSafeRefCount&);
LLThreadSafeRefCount& operator=(const LLThreadSafeRefCount& ref)
{
- if (sMutex)
- {
- sMutex->lock();
- }
mRef = 0;
- if (sMutex)
- {
- sMutex->unlock();
- }
return *this;
}
-
-
void ref()
{
- if (sMutex) sMutex->lock();
mRef++;
- if (sMutex) sMutex->unlock();
}
- S32 unref()
+ void unref()
{
llassert(mRef >= 1);
- if (sMutex) sMutex->lock();
- S32 res = --mRef;
- if (sMutex) sMutex->unlock();
- if (0 == res)
- {
- delete this;
- return 0;
+ if ((--mRef) == 0) // See note in llapr.h on atomic decrement operator return value.
+ {
+ // If we hit zero, the caller should be the only smart pointer owning the object and we can delete it.
+ // It is technically possible for a vanilla pointer to mess this up, or another thread to
+ // jump in, find this object, create another smart pointer and end up dangling, but if
+ // the code is that bad and not thread-safe, it's trouble already.
+ delete this;
}
- return res;
- }
+ }
+
S32 getNumRefs() const
{
- return mRef;
+ const S32 currentVal = mRef.CurrentValue();
+ return currentVal;
}
private:
- S32 mRef;
+ LLAtomic32< S32 > mRef;
};
+
/**
* intrusive pointer support for LLThreadSafeRefCount
* this allows you to use boost::intrusive_ptr with any LLThreadSafeRefCount-derived type
@@ -315,4 +347,6 @@ public:
//============================================================================
+extern LL_COMMON_API void assert_main_thread();
+
#endif // LL_LLTHREAD_H
diff --git a/indra/llcommon/lltimer.h b/indra/llcommon/lltimer.h
index 513de0605d..e73741217c 100755
--- a/indra/llcommon/lltimer.h
+++ b/indra/llcommon/lltimer.h
@@ -146,6 +146,13 @@ static inline time_t time_max()
}
}
+// These are really statics but they've been global for awhile
+// and they're material to other timing classes. If you are
+// not implementing a timer class, do not use these directly.
+extern LL_COMMON_API F64 gClockFrequency;
+extern LL_COMMON_API F64 gClockFrequencyInv;
+extern LL_COMMON_API F64 gClocksToMicroseconds;
+
// Correction factor used by time_corrected() above.
extern LL_COMMON_API S32 gUTCOffset;
diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h
deleted file mode 100644
index 6a5ff314e4..0000000000
--- a/indra/llcommon/llversionviewer.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * @file llversionviewer.h
- * @brief
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * 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.
- *
- * 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.
- *
- * 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
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLVERSIONVIEWER_H
-#define LL_LLVERSIONVIEWER_H
-
-const S32 LL_VERSION_MAJOR = 3;
-const S32 LL_VERSION_MINOR = 4;
-const S32 LL_VERSION_PATCH = 6;
-const S32 LL_VERSION_BUILD = 0;
-
-const char * const LL_CHANNEL = "Second Life Developer";
-
-#if LL_DARWIN
-const char * const LL_VERSION_BUNDLE_ID = "com.secondlife.indra.viewer";
-#endif
-
-#endif
diff --git a/indra/llcommon/tests/lldeadmantimer_test.cpp b/indra/llcommon/tests/lldeadmantimer_test.cpp
new file mode 100644
index 0000000000..7fd2dde6e0
--- /dev/null
+++ b/indra/llcommon/tests/lldeadmantimer_test.cpp
@@ -0,0 +1,628 @@
+/**
+ * @file lldeadmantimer_test.cpp
+ * @brief Tests for the LLDeadmanTimer class.
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2013, 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.
+ *
+ * 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.
+ *
+ * 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
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "../lldeadmantimer.h"
+#include "../llsd.h"
+#include "../lltimer.h"
+
+#include "../test/lltut.h"
+
+// Convert between floating point time deltas and U64 time deltas.
+// Reflects an implementation detail inside lldeadmantimer.cpp
+
+static LLDeadmanTimer::time_type float_time_to_u64(F64 delta)
+{
+ return LLDeadmanTimer::time_type(delta * gClockFrequency);
+}
+
+static F64 u64_time_to_float(LLDeadmanTimer::time_type delta)
+{
+ return delta * gClockFrequencyInv;
+}
+
+
+namespace tut
+{
+
+struct deadmantimer_test
+{
+ deadmantimer_test()
+ {
+ // LLTimer internals updating
+ update_clock_frequencies();
+ }
+};
+
+typedef test_group<deadmantimer_test> deadmantimer_group_t;
+typedef deadmantimer_group_t::object deadmantimer_object_t;
+tut::deadmantimer_group_t deadmantimer_instance("LLDeadmanTimer");
+
+// Basic construction test and isExpired() call
+template<> template<>
+void deadmantimer_object_t::test<1>()
+{
+ {
+ // Without cpu metrics
+ F64 started(42.0), stopped(97.0);
+ U64 count(U64L(8));
+ LLDeadmanTimer timer(10.0, false);
+
+ ensure_equals("WOCM isExpired() returns false after ctor()", timer.isExpired(0, started, stopped, count), false);
+ ensure_approximately_equals("WOCM t1 - isExpired() does not modify started", started, F64(42.0), 2);
+ ensure_approximately_equals("WOCM t1 - isExpired() does not modify stopped", stopped, F64(97.0), 2);
+ ensure_equals("WOCM t1 - isExpired() does not modify count", count, U64L(8));
+ }
+
+ {
+ // With cpu metrics
+ F64 started(42.0), stopped(97.0);
+ U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000);
+ LLDeadmanTimer timer(10.0, true);
+
+ ensure_equals("WCM isExpired() returns false after ctor()", timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), false);
+ ensure_approximately_equals("WCM t1 - isExpired() does not modify started", started, F64(42.0), 2);
+ ensure_approximately_equals("WCM t1 - isExpired() does not modify stopped", stopped, F64(97.0), 2);
+ ensure_equals("WCM t1 - isExpired() does not modify count", count, U64L(8));
+ ensure_equals("WCM t1 - isExpired() does not modify user_cpu", user_cpu, U64L(29000));
+ ensure_equals("WCM t1 - isExpired() does not modify sys_cpu", sys_cpu, U64L(57000));
+ }
+}
+
+
+// Construct with zero horizon - not useful generally but will be useful in testing
+template<> template<>
+void deadmantimer_object_t::test<2>()
+{
+ {
+ // Without cpu metrics
+ F64 started(42.0), stopped(97.0);
+ U64 count(U64L(8));
+ LLDeadmanTimer timer(0.0, false); // Zero is pre-expired
+
+ ensure_equals("WOCM isExpired() still returns false with 0.0 time ctor()",
+ timer.isExpired(0, started, stopped, count), false);
+ }
+
+ {
+ // With cpu metrics
+ F64 started(42.0), stopped(97.0);
+ U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000);
+ LLDeadmanTimer timer(0.0, true); // Zero is pre-expired
+
+ ensure_equals("WCM isExpired() still returns false with 0.0 time ctor()",
+ timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), false);
+ }
+}
+
+
+// "pre-expired" timer - starting a timer with a 0.0 horizon will result in
+// expiration on first test.
+template<> template<>
+void deadmantimer_object_t::test<3>()
+{
+ {
+ // Without cpu metrics
+ F64 started(42.0), stopped(97.0);
+ U64 count(U64L(8));
+ LLDeadmanTimer timer(0.0, false);
+
+ timer.start(0);
+ ensure_equals("WOCM isExpired() returns true with 0.0 horizon time",
+ timer.isExpired(0, started, stopped, count), true);
+ ensure_approximately_equals("WOCM expired timer with no bell ringing has stopped == started", started, stopped, 8);
+ }
+ {
+ // With cpu metrics
+ F64 started(42.0), stopped(97.0);
+ U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000);
+ LLDeadmanTimer timer(0.0, true);
+
+ timer.start(0);
+ ensure_equals("WCM isExpired() returns true with 0.0 horizon time",
+ timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), true);
+ ensure_approximately_equals("WCM expired timer with no bell ringing has stopped == started", started, stopped, 8);
+ }
+}
+
+
+// "pre-expired" timer - bell rings are ignored as we're already expired.
+template<> template<>
+void deadmantimer_object_t::test<4>()
+{
+ {
+ // Without cpu metrics
+ F64 started(42.0), stopped(97.0);
+ U64 count(U64L(8));
+ LLDeadmanTimer timer(0.0, false);
+
+ timer.start(0);
+ timer.ringBell(LLDeadmanTimer::getNow() + float_time_to_u64(1000.0), 1);
+ ensure_equals("WOCM isExpired() returns true with 0.0 horizon time after bell ring",
+ timer.isExpired(0, started, stopped, count), true);
+ ensure_approximately_equals("WOCM ringBell has no impact on expired timer leaving stopped == started", started, stopped, 8);
+ }
+ {
+ // With cpu metrics
+ F64 started(42.0), stopped(97.0);
+ U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000);
+ LLDeadmanTimer timer(0.0, true);
+
+ timer.start(0);
+ timer.ringBell(LLDeadmanTimer::getNow() + float_time_to_u64(1000.0), 1);
+ ensure_equals("WCM isExpired() returns true with 0.0 horizon time after bell ring",
+ timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), true);
+ ensure_approximately_equals("WCM ringBell has no impact on expired timer leaving stopped == started", started, stopped, 8);
+ }
+}
+
+
+// start(0) test - unexpired timer reports unexpired
+template<> template<>
+void deadmantimer_object_t::test<5>()
+{
+ {
+ // Without cpu metrics
+ F64 started(42.0), stopped(97.0);
+ U64 count(U64L(8));
+ LLDeadmanTimer timer(10.0, false);
+
+ timer.start(0);
+ ensure_equals("WOCM isExpired() returns false after starting with 10.0 horizon time",
+ timer.isExpired(0, started, stopped, count), false);
+ ensure_approximately_equals("WOCM t5 - isExpired() does not modify started", started, F64(42.0), 2);
+ ensure_approximately_equals("WOCM t5 - isExpired() does not modify stopped", stopped, F64(97.0), 2);
+ ensure_equals("WOCM t5 - isExpired() does not modify count", count, U64L(8));
+ }
+ {
+ // With cpu metrics
+ F64 started(42.0), stopped(97.0);
+ U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000);
+ LLDeadmanTimer timer(10.0, true);
+
+ timer.start(0);
+ ensure_equals("WCM isExpired() returns false after starting with 10.0 horizon time",
+ timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), false);
+ ensure_approximately_equals("WCM t5 - isExpired() does not modify started", started, F64(42.0), 2);
+ ensure_approximately_equals("WCM t5 - isExpired() does not modify stopped", stopped, F64(97.0), 2);
+ ensure_equals("WCM t5 - isExpired() does not modify count", count, U64L(8));
+ ensure_equals("WCM t5 - isExpired() does not modify user_cpu", user_cpu, U64L(29000));
+ ensure_equals("WCM t5 - isExpired() does not modify sys_cpu", sys_cpu, U64L(57000));
+ }
+}
+
+
+// start() test - start in the past but not beyond 1 horizon
+template<> template<>
+void deadmantimer_object_t::test<6>()
+{
+ {
+ // Without cpu metrics
+ F64 started(42.0), stopped(97.0);
+ U64 count(U64L(8));
+ LLDeadmanTimer timer(10.0, false);
+
+ // Would like to do subtraction on current time but can't because
+ // the implementation on Windows is zero-based. We wrap around
+ // the backside resulting in a large U64 number.
+
+ LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow());
+ LLDeadmanTimer::time_type now(the_past + float_time_to_u64(5.0));
+ timer.start(the_past);
+ ensure_equals("WOCM t6 - isExpired() returns false with 10.0 horizon time starting 5.0 in past",
+ timer.isExpired(now, started, stopped, count), false);
+ ensure_approximately_equals("WOCM t6 - isExpired() does not modify started", started, F64(42.0), 2);
+ ensure_approximately_equals("WOCM t6 - isExpired() does not modify stopped", stopped, F64(97.0), 2);
+ ensure_equals("WOCM t6 - isExpired() does not modify count", count, U64L(8));
+ }
+ {
+ // With cpu metrics
+ F64 started(42.0), stopped(97.0);
+ U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000);
+ LLDeadmanTimer timer(10.0, true);
+
+ // Would like to do subtraction on current time but can't because
+ // the implementation on Windows is zero-based. We wrap around
+ // the backside resulting in a large U64 number.
+
+ LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow());
+ LLDeadmanTimer::time_type now(the_past + float_time_to_u64(5.0));
+ timer.start(the_past);
+ ensure_equals("WCM t6 - isExpired() returns false with 10.0 horizon time starting 5.0 in past",
+ timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false);
+ ensure_approximately_equals("WCM t6 - isExpired() does not modify started", started, F64(42.0), 2);
+ ensure_approximately_equals("WCM t6 - isExpired() does not modify stopped", stopped, F64(97.0), 2);
+ ensure_equals("t6 - isExpired() does not modify count", count, U64L(8));
+ ensure_equals("WCM t6 - isExpired() does not modify user_cpu", user_cpu, U64L(29000));
+ ensure_equals("WCM t6 - isExpired() does not modify sys_cpu", sys_cpu, U64L(57000));
+ }
+}
+
+
+// start() test - start in the past but well beyond 1 horizon
+template<> template<>
+void deadmantimer_object_t::test<7>()
+{
+ {
+ // Without cpu metrics
+ F64 started(42.0), stopped(97.0);
+ U64 count(U64L(8));
+ LLDeadmanTimer timer(10.0, false);
+
+ // Would like to do subtraction on current time but can't because
+ // the implementation on Windows is zero-based. We wrap around
+ // the backside resulting in a large U64 number.
+
+ LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow());
+ LLDeadmanTimer::time_type now(the_past + float_time_to_u64(20.0));
+ timer.start(the_past);
+ ensure_equals("WOCM t7 - isExpired() returns true with 10.0 horizon time starting 20.0 in past",
+ timer.isExpired(now,started, stopped, count), true);
+ ensure_approximately_equals("WOCM t7 - starting before horizon still gives equal started / stopped", started, stopped, 8);
+ }
+ {
+ // With cpu metrics
+ F64 started(42.0), stopped(97.0);
+ U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000);
+ LLDeadmanTimer timer(10.0, true);
+
+ // Would like to do subtraction on current time but can't because
+ // the implementation on Windows is zero-based. We wrap around
+ // the backside resulting in a large U64 number.
+
+ LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow());
+ LLDeadmanTimer::time_type now(the_past + float_time_to_u64(20.0));
+ timer.start(the_past);
+ ensure_equals("WCM t7 - isExpired() returns true with 10.0 horizon time starting 20.0 in past",
+ timer.isExpired(now,started, stopped, count, user_cpu, sys_cpu), true);
+ ensure_approximately_equals("WOCM t7 - starting before horizon still gives equal started / stopped", started, stopped, 8);
+ }
+}
+
+
+// isExpired() test - results are read-once. Probes after first true are false.
+template<> template<>
+void deadmantimer_object_t::test<8>()
+{
+ {
+ // Without cpu metrics
+ F64 started(42.0), stopped(97.0);
+ U64 count(U64L(8));
+ LLDeadmanTimer timer(10.0, false);
+
+ // Would like to do subtraction on current time but can't because
+ // the implementation on Windows is zero-based. We wrap around
+ // the backside resulting in a large U64 number.
+
+ LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow());
+ LLDeadmanTimer::time_type now(the_past + float_time_to_u64(20.0));
+ timer.start(the_past);
+ ensure_equals("WOCM t8 - isExpired() returns true with 10.0 horizon time starting 20.0 in past",
+ timer.isExpired(now, started, stopped, count), true);
+
+ started = 42.0;
+ stopped = 97.0;
+ count = U64L(8);
+ ensure_equals("WOCM t8 - second isExpired() returns false after true",
+ timer.isExpired(now, started, stopped, count), false);
+ ensure_approximately_equals("WOCM t8 - 2nd isExpired() does not modify started", started, F64(42.0), 2);
+ ensure_approximately_equals("WOCM t8 - 2nd isExpired() does not modify stopped", stopped, F64(97.0), 2);
+ ensure_equals("WOCM t8 - 2nd isExpired() does not modify count", count, U64L(8));
+ }
+ {
+ // With cpu metrics
+ F64 started(42.0), stopped(97.0);
+ U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000);
+ LLDeadmanTimer timer(10.0, true);
+
+ // Would like to do subtraction on current time but can't because
+ // the implementation on Windows is zero-based. We wrap around
+ // the backside resulting in a large U64 number.
+
+ LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow());
+ LLDeadmanTimer::time_type now(the_past + float_time_to_u64(20.0));
+ timer.start(the_past);
+ ensure_equals("WCM t8 - isExpired() returns true with 10.0 horizon time starting 20.0 in past",
+ timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), true);
+
+ started = 42.0;
+ stopped = 97.0;
+ count = U64L(8);
+ user_cpu = 29000;
+ sys_cpu = 57000;
+ ensure_equals("WCM t8 - second isExpired() returns false after true",
+ timer.isExpired(now, started, stopped, count), false);
+ ensure_approximately_equals("WCM t8 - 2nd isExpired() does not modify started", started, F64(42.0), 2);
+ ensure_approximately_equals("WCM t8 - 2nd isExpired() does not modify stopped", stopped, F64(97.0), 2);
+ ensure_equals("WCM t8 - 2nd isExpired() does not modify count", count, U64L(8));
+ ensure_equals("WCM t8 - 2nd isExpired() does not modify user_cpu", user_cpu, U64L(29000));
+ ensure_equals("WCM t8 - 2nd isExpired() does not modify sys_cpu", sys_cpu, U64L(57000));
+ }
+}
+
+
+// ringBell() test - see that we can keep a timer from expiring
+template<> template<>
+void deadmantimer_object_t::test<9>()
+{
+ {
+ // Without cpu metrics
+ F64 started(42.0), stopped(97.0);
+ U64 count(U64L(8));
+ LLDeadmanTimer timer(5.0, false);
+
+ LLDeadmanTimer::time_type now(LLDeadmanTimer::getNow());
+ F64 real_start(u64_time_to_float(now));
+ timer.start(0);
+
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ ensure_equals("WOCM t9 - 5.0 horizon timer has not timed out after 10 1-second bell rings",
+ timer.isExpired(now, started, stopped, count), false);
+ F64 last_good_ring(u64_time_to_float(now));
+
+ // Jump forward and expire
+ now += float_time_to_u64(10.0);
+ ensure_equals("WOCM t9 - 5.0 horizon timer expires on 10-second jump",
+ timer.isExpired(now, started, stopped, count), true);
+ ensure_approximately_equals("WOCM t9 - started matches start() time", started, real_start, 4);
+ ensure_approximately_equals("WOCM t9 - stopped matches last ringBell() time", stopped, last_good_ring, 4);
+ ensure_equals("WOCM t9 - 10 good ringBell()s", count, U64L(10));
+ ensure_equals("WOCM t9 - single read only", timer.isExpired(now, started, stopped, count), false);
+ }
+ {
+ // With cpu metrics
+ F64 started(42.0), stopped(97.0);
+ U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000);
+ LLDeadmanTimer timer(5.0, true);
+
+ LLDeadmanTimer::time_type now(LLDeadmanTimer::getNow());
+ F64 real_start(u64_time_to_float(now));
+ timer.start(0);
+
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ ensure_equals("WCM t9 - 5.0 horizon timer has not timed out after 10 1-second bell rings",
+ timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false);
+ F64 last_good_ring(u64_time_to_float(now));
+
+ // Jump forward and expire
+ now += float_time_to_u64(10.0);
+ ensure_equals("WCM t9 - 5.0 horizon timer expires on 10-second jump",
+ timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), true);
+ ensure_approximately_equals("WCM t9 - started matches start() time", started, real_start, 4);
+ ensure_approximately_equals("WCM t9 - stopped matches last ringBell() time", stopped, last_good_ring, 4);
+ ensure_equals("WCM t9 - 10 good ringBell()s", count, U64L(10));
+ ensure_equals("WCM t9 - single read only", timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false);
+ }
+}
+
+
+// restart after expiration test - verify that restarts behave well
+template<> template<>
+void deadmantimer_object_t::test<10>()
+{
+ {
+ // Without cpu metrics
+ F64 started(42.0), stopped(97.0);
+ U64 count(U64L(8));
+ LLDeadmanTimer timer(5.0, false);
+
+ LLDeadmanTimer::time_type now(LLDeadmanTimer::getNow());
+ F64 real_start(u64_time_to_float(now));
+ timer.start(0);
+
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ ensure_equals("WOCM t10 - 5.0 horizon timer has not timed out after 10 1-second bell rings",
+ timer.isExpired(now, started, stopped, count), false);
+ F64 last_good_ring(u64_time_to_float(now));
+
+ // Jump forward and expire
+ now += float_time_to_u64(10.0);
+ ensure_equals("WOCM t10 - 5.0 horizon timer expires on 10-second jump",
+ timer.isExpired(now, started, stopped, count), true);
+ ensure_approximately_equals("WOCM t10 - started matches start() time", started, real_start, 4);
+ ensure_approximately_equals("WOCM t10 - stopped matches last ringBell() time", stopped, last_good_ring, 4);
+ ensure_equals("WOCM t10 - 10 good ringBell()s", count, U64L(10));
+ ensure_equals("WOCM t10 - single read only", timer.isExpired(now, started, stopped, count), false);
+
+ // Jump forward and restart
+ now += float_time_to_u64(1.0);
+ real_start = u64_time_to_float(now);
+ timer.start(now);
+
+ // Run a modified bell ring sequence
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ ensure_equals("WOCM t10 - 5.0 horizon timer has not timed out after 8 1-second bell rings",
+ timer.isExpired(now, started, stopped, count), false);
+ last_good_ring = u64_time_to_float(now);
+
+ // Jump forward and expire
+ now += float_time_to_u64(10.0);
+ ensure_equals("WOCM t10 - 5.0 horizon timer expires on 8-second jump",
+ timer.isExpired(now, started, stopped, count), true);
+ ensure_approximately_equals("WOCM t10 - 2nd started matches start() time", started, real_start, 4);
+ ensure_approximately_equals("WOCM t10 - 2nd stopped matches last ringBell() time", stopped, last_good_ring, 4);
+ ensure_equals("WOCM t10 - 8 good ringBell()s", count, U64L(8));
+ ensure_equals("WOCM t10 - single read only - 2nd start",
+ timer.isExpired(now, started, stopped, count), false);
+ }
+ {
+ // With cpu metrics
+ F64 started(42.0), stopped(97.0);
+ U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000);
+
+ LLDeadmanTimer timer(5.0, true);
+
+ LLDeadmanTimer::time_type now(LLDeadmanTimer::getNow());
+ F64 real_start(u64_time_to_float(now));
+ timer.start(0);
+
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ ensure_equals("WCM t10 - 5.0 horizon timer has not timed out after 10 1-second bell rings",
+ timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false);
+ F64 last_good_ring(u64_time_to_float(now));
+
+ // Jump forward and expire
+ now += float_time_to_u64(10.0);
+ ensure_equals("WCM t10 - 5.0 horizon timer expires on 10-second jump",
+ timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), true);
+ ensure_approximately_equals("WCM t10 - started matches start() time", started, real_start, 4);
+ ensure_approximately_equals("WCM t10 - stopped matches last ringBell() time", stopped, last_good_ring, 4);
+ ensure_equals("WCM t10 - 10 good ringBell()s", count, U64L(10));
+ ensure_equals("WCM t10 - single read only", timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false);
+
+ // Jump forward and restart
+ now += float_time_to_u64(1.0);
+ real_start = u64_time_to_float(now);
+ timer.start(now);
+
+ // Run a modified bell ring sequence
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ now += float_time_to_u64(1.0);
+ timer.ringBell(now, 1);
+ ensure_equals("WCM t10 - 5.0 horizon timer has not timed out after 8 1-second bell rings",
+ timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false);
+ last_good_ring = u64_time_to_float(now);
+
+ // Jump forward and expire
+ now += float_time_to_u64(10.0);
+ ensure_equals("WCM t10 - 5.0 horizon timer expires on 8-second jump",
+ timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), true);
+ ensure_approximately_equals("WCM t10 - 2nd started matches start() time", started, real_start, 4);
+ ensure_approximately_equals("WCM t10 - 2nd stopped matches last ringBell() time", stopped, last_good_ring, 4);
+ ensure_equals("WCM t10 - 8 good ringBell()s", count, U64L(8));
+ ensure_equals("WCM t10 - single read only - 2nd start",
+ timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false);
+ }
+}
+
+
+
+} // end namespace tut
diff --git a/indra/llcommon/tests/llprocinfo_test.cpp b/indra/llcommon/tests/llprocinfo_test.cpp
new file mode 100644
index 0000000000..12d5a695ee
--- /dev/null
+++ b/indra/llcommon/tests/llprocinfo_test.cpp
@@ -0,0 +1,91 @@
+/**
+ * @file llprocinfo_test.cpp
+ * @brief Tests for the LLProcInfo class.
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2013, 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.
+ *
+ * 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.
+ *
+ * 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
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "../llprocinfo.h"
+
+#include "../test/lltut.h"
+#include "../lltimer.h"
+
+
+static const LLProcInfo::time_type bad_user(289375U), bad_system(275U);
+
+
+namespace tut
+{
+
+struct procinfo_test
+{
+ procinfo_test()
+ {
+ }
+};
+
+typedef test_group<procinfo_test> procinfo_group_t;
+typedef procinfo_group_t::object procinfo_object_t;
+tut::procinfo_group_t procinfo_instance("LLProcInfo");
+
+
+// Basic invocation works
+template<> template<>
+void procinfo_object_t::test<1>()
+{
+ LLProcInfo::time_type user(bad_user), system(bad_system);
+
+ set_test_name("getCPUUsage() basic function");
+
+ LLProcInfo::getCPUUsage(user, system);
+
+ ensure_not_equals("getCPUUsage() writes to its user argument", user, bad_user);
+ ensure_not_equals("getCPUUsage() writes to its system argument", system, bad_system);
+}
+
+
+// Time increases
+template<> template<>
+void procinfo_object_t::test<2>()
+{
+ LLProcInfo::time_type user(bad_user), system(bad_system);
+ LLProcInfo::time_type user2(bad_user), system2(bad_system);
+
+ set_test_name("getCPUUsage() increases over time");
+
+ LLProcInfo::getCPUUsage(user, system);
+
+ for (int i(0); i < 100000; ++i)
+ {
+ ms_sleep(0);
+ }
+
+ LLProcInfo::getCPUUsage(user2, system2);
+
+ ensure_equals("getCPUUsage() user value doesn't decrease over time", user2 >= user, true);
+ ensure_equals("getCPUUsage() system value doesn't decrease over time", system2 >= system, true);
+}
+
+
+} // end namespace tut