diff options
| author | Monty Brandenberg <monty@lindenlab.com> | 2013-04-09 23:44:59 +0000 | 
|---|---|---|
| committer | Monty Brandenberg <monty@lindenlab.com> | 2013-04-09 23:44:59 +0000 | 
| commit | 188221a90c7a054d390ddaa534d391f6370ac6bc (patch) | |
| tree | 8a77f8077221f18a46e29296d6dbd1e9a78252cb | |
| parent | 8a330ee2eb1008951f5e5159057fa5736dd805b4 (diff) | |
SH-4088 Deadman timer switch started in llcommon.  Unit test started.
Will be used for mesh, inventory, etc., operation markers.
| -rw-r--r-- | indra/llcommon/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | indra/llcommon/lldeadmantimer.cpp | 141 | ||||
| -rw-r--r-- | indra/llcommon/lldeadmantimer.h | 171 | ||||
| -rw-r--r-- | indra/llcommon/lltimer.h | 7 | ||||
| -rw-r--r-- | indra/llcommon/tests/lldeadmantimer_test.cpp | 63 | 
5 files changed, 385 insertions, 0 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 5cce8ff2c4..7ed4137065 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -42,6 +42,7 @@ set(llcommon_SOURCE_FILES      llcriticaldamp.cpp      llcursortypes.cpp      lldate.cpp +    lldeadmantimer.cpp      lldependencies.cpp      lldictionary.cpp      llerror.cpp @@ -144,6 +145,7 @@ set(llcommon_HEADER_FILES      lldarray.h      lldarrayptr.h      lldate.h +    lldeadmantimer.h      lldefs.h      lldependencies.h      lldeleteutils.h @@ -322,6 +324,7 @@ 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}") diff --git a/indra/llcommon/lldeadmantimer.cpp b/indra/llcommon/lldeadmantimer.cpp new file mode 100644 index 0000000000..2f48d13c2d --- /dev/null +++ b/indra/llcommon/lldeadmantimer.cpp @@ -0,0 +1,141 @@ +/**  +* @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" + + +LLDeadmanTimer::LLDeadmanTimer(F64 horizon) +	: mHorizon(U64(horizon * 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)) +{} + + +void LLDeadmanTimer::start(U64 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); +} + + +void LLDeadmanTimer::stop(U64 now) +{ +	if (! mActive) +	{ +		return; +	} + +	if (! now) +	{ +		now = LLTimer::getCurrentClockCount(); +	} +	mStopped = now; +	mActive = false; +	mDone = true; +} + + +bool LLDeadmanTimer::isExpired(F64 & started, F64 & stopped, U64 & count, U64 now) +{ +	if (! mActive) +	{ +		return false; +	} +	 +	if (! mDone) +	{ +		if (! now) +		{ +			now = LLTimer::getCurrentClockCount(); +		} + +		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(U64 now) +{ +	if (! mActive) +	{ +		return; +	} +	 +	if (! now) +	{ +		now = LLTimer::getCurrentClockCount(); +	} + +	if (now > mExpires) +	{ +		mActive = false; +		mDone = true; +	} +	else +	{ +		mStopped = now; +		mExpires = now + mHorizon; +		++mCount; +	} +	 +	return; +} + diff --git a/indra/llcommon/lldeadmantimer.h b/indra/llcommon/lldeadmantimer.h new file mode 100644 index 0000000000..84023723ab --- /dev/null +++ b/indra/llcommon/lldeadmantimer.h @@ -0,0 +1,171 @@ +/**  +* @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" + + +/// @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: +	/// 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. +	/// +	LLDeadmanTimer(F64 horizon); + +	~LLDeadmanTimer()  +		{} +	 +private: +	LLDeadmanTimer(const LLDeadmanTimer &);				// Not defined +	void operator=(const LLDeadmanTimer &);				// Not defined + +public: +	/// 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(U64 now = U64L(0)); + + +	/// 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(U64 now = U64L(0)); + + +	/// 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. +	/// 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. +	/// +	void ringBell(U64 now = U64L(0)); +	 + +	/// Checks on the status of the timer 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. +	/// This count is returned via the @see isExpired() method. +	/// +	/// @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 now		Current time as returned by @see +	///					LLTimer::getCurrentClockCount().  If zero, +	///					method will lookup current time. +	/// +	/// @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(F64 & started, F64 & stopped, U64 & count, U64 now = U64L(0)); + +protected: +	U64			mHorizon; +	bool		mActive; +	bool		mDone; +	U64			mStarted; +	U64			mExpires; +	U64			mStopped; +	U64			mCount; +}; +	 + +#endif	// LL_DEADMANTIMER_H diff --git a/indra/llcommon/lltimer.h b/indra/llcommon/lltimer.h index 513de0605d..e73741217c 100644 --- 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/tests/lldeadmantimer_test.cpp b/indra/llcommon/tests/lldeadmantimer_test.cpp new file mode 100644 index 0000000000..52a27b9c0a --- /dev/null +++ b/indra/llcommon/tests/lldeadmantimer_test.cpp @@ -0,0 +1,63 @@ +/**  + * @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 "../test/lltut.h" + +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"); + +template<> template<> +void deadmantimer_object_t::test<1>() +{ +	F64 started(42.0), stopped(97.0); +	U64 count(U64L(8)); +	LLDeadmanTimer timer(1.0); + +	ensure_equals("isExpired() returns false after ctor()", timer.isExpired(started, stopped, count), false); +	ensure_approximately_equals("isExpired() does not modify started", started, F64(42.0), 2); +	ensure_approximately_equals("isExpired() does not modify stopped", stopped, F64(97.0), 2); +	ensure_equals("isExpired() does not modified count", count, U64L(8)); +} + +} // end namespace tut  | 
