summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2024-05-02 21:13:28 -0400
committerNat Goodspeed <nat@lindenlab.com>2024-05-02 21:13:28 -0400
commitc231c97eeefc484b74198ba86251054b7dc0e6bb (patch)
treeabf1a5e08311cf3bb816c49778aa10a2ab02fc7e /indra
parent9bf5fcd225ada9dcd63fc5710f58013e7839df09 (diff)
WIP: In llcallbacklist.h, add singleton LLLater for time delays.
The big idea is to reduce the number of per-tick callbacks asking, "Is it time yet? Is it time yet?" We do that for LLEventTimer and LLEventTimeout. LLLater presents doAtTime(LLDate), with doAfterInterval() and doPeriodically() methods implemented using doAtTime(). All return handles. The free functions doAfterInterval() and doPeriodically() now forward to the corresponding LLLater methods. LLLater also presents isRunning(handle) and cancel(handle). LLLater borrows the tactic of LLEventTimer: while there's at least one running timer, it registers an LLCallbackList tick() callback to service ready timers. But instead of looping over all of them asking, "Are you ready?" it keeps them in a priority queue ordered by desired timestamp, and only touches those whose timestamp has been reached. Also, it honors a maximum time slice: once the ready timers have run for longer than the limit, it defers processing other ready timers to the next tick() call. The intent is to consume fewer cycles per tick() call, both by the management machinery and the timers themselves. Revamp LLCallbackList to accept C++ callables in addition to (classic C function pointer, void*) pairs. Make addFunction() return a handle (different than LLLater handles) that can be passed to a new deleteFunction() overload, since std::function instances can't be compared for equality. In fact, implement LLCallbackList using boost::signals2::signal, which provides almost exactly what we want. LLCallbackList continues to accept (function pointer, void*) pairs, but now we store a lambda that calls the function pointer with that void*. It takes less horsing around to create a C++ callable from a (function pointer, void*) pair than the other way around. For containsFunction() and deleteFunction(), such pairs are the keys for a lookup table whose values are handles. Instead of having a static global LLCallbackList gIdleCallbacks, make LLCallbackList an LLSingleton to guarantee initialization. For backwards compatibility, gIdleCallbacks is now a macro for LLCallbackList::instance(). Move doOnIdleOneTime() and doOnIdleRepeating() functions to LLCallbackList methods, but for backwards compatibility continue providing free functions. Reimplement LLEventTimer using LLLater::doPeriodically(). One implication is that LLEventTimer need no longer be derived from LLInstanceTracker, which we used to iterate over all instances every tick. Give it start() and stop() methods, since some subclasses (e.g. LLFlashTimer) used to call its member LLTimer's start() and stop(). Remove updateClass(): LLCallbackList::callFunctions() now takes care of that. Remove LLToastLifeTimer::start() and stop(), since LLEventTimer now provides those. Remove getRemainingTimeF32(), since LLLater does not (yet) provide that feature. While at it, make LLEventTimer::tick() return bool instead of BOOL, and change existing overrides. Make LLApp::stepFrame() call LLCallbackList::callFunctions() instead of LLEventTimer::updateClass(). We could have refactored LLEventTimer to use the mechanism now built into LLLater, but frankly the LLEventTimer API is rather clumsy. You MUST derive a subclass and override tick(), and you must instantiate your subclass on the heap because, when your tick() override returns false, LLEventTimer deletes its subclass instance. The LLLater API is simpler to use, and LLEventTimer is much simplified by using it. Merge lleventfilter.h's LLEventTimeoutBase into LLEventTimeout, and likewise merge LLEventThrottleBase into LLEventThrottle. The separation was for testability, but now that they're no longer based on LLTimer, it becomes harder to use dummy time for testing. Temporarily skip tests based on LLEventTimeoutBase and LLEventThrottleBase. Instead of listening for LLEventPump("mainloop") ticks and using LLTimer, LLEventTimeout now uses LLLater::doAfterInterval(). Instead of LLTimer and LLEventTimeout, LLEventThrottle likewise now uses LLLater::doAfterInterval(). Recast a couple local LLEventTimeout pre-lambda callable classes with lambdas. Dignify F64 with a new typedef LLDate::timestamp. LLDate heavily depends on that as its base time representation, but there are those who question use of floating-point for time. This is a step towards insulating us from any future change.
Diffstat (limited to 'indra')
-rw-r--r--indra/llcommon/llapp.cpp2
-rw-r--r--indra/llcommon/llcallbacklist.cpp324
-rw-r--r--indra/llcommon/llcallbacklist.h228
-rw-r--r--indra/llcommon/lldate.cpp12
-rw-r--r--indra/llcommon/lldate.h8
-rw-r--r--indra/llcommon/llerrorlegacy.h32
-rw-r--r--indra/llcommon/lleventfilter.cpp138
-rw-r--r--indra/llcommon/lleventfilter.h129
-rw-r--r--indra/llcommon/lleventtimer.cpp39
-rw-r--r--indra/llcommon/lleventtimer.h18
-rw-r--r--indra/llcommon/lllivefile.cpp2
-rw-r--r--indra/llcommon/tests/lleventfilter_test.cpp14
-rw-r--r--indra/llcommon/tests/llmainthreadtask_test.cpp4
-rw-r--r--indra/llui/llflashtimer.cpp14
-rw-r--r--indra/llui/llflashtimer.h2
-rw-r--r--indra/newview/llappearancemgr.cpp5
-rw-r--r--indra/newview/lldonotdisturbnotificationstorage.h2
-rw-r--r--indra/newview/llfloaterlinkreplace.h2
-rw-r--r--indra/newview/llfloaterpreference.cpp2
-rw-r--r--indra/newview/llfloaterregionrestarting.h2
-rw-r--r--indra/newview/llfloateruipreview.cpp2
-rw-r--r--indra/newview/llimview.h2
-rw-r--r--indra/newview/lllocalbitmaps.h2
-rw-r--r--indra/newview/lllocalgltfmaterials.h2
-rw-r--r--indra/newview/llmediadataclient.h10
-rw-r--r--indra/newview/llpanelpeople.cpp6
-rw-r--r--indra/newview/llsetkeybinddialog.cpp2
-rw-r--r--indra/newview/llspeakers.h2
-rw-r--r--indra/newview/lltoast.cpp29
-rw-r--r--indra/newview/lltoast.h10
-rw-r--r--indra/newview/llviewermessage.cpp2
-rw-r--r--indra/newview/llviewerparcelmediaautoplay.h2
32 files changed, 564 insertions, 486 deletions
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index 90d0c28eb1..5722f10f62 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -322,7 +322,7 @@ void LLApp::stepFrame()
{
LLFrameTimer::updateFrameTime();
LLFrameTimer::updateFrameCount();
- LLEventTimer::updateClass();
+ LLCallbackList::instance().callFunctions();
mRunner.run();
}
diff --git a/indra/llcommon/llcallbacklist.cpp b/indra/llcommon/llcallbacklist.cpp
index 9f23ce5317..7f7fdc7370 100644
--- a/indra/llcommon/llcallbacklist.cpp
+++ b/indra/llcommon/llcallbacklist.cpp
@@ -25,17 +25,14 @@
*/
#include "llcallbacklist.h"
-#include "lleventtimer.h"
-#include "llerrorlegacy.h"
-
-// Globals
-//
-LLCallbackList gIdleCallbacks;
//
// Member functions
//
+/*****************************************************************************
+* LLCallbackList
+*****************************************************************************/
LLCallbackList::LLCallbackList()
{
// nothing
@@ -45,186 +42,251 @@ LLCallbackList::~LLCallbackList()
{
}
-
-void LLCallbackList::addFunction( callback_t func, void *data)
+LLCallbackList::handle_t LLCallbackList::addFunction( callback_t func, void *data)
{
if (!func)
{
- return;
+ return {};
}
// only add one callback per func/data pair
//
if (containsFunction(func, data))
{
- return;
+ return {};
}
-
- callback_pair_t t(func, data);
- mCallbackList.push_back(t);
+
+ auto handle = addFunction([func, data]{ func(data); });
+ mLookup.emplace(callback_pair_t(func, data), handle);
+ return handle;
}
-bool LLCallbackList::containsFunction( callback_t func, void *data)
+LLCallbackList::handle_t LLCallbackList::addFunction( const callable_t& func )
{
- callback_pair_t t(func, data);
- callback_list_t::iterator iter = find(func,data);
- if (iter != mCallbackList.end())
- {
- return TRUE;
- }
- else
- {
- return FALSE;
- }
+ return mCallbackList.connect(func);
}
+bool LLCallbackList::containsFunction( callback_t func, void *data)
+{
+ return mLookup.find(callback_pair_t(func, data)) != mLookup.end();
+}
bool LLCallbackList::deleteFunction( callback_t func, void *data)
{
- callback_list_t::iterator iter = find(func,data);
- if (iter != mCallbackList.end())
+ auto found = mLookup.find(callback_pair_t(func, data));
+ if (found != mLookup.end())
{
- mCallbackList.erase(iter);
- return TRUE;
+ mLookup.erase(found);
+ deleteFunction(found->second);
+ return true;
}
else
{
- return FALSE;
+ return false;
}
}
-inline
-LLCallbackList::callback_list_t::iterator
-LLCallbackList::find(callback_t func, void *data)
+void LLCallbackList::deleteFunction( const handle_t& handle )
{
- callback_pair_t t(func, data);
- return std::find(mCallbackList.begin(), mCallbackList.end(), t);
+ handle.disconnect();
}
void LLCallbackList::deleteAllFunctions()
{
- mCallbackList.clear();
+ mCallbackList = {};
+ mLookup.clear();
}
-
void LLCallbackList::callFunctions()
{
- for (callback_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end(); )
- {
- callback_list_t::iterator curiter = iter++;
- curiter->first(curiter->second);
- }
+ mCallbackList();
}
-// Shim class to allow arbitrary boost::bind
-// expressions to be run as one-time idle callbacks.
-class OnIdleCallbackOneTime
+LLCallbackList::handle_t LLCallbackList::doOnIdleOneTime( const callable_t& func )
{
-public:
- OnIdleCallbackOneTime(nullary_func_t callable):
- mCallable(callable)
- {
- }
- static void onIdle(void *data)
- {
- gIdleCallbacks.deleteFunction(onIdle, data);
- OnIdleCallbackOneTime* self = reinterpret_cast<OnIdleCallbackOneTime*>(data);
- self->call();
- delete self;
- }
- void call()
- {
- mCallable();
- }
-private:
- nullary_func_t mCallable;
-};
+ // connect_extended() passes the connection to the callback
+ return mCallbackList.connect_extended(
+ [func](const handle_t& handle)
+ {
+ handle.disconnect();
+ func();
+ });
+}
-void doOnIdleOneTime(nullary_func_t callable)
+LLCallbackList::handle_t LLCallbackList::doOnIdleRepeating( const bool_func_t& func )
{
- OnIdleCallbackOneTime* cb_functor = new OnIdleCallbackOneTime(callable);
- gIdleCallbacks.addFunction(&OnIdleCallbackOneTime::onIdle,cb_functor);
+ return mCallbackList.connect_extended(
+ [func](const handle_t& handle)
+ {
+ if (func())
+ {
+ handle.disconnect();
+ }
+ });
}
-// Shim class to allow generic boost functions to be run as
-// recurring idle callbacks. Callable should return true when done,
-// false to continue getting called.
-class OnIdleCallbackRepeating
-{
-public:
- OnIdleCallbackRepeating(bool_func_t callable):
- mCallable(callable)
- {
- }
- // Will keep getting called until the callable returns true.
- static void onIdle(void *data)
- {
- OnIdleCallbackRepeating* self = reinterpret_cast<OnIdleCallbackRepeating*>(data);
- bool done = self->call();
- if (done)
- {
- gIdleCallbacks.deleteFunction(onIdle, data);
- delete self;
- }
- }
- bool call()
- {
- return mCallable();
- }
-private:
- bool_func_t mCallable;
-};
+/*****************************************************************************
+* LLLater
+*****************************************************************************/
+LLLater::LLLater() {}
-void doOnIdleRepeating(bool_func_t callable)
+// Call a given callable once at specified timestamp.
+LLLater::handle_t LLLater::doAtTime(nullary_func_t callable, LLDate::timestamp time)
{
- OnIdleCallbackRepeating* cb_functor = new OnIdleCallbackRepeating(callable);
- gIdleCallbacks.addFunction(&OnIdleCallbackRepeating::onIdle,cb_functor);
+ bool first{ mQueue.empty() };
+ // Pick token FIRST to store a self-reference in mQueue's managed node as
+ // well as in mHandles. Pre-increment to distinguish 0 from any live
+ // handle_t.
+ token_t token{ ++mToken };
+ auto handle{ mQueue.emplace(callable, time, token) };
+ mHandles.emplace(token, handle);
+ if (first)
+ {
+ // If this is our first entry, register for regular callbacks.
+ mLive = LLCallbackList::instance().doOnIdleRepeating([this]{ return tick(); });
+ }
+ return handle_t{ token };
}
-class NullaryFuncEventTimer: public LLEventTimer
+// Call a given callable once after specified interval.
+LLLater::handle_t LLLater::doAfterInterval(nullary_func_t callable, F32 seconds)
{
-public:
- NullaryFuncEventTimer(nullary_func_t callable, F32 seconds):
- LLEventTimer(seconds),
- mCallable(callable)
- {
- }
+ // Passing 0 is a slightly more expensive way of calling
+ // LLCallbackList::doOnIdleOneTime(). Are we sure the caller is correct?
+ // (If there's a valid use case, remove the llassert() and carry on.)
+ llassert(seconds > 0);
+ return doAtTime(callable, LLDate::now().secondsSinceEpoch() + seconds);
+}
-private:
- BOOL tick()
- {
- mCallable();
- return TRUE;
- }
+// For doPeriodically(), we need a struct rather than a lambda because a
+// struct, unlike a lambda, has access to 'this'.
+struct Periodic
+{
+ LLLater* mLater;
+ bool_func_t mCallable;
+ LLDate::timestamp mNext;
+ F32 mSeconds;
- nullary_func_t mCallable;
+ void operator()()
+ {
+ if (! mCallable())
+ {
+ // Returning false means please schedule another call.
+ // Don't call doAfterInterval(), which rereads LLDate::now(),
+ // since that would defer by however long it took us to wake
+ // up and notice plus however long callable() took to run.
+ mNext += mSeconds;
+ mLater->doAtTime(*this, mNext);
+ }
+ }
};
-// Call a given callable once after specified interval.
-void doAfterInterval(nullary_func_t callable, F32 seconds)
+// Call a given callable every specified number of seconds, until it returns true.
+LLLater::handle_t LLLater::doPeriodically(bool_func_t callable, F32 seconds)
{
- new NullaryFuncEventTimer(callable, seconds);
+ // Passing seconds <= 0 will produce an infinite loop.
+ llassert(seconds > 0);
+ auto next{ LLDate::now().secondsSinceEpoch() + seconds };
+ return doAtTime(Periodic{ this, callable, next, seconds }, next);
}
-class BoolFuncEventTimer: public LLEventTimer
+bool LLLater::isRunning(handle_t timer)
{
-public:
- BoolFuncEventTimer(bool_func_t callable, F32 seconds):
- LLEventTimer(seconds),
- mCallable(callable)
- {
- }
-private:
- BOOL tick()
- {
- return mCallable();
- }
+ // A default-constructed timer isn't running.
+ // A timer we don't find in mHandles has fired or been canceled.
+ return timer && mHandles.find(timer.token) != mHandles.end();
+}
- bool_func_t mCallable;
-};
+// Cancel a future timer set by doAtTime(), doAfterInterval(), doPeriodically()
+bool LLLater::cancel(handle_t& timer)
+{
+ // For exception safety, capture and clear timer before canceling.
+ // Once we've canceled this handle, don't retain the live handle.
+ const handle_t ctimer{ timer };
+ timer = handle_t();
+ return cancel(ctimer);
+}
-// Call a given callable every specified number of seconds, until it returns true.
-void doPeriodically(bool_func_t callable, F32 seconds)
+bool LLLater::cancel(const handle_t& timer)
+{
+ if (! timer)
+ {
+ return false;
+ }
+
+ // fibonacci_heap documentation does not address the question of what
+ // happens if you call erase() twice with the same handle. Is it a no-op?
+ // Does it invalidate the heap? Is it UB?
+
+ // Nor do we find any documented way to ask whether a given handle still
+ // tracks a valid heap node. That's why we capture all returned handles in
+ // mHandles and validate against that collection. What about the pop()
+ // call in tick()? How to map from the top() value back to the
+ // corresponding handle_t? That's why we store func_at::mToken.
+
+ // fibonacci_heap provides a pair of begin()/end() methods to iterate over
+ // all nodes (NOT in heap order), plus a function to convert from such
+ // iterators to handles. Without mHandles, that would be our only chance
+ // to validate.
+ auto found{ mHandles.find(timer.token) };
+ if (found == mHandles.end())
+ {
+ // we don't recognize this handle -- maybe the timer has already
+ // fired, maybe it was previously canceled.
+ return false;
+ }
+
+ // erase from mQueue the handle_t referenced by timer.token
+ mQueue.erase(found->second);
+ // before erasing timer.token from mHandles
+ mHandles.erase(found);
+ if (mQueue.empty())
+ {
+ // If that was the last active timer, unregister for callbacks.
+ //LLCallbackList::instance().deleteFunction(mLive);
+ // Since we're in the source file that knows the true identity of an
+ // LLCallbackList::handle_t, we don't even need to call instance().
+ mLive.disconnect();
+ }
+ return true;
+}
+
+bool LLLater::tick()
{
- new BoolFuncEventTimer(callable, seconds);
+ // Fetch current time only on entry, even though running some mQueue task
+ // may take long enough that the next one after would become ready. We're
+ // sharing this thread with everything else, and there's a risk we might
+ // starve it if we have a sequence of tasks that take nontrivial time.
+ auto now{ LLDate::now().secondsSinceEpoch() };
+ auto cutoff{ now + TIMESLICE };
+ while (! mQueue.empty())
+ {
+ auto& top{ mQueue.top() };
+ if (top.mTime > now)
+ {
+ // we've hit an entry that's still in the future:
+ // done with this tick(), but schedule another call
+ return false;
+ }
+ if (LLDate::now().secondsSinceEpoch() > cutoff)
+ {
+ // we still have ready tasks, but we've already eaten too much
+ // time this tick() -- defer until next tick() -- call again
+ return false;
+ }
+
+ // Found a ready task. Hate to copy stuff, but -- what if the task
+ // indirectly ends up trying to cancel a handle referencing its own
+ // node in mQueue? If the task has any state, that would be Bad. Copy
+ // the node before running it.
+ auto current{ top };
+ // remove the mHandles entry referencing this task
+ mHandles.erase(current.mToken);
+ // before removing the mQueue task entry itself
+ mQueue.pop();
+ // okay, NOW run
+ current.mFunc();
+ }
+ // queue is empty: stop callbacks
+ return true;
}
diff --git a/indra/llcommon/llcallbacklist.h b/indra/llcommon/llcallbacklist.h
index 89716cd74c..522a9b838b 100644
--- a/indra/llcommon/llcallbacklist.h
+++ b/indra/llcommon/llcallbacklist.h
@@ -27,53 +27,237 @@
#ifndef LL_LLCALLBACKLIST_H
#define LL_LLCALLBACKLIST_H
+#include "lldate.h"
+#include "llsingleton.h"
#include "llstl.h"
-#include <boost/function.hpp>
-#include <list>
+#include <boost/container_hash/hash.hpp>
+#include <boost/heap/fibonacci_heap.hpp>
+#include <boost/signals2.hpp>
+#include <functional>
+#include <unordered_map>
-class LLCallbackList
+/*****************************************************************************
+* LLCallbackList: callbacks every idle tick (every callFunctions() call)
+*****************************************************************************/
+class LLCallbackList: public LLSingleton<LLCallbackList>
{
+ LLSINGLETON(LLCallbackList);
public:
typedef void (*callback_t)(void*);
- typedef std::pair< callback_t,void* > callback_pair_t;
- // NOTE: It is confirmed that we DEPEND on the order provided by using a list :(
- //
- typedef std::list< callback_pair_t > callback_list_t;
-
- LLCallbackList();
+ typedef boost::signals2::signal<void()> callback_list_t;
+ typedef callback_list_t::slot_type callable_t;
+ typedef boost::signals2::connection handle_t;
+ typedef boost::signals2::scoped_connection temp_handle_t;
+ typedef std::function<bool ()> bool_func_t;
+
~LLCallbackList();
- void addFunction( callback_t func, void *data = NULL ); // register a callback, which will be called as func(data)
+ handle_t addFunction( callback_t func, void *data = NULL ); // register a callback, which will be called as func(data)
+ handle_t addFunction( const callable_t& func );
bool containsFunction( callback_t func, void *data = NULL ); // true if list already contains the function/data pair
bool deleteFunction( callback_t func, void *data = NULL ); // removes the first instance of this function/data pair from the list, false if not found
- void callFunctions(); // calls all functions
+ void deleteFunction( const handle_t& handle );
+ void callFunctions(); // calls all functions
void deleteAllFunctions();
+ handle_t doOnIdleOneTime( const callable_t& func );
+ handle_t doOnIdleRepeating( const bool_func_t& func );
+ bool isRunning(const handle_t& handle) const { return handle.connected(); };
+
static void test();
protected:
-
- inline callback_list_t::iterator find(callback_t func, void *data);
-
callback_list_t mCallbackList;
+
+ // "Additional specializations for std::pair and the standard container
+ // types, as well as utility functions to compose hashes are available in
+ // boost::hash."
+ // https://en.cppreference.com/w/cpp/utility/hash
+ typedef std::pair< callback_t,void* > callback_pair_t;
+ typedef std::unordered_map<callback_pair_t, handle_t,
+ boost::hash<callback_pair_t>> lookup_table;
+ lookup_table mLookup;
};
-typedef boost::function<void ()> nullary_func_t;
-typedef boost::function<bool ()> bool_func_t;
+/*-------------------- legacy names in global namespace --------------------*/
+#define gIdleCallbacks (LLCallbackList::instance())
+
+using nullary_func_t = LLCallbackList::callable_t;
+using bool_func_t = LLCallbackList::bool_func_t;
// Call a given callable once in idle loop.
-void doOnIdleOneTime(nullary_func_t callable);
+inline
+LLCallbackList::handle_t doOnIdleOneTime(nullary_func_t callable)
+{
+ return gIdleCallbacks.doOnIdleOneTime(callable);
+}
// Repeatedly call a callable in idle loop until it returns true.
-void doOnIdleRepeating(bool_func_t callable);
+inline
+LLCallbackList::handle_t doOnIdleRepeating(bool_func_t callable)
+{
+ return gIdleCallbacks.doOnIdleRepeating(callable);
+}
+
+/*****************************************************************************
+* LLLater: callbacks at some future time
+*****************************************************************************/
+class LLLater: public LLSingleton<LLLater>
+{
+ LLSINGLETON(LLLater);
+
+ using token_t = U32;
+
+ // Define a struct for our priority queue entries, instead of using
+ // a tuple, because we need to define the comparison operator.
+ struct func_at
+ {
+ nullary_func_t mFunc;
+ LLDate::timestamp mTime;
+ token_t mToken;
+
+ func_at(const nullary_func_t& func, LLDate::timestamp tm, token_t token):
+ mFunc(func),
+ mTime(tm),
+ mToken(token)
+ {}
+
+ friend bool operator<(const func_at& lhs, const func_at& rhs)
+ {
+ // use greater-than because we want fibonacci_heap to select the
+ // EARLIEST time as the top()
+ return lhs.mTime > rhs.mTime;
+ }
+ };
+
+ // Accept default stable<false>: when two funcs have the same timestamp,
+ // we don't care in what order they're called.
+ // Specify constant_time_size<false>: we don't need to optimize the size()
+ // method, iow we don't need to store and maintain a count of entries.
+ typedef boost::heap::fibonacci_heap<func_at, boost::heap::constant_time_size<false>>
+ queue_t;
+
+public:
+ // If tasks that come ready during a given tick() take longer than this,
+ // defer any subsequent ready tasks to a future tick() call.
+ static constexpr F32 TIMESLICE{ 0.005f };
+ class handle_t
+ {
+ private:
+ friend class LLLater;
+ token_t token;
+ public:
+ handle_t(token_t token=0): token(token) {}
+ bool operator==(const handle_t& rhs) const { return this->token == rhs.token; }
+ explicit operator bool() const { return bool(token); }
+ bool operator!() const { return ! bool(*this); }
+ };
+
+ // Call a given callable once at specified timestamp.
+ handle_t doAtTime(nullary_func_t callable, LLDate::timestamp time);
+
+ // Call a given callable once after specified interval.
+ handle_t doAfterInterval(nullary_func_t callable, F32 seconds);
+
+ // Call a given callable every specified number of seconds, until it returns true.
+ handle_t doPeriodically(bool_func_t callable, F32 seconds);
+
+ // test whether specified handle is still live
+ bool isRunning(handle_t timer);
+
+ // Cancel a future timer set by doAtTime(), doAfterInterval(), doPeriodically().
+ // Return true iff the handle corresponds to a live timer.
+ bool cancel(const handle_t& timer);
+ // If we're canceling a non-const handle_t, also clear it so we need not
+ // cancel again.
+ bool cancel(handle_t& timer);
+
+ // Store a handle_t returned by doAtTime(), doAfterInterval() or
+ // doPeriodically() in a temp_handle_t to cancel() automatically on
+ // destruction of the temp_handle_t.
+ class temp_handle_t
+ {
+ public:
+ temp_handle_t() {}
+ temp_handle_t(const handle_t& hdl): mHandle(hdl) {}
+ temp_handle_t(const temp_handle_t&) = delete;
+ temp_handle_t(temp_handle_t&&) = default;
+ temp_handle_t& operator=(const handle_t& hdl)
+ {
+ // initializing a new temp_handle_t, then swapping it into *this,
+ // takes care of destroying any previous mHandle
+ temp_handle_t replacement(hdl);
+ swap(replacement);
+ return *this;
+ }
+ temp_handle_t& operator=(const temp_handle_t&) = delete;
+ temp_handle_t& operator=(temp_handle_t&&) = default;
+ ~temp_handle_t()
+ {
+ cancel();
+ }
+
+ // temp_handle_t should be usable wherever handle_t is
+ operator handle_t() const { return mHandle; }
+ // If we're dealing with a non-const temp_handle_t, pass a reference
+ // to our handle_t member (e.g. to LLLater::cancel()).
+ operator handle_t&() { return mHandle; }
+
+ // For those in the know, provide a cancel() method of our own that
+ // avoids LLLater::instance() lookup when mHandle isn't live.
+ bool cancel()
+ {
+ if (! mHandle)
+ {
+ return false;
+ }
+ else
+ {
+ return LLLater::instance().cancel(mHandle);
+ }
+ }
+
+ void swap(temp_handle_t& other) noexcept
+ {
+ std::swap(this->mHandle, other.mHandle);
+ }
+
+ private:
+ handle_t mHandle;
+ };
+
+private:
+ bool tick();
+
+ // NOTE: We don't lock our data members because it doesn't make sense to
+ // register cross-thread callbacks. If we start wanting to use them on
+ // threads other than the main thread, it would make more sense to make
+ // our data members thread_local than to lock them.
+
+ // the heap aka priority queue
+ queue_t mQueue;
+ // handles we've returned that haven't yet canceled
+ std::unordered_map<token_t, queue_t::handle_type> mHandles;
+ token_t mToken{ 0 };
+ // While mQueue is non-empty, register for regular callbacks.
+ LLCallbackList::temp_handle_t mLive;
+};
+
+/*-------------------- legacy names in global namespace --------------------*/
// Call a given callable once after specified interval.
-void doAfterInterval(nullary_func_t callable, F32 seconds);
+inline
+LLLater::handle_t doAfterInterval(nullary_func_t callable, F32 seconds)
+{
+ return LLLater::instance().doAfterInterval(callable, seconds);
+}
// Call a given callable every specified number of seconds, until it returns true.
-void doPeriodically(bool_func_t callable, F32 seconds);
-
-extern LLCallbackList gIdleCallbacks;
+inline
+LLLater::handle_t doPeriodically(bool_func_t callable, F32 seconds)
+{
+ return LLLater::instance().doPeriodically(callable, seconds);
+}
#endif
diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp
index 2ddcf40895..6c23444820 100644
--- a/indra/llcommon/lldate.cpp
+++ b/indra/llcommon/lldate.cpp
@@ -41,9 +41,9 @@
#include "llstring.h"
#include "llfasttimer.h"
-static const F64 DATE_EPOCH = 0.0;
+static const LLDate::timestamp DATE_EPOCH = 0.0;
-static const F64 LL_APR_USEC_PER_SEC = 1000000.0;
+static const LLDate::timestamp LL_APR_USEC_PER_SEC = 1000000.0;
// should be APR_USEC_PER_SEC, but that relies on INT64_C which
// isn't defined in glib under our build set up for some reason
@@ -233,13 +233,13 @@ bool LLDate::fromStream(std::istream& s)
return false;
}
- F64 seconds_since_epoch = time / LL_APR_USEC_PER_SEC;
+ timestamp seconds_since_epoch = time / LL_APR_USEC_PER_SEC;
// check for fractional
c = s.peek();
if(c == '.')
{
- F64 fractional = 0.0;
+ timestamp fractional = 0.0;
s >> fractional;
seconds_since_epoch += fractional;
}
@@ -299,12 +299,12 @@ bool LLDate::fromYMDHMS(S32 year, S32 month, S32 day, S32 hour, S32 min, S32 sec
return true;
}
-F64 LLDate::secondsSinceEpoch() const
+LLDate::timestamp LLDate::secondsSinceEpoch() const
{
return mSecondsSinceEpoch;
}
-void LLDate::secondsSinceEpoch(F64 seconds)
+void LLDate::secondsSinceEpoch(timestamp seconds)
{
mSecondsSinceEpoch = seconds;
}
diff --git a/indra/llcommon/lldate.h b/indra/llcommon/lldate.h
index be2cd2d051..c3d0cb97f3 100644
--- a/indra/llcommon/lldate.h
+++ b/indra/llcommon/lldate.h
@@ -44,6 +44,8 @@
class LL_COMMON_API LLDate
{
public:
+ using timestamp = F64;
+
/**
* @brief Construct a date equal to epoch.
*/
@@ -103,14 +105,14 @@ public:
*
* @return The number of seconds since epoch UTC.
*/
- F64 secondsSinceEpoch() const;
+ timestamp secondsSinceEpoch() const;
/**
* @brief Set the date in seconds since epoch.
*
* @param seconds The number of seconds since epoch UTC.
*/
- void secondsSinceEpoch(F64 seconds);
+ void secondsSinceEpoch(timestamp seconds);
/**
* @brief Create an LLDate object set to the current time.
@@ -147,7 +149,7 @@ public:
private:
- F64 mSecondsSinceEpoch;
+ timestamp mSecondsSinceEpoch;
};
// Helper function to stream out a date
diff --git a/indra/llcommon/llerrorlegacy.h b/indra/llcommon/llerrorlegacy.h
deleted file mode 100644
index 31dd207008..0000000000
--- a/indra/llcommon/llerrorlegacy.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * @file llerrorlegacy.h
- * @date January 2007
- * @brief old things from the older error system
- *
- * $LicenseInfo:firstyear=2007&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_LLERRORLEGACY_H
-#define LL_LLERRORLEGACY_H
-
-
-#endif // LL_LLERRORLEGACY_H
diff --git a/indra/llcommon/lleventfilter.cpp b/indra/llcommon/lleventfilter.cpp
index 14c9c51830..e72ae7ad33 100644
--- a/indra/llcommon/lleventfilter.cpp
+++ b/indra/llcommon/lleventfilter.cpp
@@ -73,115 +73,52 @@ bool LLEventMatching::post(const LLSD& event)
}
/*****************************************************************************
-* LLEventTimeoutBase
+* LLEventTimeout
*****************************************************************************/
-LLEventTimeoutBase::LLEventTimeoutBase():
+LLEventTimeout::LLEventTimeout():
LLEventFilter("timeout")
{
}
-LLEventTimeoutBase::LLEventTimeoutBase(LLEventPump& source):
+LLEventTimeout::LLEventTimeout(LLEventPump& source):
LLEventFilter(source, "timeout")
{
}
-void LLEventTimeoutBase::actionAfter(F32 seconds, const Action& action)
+void LLEventTimeout::actionAfter(F32 seconds, const Action& action)
{
- setCountdown(seconds);
- mAction = action;
- if (! mMainloop.connected())
- {
- LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
- mMainloop = mainloop.listen(getName(), [this](const LLSD& event){ return tick(event); });
- }
+ mTimer = LLLater::instance().doAfterInterval(action, seconds);
}
-class ErrorAfter
-{
-public:
- ErrorAfter(const std::string& message): mMessage(message) {}
-
- void operator()()
- {
- LL_ERRS("LLEventTimeout") << mMessage << LL_ENDL;
- }
-
-private:
- std::string mMessage;
-};
-
-void LLEventTimeoutBase::errorAfter(F32 seconds, const std::string& message)
+void LLEventTimeout::errorAfter(F32 seconds, const std::string& message)
{
- actionAfter(seconds, ErrorAfter(message));
+ actionAfter(
+ seconds,
+ [message=message]
+ {
+ LL_ERRS("LLEventTimeout") << message << LL_ENDL;
+ });
}
-class EventAfter
+void LLEventTimeout::eventAfter(F32 seconds, const LLSD& event)
{
-public:
- EventAfter(LLEventPump& pump, const LLSD& event):
- mPump(pump),
- mEvent(event)
- {}
-
- void operator()()
- {
- mPump.post(mEvent);
- }
-
-private:
- LLEventPump& mPump;
- LLSD mEvent;
-};
-
-void LLEventTimeoutBase::eventAfter(F32 seconds, const LLSD& event)
-{
- actionAfter(seconds, EventAfter(*this, event));
+ actionAfter(seconds, [this, event]{ post(event); });
}
-bool LLEventTimeoutBase::post(const LLSD& event)
+bool LLEventTimeout::post(const LLSD& event)
{
cancel();
return LLEventStream::post(event);
}
-void LLEventTimeoutBase::cancel()
-{
- mMainloop.disconnect();
-}
-
-bool LLEventTimeoutBase::tick(const LLSD&)
-{
- if (countdownElapsed())
- {
- cancel();
- mAction();
- }
- return false; // show event to other listeners
-}
-
-bool LLEventTimeoutBase::running() const
-{
- return mMainloop.connected();
-}
-
-/*****************************************************************************
-* LLEventTimeout
-*****************************************************************************/
-LLEventTimeout::LLEventTimeout() {}
-
-LLEventTimeout::LLEventTimeout(LLEventPump& source):
- LLEventTimeoutBase(source)
+void LLEventTimeout::cancel()
{
+ mTimer.cancel();
}
-void LLEventTimeout::setCountdown(F32 seconds)
+bool LLEventTimeout::running() const
{
- mTimer.setTimerExpirySec(seconds);
-}
-
-bool LLEventTimeout::countdownElapsed() const
-{
- return mTimer.hasExpired();
+ return LLLater::instance().isRunning(mTimer);
}
/*****************************************************************************
@@ -224,21 +161,21 @@ void LLEventBatch::setSize(std::size_t size)
}
/*****************************************************************************
-* LLEventThrottleBase
+* LLEventThrottle
*****************************************************************************/
-LLEventThrottleBase::LLEventThrottleBase(F32 interval):
+LLEventThrottle::LLEventThrottle(F32 interval):
LLEventFilter("throttle"),
mInterval(interval),
mPosts(0)
{}
-LLEventThrottleBase::LLEventThrottleBase(LLEventPump& source, F32 interval):
+LLEventThrottle::LLEventThrottle(LLEventPump& source, F32 interval):
LLEventFilter(source, "throttle"),
mInterval(interval),
mPosts(0)
{}
-void LLEventThrottleBase::flush()
+void LLEventThrottle::flush()
{
// flush() is a no-op unless there's something pending.
// Don't test mPending because there's no requirement that the consumer
@@ -259,12 +196,12 @@ void LLEventThrottleBase::flush()
}
}
-LLSD LLEventThrottleBase::pending() const
+LLSD LLEventThrottle::pending() const
{
return mPending;
}
-bool LLEventThrottleBase::post(const LLSD& event)
+bool LLEventThrottle::post(const LLSD& event)
{
// Always capture most recent post() event data. If caller wants to
// aggregate multiple events, let them retrieve pending() and modify
@@ -289,13 +226,13 @@ bool LLEventThrottleBase::post(const LLSD& event)
// timeRemaining tells us how much longer it will be until
// mInterval seconds since the last flush() call. At that time,
// flush() deferred events.
- alarmActionAfter(timeRemaining, [this](){ flush(); });
+ alarmActionAfter(timeRemaining, [this]{ flush(); });
}
}
return false;
}
-void LLEventThrottleBase::setInterval(F32 interval)
+void LLEventThrottle::setInterval(F32 interval)
{
F32 oldInterval = mInterval;
mInterval = interval;
@@ -333,35 +270,24 @@ void LLEventThrottleBase::setInterval(F32 interval)
}
}
-F32 LLEventThrottleBase::getDelay() const
+F32 LLEventThrottle::getDelay() const
{
return timerGetRemaining();
}
-/*****************************************************************************
-* LLEventThrottle implementation
-*****************************************************************************/
-LLEventThrottle::LLEventThrottle(F32 interval):
- LLEventThrottleBase(interval)
-{}
-
-LLEventThrottle::LLEventThrottle(LLEventPump& source, F32 interval):
- LLEventThrottleBase(source, interval)
-{}
-
-void LLEventThrottle::alarmActionAfter(F32 interval, const LLEventTimeoutBase::Action& action)
+void LLEventThrottle::alarmActionAfter(F32 interval, const LLEventTimeout::Action& action)
{
- mAlarm.actionAfter(interval, action);
+ mAlarm = LLLater::instance().doAfterInterval(action, interval);
}
bool LLEventThrottle::alarmRunning() const
{
- return mAlarm.running();
+ return LLLater::instance().isRunning(mAlarm);
}
void LLEventThrottle::alarmCancel()
{
- return mAlarm.cancel();
+ LLLater::instance().cancel(mAlarm);
}
void LLEventThrottle::timerSet(F32 interval)
diff --git a/indra/llcommon/lleventfilter.h b/indra/llcommon/lleventfilter.h
index 88dc5a3015..1deb6f0f4c 100644
--- a/indra/llcommon/lleventfilter.h
+++ b/indra/llcommon/lleventfilter.h
@@ -29,13 +29,13 @@
#if ! defined(LL_LLEVENTFILTER_H)
#define LL_LLEVENTFILTER_H
+#include "llcallbacklist.h"
#include "llevents.h"
-#include "stdtypes.h"
-#include "lltimer.h"
#include "llsdutil.h"
-#include <boost/function.hpp>
+#include "lltimer.h"
+#include "stdtypes.h"
+#include <functional>
-class LLEventTimer;
class LLDate;
/**
@@ -78,22 +78,27 @@ private:
/**
* Wait for an event to be posted. If no such event arrives within a specified
- * time, take a specified action. See LLEventTimeout for production
- * implementation.
- *
- * @NOTE This is an abstract base class so that, for testing, we can use an
- * alternate "timer" that doesn't actually consume real time.
+ * time, take a specified action.
+ *
+ * @NOTE: Caution should be taken when using the LLEventTimeout(LLEventPump &)
+ * constructor to ensure that the upstream event pump is not an LLEventMaildrop
+ * or any other kind of store and forward pump which may have events outstanding.
+ * Using this constructor will cause the upstream event pump to fire any pending
+ * events and could result in the invocation of a virtual method before the timeout
+ * has been fully constructed. The timeout should instead be constructed separately
+ * from the event pump and attached using the listen method.
+ * See llcoro::suspendUntilEventOnWithTimeout() for an example.
*/
-class LL_COMMON_API LLEventTimeoutBase: public LLEventFilter
+class LL_COMMON_API LLEventTimeout: public LLEventFilter
{
public:
/// construct standalone
- LLEventTimeoutBase();
+ LLEventTimeout();
/// construct and connect
- LLEventTimeoutBase(LLEventPump& source);
+ LLEventTimeout(LLEventPump& source);
/// Callable, can be constructed with boost::bind()
- typedef boost::function<void()> Action;
+ typedef std::function<void()> Action;
/**
* Start countdown timer for the specified number of @a seconds. Forward
@@ -120,8 +125,8 @@ public:
* @endcode
*
* @NOTE
- * The implementation relies on frequent events on the LLEventPump named
- * "mainloop".
+ * The implementation relies on frequent calls to
+ * gIdleCallbacks.callFunctions().
*/
void actionAfter(F32 seconds, const Action& action);
@@ -134,7 +139,7 @@ public:
* Instantiate an LLEventTimeout listening to that API and call
* errorAfter() on each async request with a timeout comfortably longer
* than the API's time guarantee (much longer than the anticipated
- * "mainloop" granularity).
+ * gIdleCallbacks.callFunctions() granularity).
*
* Then if the async API breaks its promise, the program terminates with
* the specified LL_ERRS @a message. The client of the async API can
@@ -184,42 +189,9 @@ public:
/// Is this timer currently running?
bool running() const;
-protected:
- virtual void setCountdown(F32 seconds) = 0;
- virtual bool countdownElapsed() const = 0;
-
private:
- bool tick(const LLSD&);
-
- LLTempBoundListener mMainloop;
- Action mAction;
-};
-
-/**
- * Production implementation of LLEventTimoutBase.
- *
- * @NOTE: Caution should be taken when using the LLEventTimeout(LLEventPump &)
- * constructor to ensure that the upstream event pump is not an LLEventMaildrop
- * or any other kind of store and forward pump which may have events outstanding.
- * Using this constructor will cause the upstream event pump to fire any pending
- * events and could result in the invocation of a virtual method before the timeout
- * has been fully constructed. The timeout should instead be connected upstream
- * from the event pump and attached using the listen method.
- * See llcoro::suspendUntilEventOnWithTimeout() for an example.
- */
-
-class LL_COMMON_API LLEventTimeout: public LLEventTimeoutBase
-{
-public:
- LLEventTimeout();
- LLEventTimeout(LLEventPump& source);
-
-protected:
- virtual void setCountdown(F32 seconds);
- virtual bool countdownElapsed() const;
-
-private:
- LLTimer mTimer;
+ // Use a temp_handle_t so it's canceled on destruction.
+ LLLater::temp_handle_t mTimer;
};
/**
@@ -251,7 +223,7 @@ private:
};
/**
- * LLEventThrottleBase: construct with a time interval. Regardless of how
+ * LLEventThrottle: construct with a time interval. Regardless of how
* frequently you call post(), LLEventThrottle will pass on an event to
* its listeners no more often than once per specified interval.
*
@@ -284,13 +256,13 @@ private:
* alternate "timer" that doesn't actually consume real time. See
* LLEventThrottle.
*/
-class LL_COMMON_API LLEventThrottleBase: public LLEventFilter
+class LL_COMMON_API LLEventThrottle: public LLEventFilter
{
public:
// pass time interval
- LLEventThrottleBase(F32 interval);
+ LLEventThrottle(F32 interval);
// construct and connect
- LLEventThrottleBase(LLEventPump& source, F32 interval);
+ LLEventThrottle(LLEventPump& source, F32 interval);
// force out any deferred events
void flush();
@@ -311,45 +283,24 @@ public:
// time until next event would be passed through, 0.0 if now
F32 getDelay() const;
-protected:
- // Implement these time-related methods for a valid LLEventThrottleBase
- // subclass (see LLEventThrottle). For testing, we use a subclass that
- // doesn't involve actual elapsed time.
- virtual void alarmActionAfter(F32 interval, const LLEventTimeoutBase::Action& action) = 0;
- virtual bool alarmRunning() const = 0;
- virtual void alarmCancel() = 0;
- virtual void timerSet(F32 interval) = 0;
- virtual F32 timerGetRemaining() const = 0;
-
private:
- // remember throttle interval
- F32 mInterval;
- // count post() calls since last flush()
- std::size_t mPosts;
+ void alarmActionAfter(F32 interval, const LLEventTimeout::Action& action);
+ bool alarmRunning() const;
+ void alarmCancel();
+ void timerSet(F32 interval);
+ F32 timerGetRemaining() const;
+
// pending event data from most recent deferred event
LLSD mPending;
-};
-
-/**
- * Production implementation of LLEventThrottle.
- */
-class LLEventThrottle: public LLEventThrottleBase
-{
-public:
- LLEventThrottle(F32 interval);
- LLEventThrottle(LLEventPump& source, F32 interval);
-
-private:
- virtual void alarmActionAfter(F32 interval, const LLEventTimeoutBase::Action& action) /*override*/;
- virtual bool alarmRunning() const /*override*/;
- virtual void alarmCancel() /*override*/;
- virtual void timerSet(F32 interval) /*override*/;
- virtual F32 timerGetRemaining() const /*override*/;
-
- // use this to arrange a deferred flush() call
- LLEventTimeout mAlarm;
// use this to track whether we're within mInterval of last flush()
LLTimer mTimer;
+ // count post() calls since last flush()
+ std::size_t mPosts;
+ // remember throttle interval
+ F32 mInterval;
+
+ // use this to arrange a deferred flush() call
+ LLLater::handle_t mAlarm;
};
/**
diff --git a/indra/llcommon/lleventtimer.cpp b/indra/llcommon/lleventtimer.cpp
index f575a7b6bf..b163ad375c 100644
--- a/indra/llcommon/lleventtimer.cpp
+++ b/indra/llcommon/lleventtimer.cpp
@@ -25,49 +25,34 @@
*/
#include "linden_common.h"
-
#include "lleventtimer.h"
-#include "u64.h"
-
-
//////////////////////////////////////////////////////////////////////////////
//
// LLEventTimer Implementation
//
//////////////////////////////////////////////////////////////////////////////
-LLEventTimer::LLEventTimer(F32 period)
-: mEventTimer()
+LLEventTimer::LLEventTimer(F32 period):
+ mPeriod(period)
{
- mPeriod = period;
-}
-
-LLEventTimer::LLEventTimer(const LLDate& time)
-: mEventTimer()
-{
- mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch());
+ start();
}
+LLEventTimer::LLEventTimer(const LLDate& time):
+ LLEventTimer(F32(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch()))
+{}
LLEventTimer::~LLEventTimer()
{
}
-//static
-void LLEventTimer::updateClass()
+void LLEventTimer::start()
{
- for (auto& timer : instance_snapshot())
- {
- F32 et = timer.mEventTimer.getElapsedTimeF32();
- if (timer.mEventTimer.getStarted() && et > timer.mPeriod) {
- timer.mEventTimer.reset();
- if ( timer.tick() )
- {
- delete &timer;
- }
- }
- }
+ mTimer = LLLater::instance().doPeriodically([this]{ return tick(); }, mPeriod);
}
-
+void LLEventTimer::stop()
+{
+ LLLater::instance().cancel(mTimer);
+}
diff --git a/indra/llcommon/lleventtimer.h b/indra/llcommon/lleventtimer.h
index b5d40a0622..34ff157e22 100644
--- a/indra/llcommon/lleventtimer.h
+++ b/indra/llcommon/lleventtimer.h
@@ -27,13 +27,12 @@
#ifndef LL_EVENTTIMER_H
#define LL_EVENTTIMER_H
-#include "stdtypes.h"
+#include "llcallbacklist.h"
#include "lldate.h"
-#include "llinstancetracker.h"
-#include "lltimer.h"
+#include "stdtypes.h"
// class for scheduling a function to be called at a given frequency (approximate, inprecise)
-class LL_COMMON_API LLEventTimer : public LLInstanceTracker<LLEventTimer>
+class LL_COMMON_API LLEventTimer
{
public:
@@ -41,14 +40,15 @@ public:
LLEventTimer(const LLDate& time);
virtual ~LLEventTimer();
- //function to be called at the supplied frequency
- // Normally return FALSE; TRUE will delete the timer after the function returns.
- virtual BOOL tick() = 0;
+ void start();
+ void stop();
- static void updateClass();
+ //function to be called at the supplied frequency
+ // Normally return false; true will delete the timer after the function returns.
+ virtual bool tick() = 0;
protected:
- LLTimer mEventTimer;
+ LLLater::temp_handle_t mTimer;
F32 mPeriod;
};
diff --git a/indra/llcommon/lllivefile.cpp b/indra/llcommon/lllivefile.cpp
index ea485c2d86..692a21c1f1 100644
--- a/indra/llcommon/lllivefile.cpp
+++ b/indra/llcommon/lllivefile.cpp
@@ -170,7 +170,7 @@ namespace
: LLEventTimer(refresh), mLiveFile(f)
{ }
- BOOL tick()
+ bool tick() override
{
mLiveFile.checkAndReload();
return FALSE;
diff --git a/indra/llcommon/tests/lleventfilter_test.cpp b/indra/llcommon/tests/lleventfilter_test.cpp
index fa2cb03e95..38d6d0076e 100644
--- a/indra/llcommon/tests/lleventfilter_test.cpp
+++ b/indra/llcommon/tests/lleventfilter_test.cpp
@@ -51,6 +51,7 @@
// as we've carefully put all functionality except actual LLTimer calls into
// LLEventTimeoutBase, that should suffice. We're not not not trying to test
// LLTimer here.
+#if 0 // time testing needs reworking
class TestEventTimeout: public LLEventTimeoutBase
{
public:
@@ -151,6 +152,7 @@ public:
F32 mAlarmRemaining, mTimerRemaining;
LLEventTimeoutBase::Action mAlarmAction;
};
+#endif // time testing needs reworking
/*****************************************************************************
* TUT
@@ -220,6 +222,8 @@ namespace tut
void filter_object::test<2>()
{
set_test_name("LLEventTimeout::actionAfter()");
+ skip("time testing needs reworking");
+#if 0 // time testing needs reworking
LLEventPump& driver(pumps.obtain("driver"));
TestEventTimeout filter(driver);
listener0.reset(0);
@@ -285,12 +289,15 @@ namespace tut
filter.forceTimeout();
mainloop.post(17);
check_listener("no timeout 6", listener1, LLSD(0));
+#endif // time testing needs reworking
}
template<> template<>
void filter_object::test<3>()
{
set_test_name("LLEventTimeout::eventAfter()");
+ skip("time testing needs reworking");
+#if 0 // time testing needs reworking
LLEventPump& driver(pumps.obtain("driver"));
TestEventTimeout filter(driver);
listener0.reset(0);
@@ -322,12 +329,15 @@ namespace tut
filter.forceTimeout();
mainloop.post(17);
check_listener("no timeout 3", listener0, LLSD(0));
+#endif // time testing needs reworking
}
template<> template<>
void filter_object::test<4>()
{
set_test_name("LLEventTimeout::errorAfter()");
+ skip("time testing needs reworking");
+#if 0 // time testing needs reworking
WrapLLErrs capture;
LLEventPump& driver(pumps.obtain("driver"));
TestEventTimeout filter(driver);
@@ -362,12 +372,15 @@ namespace tut
filter.forceTimeout();
mainloop.post(17);
check_listener("no timeout 3", listener0, LLSD(0));
+#endif // time testing needs reworking
}
template<> template<>
void filter_object::test<5>()
{
set_test_name("LLEventThrottle");
+ skip("time testing needs reworking");
+#if 0 // time testing needs reworking
TestEventThrottle throttle(3);
Concat cat;
throttle.listen("concat", boost::ref(cat));
@@ -403,6 +416,7 @@ namespace tut
throttle.advance(5);
throttle.post(";17");
ensure_equals("17", cat.result, "136;12;17"); // "17" delivered
+#endif // time testing needs reworking
}
template<class PUMP>
diff --git a/indra/llcommon/tests/llmainthreadtask_test.cpp b/indra/llcommon/tests/llmainthreadtask_test.cpp
index 69b11ccafb..4a15e30a30 100644
--- a/indra/llcommon/tests/llmainthreadtask_test.cpp
+++ b/indra/llcommon/tests/llmainthreadtask_test.cpp
@@ -20,8 +20,8 @@
// other Linden headers
#include "../test/lltut.h"
#include "../test/sync.h"
+#include "llcallbacklist.h"
#include "llthread.h" // on_main_thread()
-#include "lleventtimer.h"
#include "lockstatic.h"
/*****************************************************************************
@@ -108,7 +108,7 @@ namespace tut
lk.unlock();
// run the task -- should unblock thread, which will immediately block
// on mSync
- LLEventTimer::updateClass();
+ LLCallbackList::instance().callFunctions();
// 'lk', having unlocked, can no longer be used to access; relock with
// a new LockStatic instance
ensure("should now have run", LockStatic()->ran);
diff --git a/indra/llui/llflashtimer.cpp b/indra/llui/llflashtimer.cpp
index 39793316f4..4a5b220008 100644
--- a/indra/llui/llflashtimer.cpp
+++ b/indra/llui/llflashtimer.cpp
@@ -31,11 +31,11 @@ LLFlashTimer::LLFlashTimer(callback_t cb, S32 count, F32 period)
: LLEventTimer(period),
mCallback(cb),
mCurrentTickCount(0),
- mIsFlashingInProgress(false),
- mIsCurrentlyHighlighted(false),
- mUnset(false)
+ mIsFlashingInProgress(false),
+ mIsCurrentlyHighlighted(false),
+ mUnset(false)
{
- mEventTimer.stop();
+ stop();
// By default use settings from settings.xml to be able change them via Debug settings. See EXT-5973.
// Due to Timer is implemented as derived class from EventTimer it is impossible to change period
@@ -53,7 +53,7 @@ void LLFlashTimer::unset()
mCallback = NULL;
}
-BOOL LLFlashTimer::tick()
+bool LLFlashTimer::tick()
{
mIsCurrentlyHighlighted = !mIsCurrentlyHighlighted;
@@ -74,12 +74,12 @@ void LLFlashTimer::startFlashing()
{
mIsFlashingInProgress = true;
mIsCurrentlyHighlighted = true;
- mEventTimer.start();
+ start();
}
void LLFlashTimer::stopFlashing()
{
- mEventTimer.stop();
+ stop();
mIsFlashingInProgress = false;
mIsCurrentlyHighlighted = false;
mCurrentTickCount = 0;
diff --git a/indra/llui/llflashtimer.h b/indra/llui/llflashtimer.h
index db8d49f009..4a2088734d 100644
--- a/indra/llui/llflashtimer.h
+++ b/indra/llui/llflashtimer.h
@@ -46,7 +46,7 @@ public:
LLFlashTimer(callback_t cb = NULL, S32 count = 0, F32 period = 0.0);
~LLFlashTimer() {};
- /*virtual*/ BOOL tick();
+ bool tick() override;
void startFlashing();
void stopFlashing();
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index c84657cf7a..7e84ad3b2a 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -123,8 +123,7 @@ public:
stop();
}
- /*virtual*/
- BOOL tick()
+ bool tick() override
{
if(mEventTimer.hasExpired())
{
@@ -332,7 +331,7 @@ public:
// virtual
// Will be deleted after returning true - only safe to do this if all callbacks have fired.
- BOOL tick()
+ bool tick() override
{
// mPendingRequests will be zero if all requests have been
// responded to. mWaitTimes.empty() will be true if we have
diff --git a/indra/newview/lldonotdisturbnotificationstorage.h b/indra/newview/lldonotdisturbnotificationstorage.h
index 237d58b4de..2d39b5efed 100644
--- a/indra/newview/lldonotdisturbnotificationstorage.h
+++ b/indra/newview/lldonotdisturbnotificationstorage.h
@@ -42,7 +42,7 @@ public:
~LLDoNotDisturbNotificationStorageTimer();
public:
- BOOL tick();
+ bool tick() override;
};
class LLDoNotDisturbNotificationStorage : public LLParamSingleton<LLDoNotDisturbNotificationStorage>, public LLNotificationStorage
diff --git a/indra/newview/llfloaterlinkreplace.h b/indra/newview/llfloaterlinkreplace.h
index 060773f93e..8d91187a33 100644
--- a/indra/newview/llfloaterlinkreplace.h
+++ b/indra/newview/llfloaterlinkreplace.h
@@ -89,7 +89,7 @@ public:
BOOL postBuild();
virtual void onOpen(const LLSD& key);
- virtual BOOL tick();
+ bool tick() override;
private:
void checkEnableStart();
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index a3e173398f..34dc263519 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -1960,7 +1960,7 @@ public:
protected:
- BOOL tick()
+ bool tick() override
{
mCallback(mNewValue);
mEventTimer.stop();
diff --git a/indra/newview/llfloaterregionrestarting.h b/indra/newview/llfloaterregionrestarting.h
index 46416db2c8..d254149e30 100644
--- a/indra/newview/llfloaterregionrestarting.h
+++ b/indra/newview/llfloaterregionrestarting.h
@@ -43,7 +43,7 @@ private:
LLFloaterRegionRestarting(const LLSD& key);
virtual ~LLFloaterRegionRestarting();
virtual BOOL postBuild();
- virtual BOOL tick();
+ bool tick() override;
virtual void refresh();
virtual void draw();
virtual void regionChange();
diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp
index 553d09bec2..6da380c639 100644
--- a/indra/newview/llfloateruipreview.cpp
+++ b/indra/newview/llfloateruipreview.cpp
@@ -254,7 +254,7 @@ class LLFadeEventTimer : public LLEventTimer
{
public:
LLFadeEventTimer(F32 refresh, LLGUIPreviewLiveFile* parent);
- BOOL tick();
+ bool tick() override;
LLGUIPreviewLiveFile* mParent;
private:
BOOL mFadingOut; // fades in then out; this is toggled in between
diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h
index bace97d37a..f0e3e26a86 100644
--- a/indra/newview/llimview.h
+++ b/indra/newview/llimview.h
@@ -51,7 +51,7 @@ class LLSessionTimeoutTimer : public LLEventTimer
public:
LLSessionTimeoutTimer(const LLUUID& session_id, F32 period) : LLEventTimer(period), mSessionId(session_id) {}
virtual ~LLSessionTimeoutTimer() {};
- /* virtual */ BOOL tick();
+ bool tick() override;
private:
LLUUID mSessionId;
diff --git a/indra/newview/lllocalbitmaps.h b/indra/newview/lllocalbitmaps.h
index 1fdf9dccbf..8420049b1e 100644
--- a/indra/newview/lllocalbitmaps.h
+++ b/indra/newview/lllocalbitmaps.h
@@ -121,7 +121,7 @@ class LLLocalBitmapTimer : public LLEventTimer
void startTimer();
void stopTimer();
bool isRunning();
- BOOL tick();
+ bool tick() override;
};
diff --git a/indra/newview/lllocalgltfmaterials.h b/indra/newview/lllocalgltfmaterials.h
index 13b7577e96..53639dfb1d 100644
--- a/indra/newview/lllocalgltfmaterials.h
+++ b/indra/newview/lllocalgltfmaterials.h
@@ -90,7 +90,7 @@ public:
void startTimer();
void stopTimer();
bool isRunning();
- BOOL tick();
+ bool tick() override;
};
class LLLocalGLTFMaterialMgr : public LLSingleton<LLLocalGLTFMaterialMgr>
diff --git a/indra/newview/llmediadataclient.h b/indra/newview/llmediadataclient.h
index 8cd4793106..428e85b976 100644
--- a/indra/newview/llmediadataclient.h
+++ b/indra/newview/llmediadataclient.h
@@ -219,13 +219,13 @@ protected:
{
public:
RetryTimer(F32 time, Request::ptr_t);
- virtual BOOL tick();
+ virtual bool tick() override;
private:
// back-pointer
Request::ptr_t mRequest;
};
-
-
+
+
protected:
typedef std::list<Request::ptr_t> request_queue_t;
typedef std::set<Request::ptr_t> request_set_t;
@@ -286,12 +286,12 @@ private:
{
public:
QueueTimer(F32 time, LLMediaDataClient *mdc);
- virtual BOOL tick();
+ bool tick() override;
private:
// back-pointer
LLPointer<LLMediaDataClient> mMDC;
};
-
+
void setIsRunning(bool val) { mQueueTimerIsRunning = val; }
bool mQueueTimerIsRunning;
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index 13b52e97c5..aad6ceecb2 100644
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -313,7 +313,7 @@ public:
mEventTimer.stop();
}
- virtual BOOL tick() // from LLEventTimer
+ virtual bool tick() override // from LLEventTimer
{
return FALSE;
}
@@ -367,7 +367,7 @@ public:
}
- /*virtual*/ BOOL tick()
+ bool tick() override
{
if (!mIsActive) return FALSE;
@@ -508,7 +508,7 @@ public:
}
}
- /*virtual*/ BOOL tick()
+ bool tick() override
{
update();
return FALSE;
diff --git a/indra/newview/llsetkeybinddialog.cpp b/indra/newview/llsetkeybinddialog.cpp
index 74844a80e8..79d03922cc 100644
--- a/indra/newview/llsetkeybinddialog.cpp
+++ b/indra/newview/llsetkeybinddialog.cpp
@@ -53,7 +53,7 @@ public:
virtual ~Updater(){}
protected:
- BOOL tick()
+ bool tick() override
{
mCallback(mMask);
// Deletes itseft after execution
diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h
index 22c9481687..0242da1605 100644
--- a/indra/newview/llspeakers.h
+++ b/indra/newview/llspeakers.h
@@ -159,7 +159,7 @@ public:
*
* If action callback is not specified returns true. Instance will be deleted by LLEventTimer::updateClass().
*/
- virtual BOOL tick();
+ bool tick() override;
/**
* Clears the callback.
diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp
index 223aaad811..d30e028d33 100644
--- a/indra/newview/lltoast.cpp
+++ b/indra/newview/lltoast.cpp
@@ -43,34 +43,21 @@ LLToastLifeTimer::LLToastLifeTimer(LLToast* toast, F32 period)
{
}
-/*virtual*/
-BOOL LLToastLifeTimer::tick()
-{
- if (mEventTimer.hasExpired())
- {
- mToast->expire();
- }
- return FALSE;
-}
-
-void LLToastLifeTimer::stop()
-{
- mEventTimer.stop();
-}
-
-void LLToastLifeTimer::start()
+bool LLToastLifeTimer::tick()
{
- mEventTimer.start();
+ mToast->expire();
+ return false;
}
void LLToastLifeTimer::restart()
{
- mEventTimer.reset();
+ // start() discards any previously-running mTimer
+ start();
}
-BOOL LLToastLifeTimer::getStarted()
+bool LLToastLifeTimer::getStarted()
{
- return mEventTimer.getStarted();
+ return LLLater::instance.isRunning(mTimer);
}
void LLToastLifeTimer::setPeriod(F32 period)
@@ -78,12 +65,14 @@ void LLToastLifeTimer::setPeriod(F32 period)
mPeriod = period;
}
+/*==========================================================================*|
F32 LLToastLifeTimer::getRemainingTimeF32()
{
F32 et = mEventTimer.getElapsedTimeF32();
if (!getStarted() || et > mPeriod) return 0.0f;
return mPeriod - et;
}
+|*==========================================================================*/
//--------------------------------------------------------------------------
LLToast::Params::Params()
diff --git a/indra/newview/lltoast.h b/indra/newview/lltoast.h
index ab559f1e6f..49969ab70a 100644
--- a/indra/newview/lltoast.h
+++ b/indra/newview/lltoast.h
@@ -53,15 +53,13 @@ public:
LLToastLifeTimer(LLToast* toast, F32 period);
/*virtual*/
- BOOL tick();
- void stop();
- void start();
+ bool tick() override;
void restart();
- BOOL getStarted();
+ bool getStarted();
void setPeriod(F32 period);
- F32 getRemainingTimeF32();
+// F32 getRemainingTimeF32();
- LLTimer& getEventTimer() { return mEventTimer;}
+// LLTimer& getEventTimer() { return mEventTimer;}
private :
LLToast* mToast;
};
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index ff2753d240..b65305337f 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -2890,7 +2890,7 @@ public:
virtual ~LLPostTeleportNotifiers();
//function to be called at the supplied frequency
- virtual BOOL tick();
+ bool tick() override;
};
LLPostTeleportNotifiers::LLPostTeleportNotifiers() : LLEventTimer( 2.0 )
diff --git a/indra/newview/llviewerparcelmediaautoplay.h b/indra/newview/llviewerparcelmediaautoplay.h
index e83085dee0..9367c2a629 100644
--- a/indra/newview/llviewerparcelmediaautoplay.h
+++ b/indra/newview/llviewerparcelmediaautoplay.h
@@ -35,7 +35,7 @@ class LLViewerParcelMediaAutoPlay : LLEventTimer, public LLSingleton<LLViewerPar
{
LLSINGLETON(LLViewerParcelMediaAutoPlay);
public:
- virtual BOOL tick() override;
+ bool tick() override;
static void playStarted();
private: