diff --git a/indra/llcommon/lleventfilter.cpp b/indra/llcommon/lleventfilter.cpp
index 06b3cb769e2ab6a8bd6778cc9e67348cb13b4c06..ae35fb9c8ecfe7faba7b7b1c30b27948406e7a0f 100644
--- a/indra/llcommon/lleventfilter.cpp
+++ b/indra/llcommon/lleventfilter.cpp
@@ -38,6 +38,7 @@
 #include "llerror.h"                // LL_ERRS
 #include "llsdutil.h"               // llsd_matches()
 #include "stringize.h"
+#include "lldate.h"
 
 /*****************************************************************************
 *   LLEventFilter
@@ -183,6 +184,27 @@ bool LLEventTimeout::countdownElapsed() const
     return mTimer.hasExpired();
 }
 
+LLEventTimer* LLEventTimeout::post_every(F32 period, const std::string& pump, const LLSD& data)
+{
+    return LLEventTimer::run_every(
+        period,
+        [pump, data](){ LLEventPumps::instance().obtain(pump).post(data); });
+}
+
+LLEventTimer* LLEventTimeout::post_at(const LLDate& time, const std::string& pump, const LLSD& data)
+{
+    return LLEventTimer::run_at(
+        time,
+        [pump, data](){ LLEventPumps::instance().obtain(pump).post(data); });
+}
+
+LLEventTimer* LLEventTimeout::post_after(F32 interval, const std::string& pump, const LLSD& data)
+{
+    return LLEventTimer::run_after(
+        interval,
+        [pump, data](){ LLEventPumps::instance().obtain(pump).post(data); });
+}
+
 /*****************************************************************************
 *   LLEventBatch
 *****************************************************************************/
diff --git a/indra/llcommon/lleventfilter.h b/indra/llcommon/lleventfilter.h
index 79319353a7355af85efa832ba041b99d62b7ff29..f28d7e54aa91c8c9da572286457b9047118f7ab0 100644
--- a/indra/llcommon/lleventfilter.h
+++ b/indra/llcommon/lleventfilter.h
@@ -33,8 +33,11 @@
 #include "stdtypes.h"
 #include "lltimer.h"
 #include "llsdutil.h"
+#include "lleventtimer.h"
 #include <boost/function.hpp>
 
+class LLDate;
+
 /**
  * Generic base class
  */
@@ -211,6 +214,19 @@ class LL_COMMON_API LLEventTimeout: public LLEventTimeoutBase
     LLEventTimeout();
     LLEventTimeout(LLEventPump& source);
 
+    /// using LLEventTimeout as namespace for free functions
+    /// Post event to specified LLEventPump every period seconds. Delete
+    /// returned LLEventTimer* to cancel.
+    static LLEventTimer* post_every(F32 period, const std::string& pump, const LLSD& data);
+    /// Post event to specified LLEventPump at specified future time. Call
+    /// LLEventTimer::getInstance(returned pointer) to check whether it's still
+    /// pending; if so, delete the pointer to cancel.
+    static LLEventTimer* post_at(const LLDate& time, const std::string& pump, const LLSD& data);
+    /// Post event to specified LLEventPump after specified interval. Call
+    /// LLEventTimer::getInstance(returned pointer) to check whether it's still
+    /// pending; if so, delete the pointer to cancel.
+    static LLEventTimer* post_after(F32 interval, const std::string& pump, const LLSD& data);
+
 protected:
     virtual void setCountdown(F32 seconds);
     virtual bool countdownElapsed() const;
diff --git a/indra/llcommon/lleventtimer.h b/indra/llcommon/lleventtimer.h
index dc918121e129312d6248442f94c7e7282e1744da..dbbfe0c6e6cf18efa5ef4fd97f2ff3939cd4f158 100644
--- a/indra/llcommon/lleventtimer.h
+++ b/indra/llcommon/lleventtimer.h
@@ -40,16 +40,83 @@ class LL_COMMON_API LLEventTimer : public LLInstanceTracker<LLEventTimer>
 	LLEventTimer(F32 period);	// period is the amount of time between each call to tick() in seconds
 	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;
 
 	static void updateClass();
 
+	/// Schedule recurring calls to generic callable every period seconds.
+	/// Returns a pointer; if you delete it, cancels the recurring calls.
+	template <typename CALLABLE>
+	static LLEventTimer* run_every(F32 period, const CALLABLE& callable);
+
+	/// Schedule a future call to generic callable. Returns a pointer.
+	/// CAUTION: The object referenced by that pointer WILL BE DELETED once
+	/// the callback has been called! LLEventTimer::getInstance(pointer) (NOT
+	/// pointer->getInstance(pointer)!) can be used to test whether the
+	/// pointer is still valid. If it is, deleting it will cancel the
+	/// callback.
+	template <typename CALLABLE>
+	static LLEventTimer* run_at(const LLDate& time, const CALLABLE& callable);
+
+	/// Like run_at(), but after a time delta rather than at a timestamp.
+	/// Same CAUTION.
+	template <typename CALLABLE>
+	static LLEventTimer* run_after(F32 interval, const CALLABLE& callable);
+
 protected:
 	LLTimer mEventTimer;
 	F32 mPeriod;
+
+private:
+	template <typename CALLABLE>
+	class Generic;
+};
+
+template <typename CALLABLE>
+class LLEventTimer::Generic: public LLEventTimer
+{
+public:
+    // making TIME generic allows engaging either LLEventTimer constructor
+    template <typename TIME>
+    Generic(const TIME& time, bool once, const CALLABLE& callable):
+        LLEventTimer(time),
+        mOnce(once),
+        mCallable(callable)
+    {}
+    BOOL tick() override
+    {
+        mCallable();
+        // true tells updateClass() to delete this instance
+        return mOnce;
+    }
+
+private:
+    bool mOnce;
+    CALLABLE mCallable;
 };
 
+template <typename CALLABLE>
+LLEventTimer* LLEventTimer::run_every(F32 period, const CALLABLE& callable)
+{
+    // return false to schedule recurring calls
+    return new Generic<CALLABLE>(period, false, callable);
+}
+
+template <typename CALLABLE>
+LLEventTimer* LLEventTimer::run_at(const LLDate& time, const CALLABLE& callable)
+{
+    // return true for one-shot callback
+    return new Generic<CALLABLE>(time, true, callable);
+}
+
+template <typename CALLABLE>
+LLEventTimer* LLEventTimer::run_after(F32 interval, const CALLABLE& callable)
+{
+    // one-shot callback after specified interval
+    return new Generic<CALLABLE>(interval, true, callable);
+}
+
 #endif //LL_EVENTTIMER_H