summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/llcommon/llmainthreadtask.h58
-rw-r--r--indra/llcommon/workqueue.h40
2 files changed, 43 insertions, 55 deletions
diff --git a/indra/llcommon/llmainthreadtask.h b/indra/llcommon/llmainthreadtask.h
index d509b687c0..dde6c20210 100644
--- a/indra/llcommon/llmainthreadtask.h
+++ b/indra/llcommon/llmainthreadtask.h
@@ -13,11 +13,8 @@
#if ! defined(LL_LLMAINTHREADTASK_H)
#define LL_LLMAINTHREADTASK_H
-#include "lleventtimer.h"
#include "llthread.h"
-#include "llmake.h"
-#include <future>
-#include <type_traits> // std::result_of
+#include "workqueue.h"
/**
* LLMainThreadTask provides a way to perform some task specifically on the
@@ -28,18 +25,17 @@
* Instead of instantiating LLMainThreadTask, pass your invocable to its
* static dispatch() method. dispatch() returns the result of calling your
* task. (Or, if your task throws an exception, dispatch() throws that
- * exception. See std::packaged_task.)
+ * exception.)
*
* When you call dispatch() on the main thread (as determined by
* on_main_thread() in llthread.h), it simply calls your task and returns the
* result.
*
- * When you call dispatch() on a secondary thread, it instantiates an
- * LLEventTimer subclass scheduled immediately. Next time the main loop calls
- * LLEventTimer::updateClass(), your task will be run, and LLMainThreadTask
- * will fulfill a future with its result. Meanwhile the requesting thread
- * blocks on that future. As soon as it is set, the requesting thread wakes up
- * with the task result.
+ * When you call dispatch() on a secondary thread, it posts your task to
+ * gMainloopWork, the WorkQueue serviced by the main thread, using
+ * WorkQueue::waitForResult() to block the caller. Next time the main loop
+ * calls gMainloopWork.runFor(), your task will be run, and waitForResult()
+ * will return its result.
*/
class LLMainThreadTask
{
@@ -59,41 +55,15 @@ public:
}
else
{
- // It's essential to construct LLEventTimer subclass instances on
- // the heap because, on completion, LLEventTimer deletes them.
- // Once we enable C++17, we can use Class Template Argument
- // Deduction. Until then, use llmake_heap().
- auto* task = llmake_heap<Task>(std::forward<CALLABLE>(callable));
- auto future = task->mTask.get_future();
- // Now simply block on the future.
- return future.get();
+ auto queue{ LL::WorkQueue::getInstance("mainloop") };
+ // If this needs a null check and a message, please introduce a
+ // method in the .cpp file so consumers of this header don't drag
+ // in llerror.h.
+ // Use waitForResult_() so dispatch() can be used even from the
+ // calling thread's default coroutine.
+ return queue->waitForResult_(std::forward<CALLABLE>(callable));
}
}
-
-private:
- template <typename CALLABLE>
- struct Task: public LLEventTimer
- {
- Task(CALLABLE&& callable):
- // no wait time: call tick() next chance we get
- LLEventTimer(0),
- mTask(std::forward<CALLABLE>(callable))
- {}
- BOOL tick() override
- {
- // run the task on the main thread, will populate the future
- // obtained by get_future()
- mTask();
- // tell LLEventTimer we're done (one shot)
- return TRUE;
- }
- // Given arbitrary CALLABLE, which might be a lambda, how are we
- // supposed to obtain its signature for std::packaged_task? It seems
- // redundant to have to add an argument list to engage result_of, then
- // add the argument list again to complete the signature. At least we
- // only support a nullary CALLABLE.
- std::packaged_task<typename std::result_of<CALLABLE()>::type()> mTask;
- };
};
#endif /* ! defined(LL_LLMAINTHREADTASK_H) */
diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h
index 70fd65bd0c..20fd15d0d5 100644
--- a/indra/llcommon/workqueue.h
+++ b/indra/llcommon/workqueue.h
@@ -12,7 +12,6 @@
#if ! defined(LL_WORKQUEUE_H)
#define LL_WORKQUEUE_H
-#include "llcoros.h"
#include "llexception.h"
#include "llinstancetracker.h"
#include "threadsafeschedule.h"
@@ -200,31 +199,51 @@ namespace LL
}
/**
- * Post work to another WorkQueue to be run at a specified time,
- * blocking the calling coroutine until then, returning the result to
- * caller on completion.
+ * Post work, blocking the calling coroutine until then, returning the
+ * result to caller on completion.
*
* In general, we assume that each thread's default coroutine is busy
* servicing its WorkQueue or whatever. To try to prevent mistakes, we
* forbid calling waitForResult() from a thread's default coroutine.
*/
template <typename CALLABLE>
- auto waitForResult(const TimePoint& time, CALLABLE&& callable);
+ auto waitForResult(CALLABLE&& callable)
+ {
+ return waitForResult(TimePoint::clock::now(), std::forward<CALLABLE>(callable));
+ }
/**
- * Post work to another WorkQueue, blocking the calling coroutine
- * until then, returning the result to caller on completion.
+ * Post work to be run at a specified time, blocking the calling
+ * coroutine until then, returning the result to caller on completion.
*
* In general, we assume that each thread's default coroutine is busy
* servicing its WorkQueue or whatever. To try to prevent mistakes, we
* forbid calling waitForResult() from a thread's default coroutine.
*/
template <typename CALLABLE>
- auto waitForResult(CALLABLE&& callable)
+ auto waitForResult(const TimePoint& time, CALLABLE&& callable)
{
- return waitForResult(TimePoint::clock::now(), std::move(callable));
+ checkCoroutine("waitForResult()");
+ return waitForResult_(time, std::forward<CALLABLE>(callable));
}
+ /**
+ * Post work, blocking the calling coroutine until then, returning the
+ * result to caller on completion.
+ */
+ template <typename CALLABLE>
+ auto waitForResult_(CALLABLE&& callable)
+ {
+ return waitForResult_(TimePoint::clock::now(), std::forward<CALLABLE>(callable));
+ }
+
+ /**
+ * Post work to be run at a specified time, blocking the calling
+ * coroutine until then, returning the result to caller on completion.
+ */
+ template <typename CALLABLE>
+ auto waitForResult_(const TimePoint& time, CALLABLE&& callable);
+
/*--------------------------- worker API ---------------------------*/
/**
@@ -561,9 +580,8 @@ namespace LL
};
template <typename CALLABLE>
- auto WorkQueue::waitForResult(const TimePoint& time, CALLABLE&& callable)
+ auto WorkQueue::waitForResult_(const TimePoint& time, CALLABLE&& callable)
{
- checkCoroutine("waitForResult()");
// derive callable's return type so we can specialize for void
return WaitForResult<CALLABLE, decltype(std::forward<CALLABLE>(callable)())>()
(this, time, std::forward<CALLABLE>(callable));