diff options
Diffstat (limited to 'indra')
-rw-r--r-- | indra/llcommon/llmainthreadtask.h | 58 | ||||
-rw-r--r-- | indra/llcommon/workqueue.h | 40 |
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)); |