Skip to content
Snippets Groups Projects
Commit 188221a9 authored by Monty Brandenberg's avatar Monty Brandenberg
Browse files

SH-4088 Deadman timer switch started in llcommon. Unit test started.

Will be used for mesh, inventory, etc., operation markers.
parent 8a330ee2
No related branches found
No related tags found
No related merge requests found
......@@ -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}")
......
/**
* @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;
}
/**
* @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
......@@ -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;
......
/**
* @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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment