summaryrefslogtreecommitdiff
path: root/indra/llcommon/lldeadmantimer.h
blob: 8643b8cad8babae565995e71fb986193838f7fe8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/** 
* @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:
	/// 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.
	///
	LLDeadmanTimer(F64 horizon);

	~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 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 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.
	///
	/// @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);

protected:
	time_type	mHorizon;
	bool		mActive;
	bool		mDone;
	time_type	mStarted;
	time_type	mExpires;
	time_type	mStopped;
	time_type	mCount;
};
	

#endif	// LL_DEADMANTIMER_H