From e4995e8d3a38dfd2ed64337e712ecf701af37454 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Fri, 2 Sep 2016 16:52:25 -0700 Subject: [core] Extract WorkTaskImpl from run_loop.hpp --- include/mbgl/util/work_task_impl.hpp | 92 ++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 include/mbgl/util/work_task_impl.hpp (limited to 'include/mbgl/util/work_task_impl.hpp') diff --git a/include/mbgl/util/work_task_impl.hpp b/include/mbgl/util/work_task_impl.hpp new file mode 100644 index 0000000000..2c016601bb --- /dev/null +++ b/include/mbgl/util/work_task_impl.hpp @@ -0,0 +1,92 @@ +#pragma once + +#include +#include + +#include + +namespace mbgl { + +template +class WorkTaskImpl : public WorkTask { +public: + WorkTaskImpl(F&& f, P&& p, std::shared_ptr> canceled_) + : canceled(std::move(canceled_)), + func(std::move(f)), + params(std::move(p)) { + } + + void operator()() override { + // Lock the mutex while processing so that cancel() will block. + std::lock_guard lock(mutex); + if (!*canceled) { + invoke(std::make_index_sequence::value>{}); + } + } + + // If the task has not yet begun, this will cancel it. + // If the task is in progress, this will block until it completed. (Currently + // necessary because of shared state, but should be removed.) It will also + // cancel the after callback. + // If the task has completed, but the after callback has not executed, this + // will cancel the after callback. + // If the task has completed and the after callback has executed, this will + // do nothing. + void cancel() override { + std::lock_guard lock(mutex); + *canceled = true; + } + +private: + template + void invoke(std::index_sequence) { + func(std::move(std::get(std::forward

(params)))...); + } + + std::recursive_mutex mutex; + std::shared_ptr> canceled; + + F func; + P params; +}; + +template +std::shared_ptr WorkTask::make(Fn&& fn, Args&&... args) { + auto flag = std::make_shared>(); + *flag = false; + + auto tuple = std::make_tuple(std::move(args)...); + return std::make_shared>( + std::move(fn), + std::move(tuple), + flag); +} + +template +std::shared_ptr WorkTask::makeWithCallback(Fn&& fn, Cb&& callback, Args&&... args) { + auto flag = std::make_shared>(); + *flag = false; + + // Create a lambda L1 that invokes another lambda L2 on the current RunLoop R, that calls + // the callback C. Both lambdas check the flag before proceeding. L1 needs to check the flag + // because if the request was cancelled, then R might have been destroyed. L2 needs to check + // the flag because the request may have been cancelled after L2 was invoked but before it + // began executing. + auto after = [flag, current = util::RunLoop::Get(), callback1 = std::move(callback)] (auto&&... results1) { + if (!*flag) { + current->invoke([flag, callback2 = std::move(callback1)] (auto&&... results2) { + if (!*flag) { + callback2(std::move(results2)...); + } + }, std::move(results1)...); + } + }; + + auto tuple = std::make_tuple(std::move(args)..., after); + return std::make_shared>( + std::move(fn), + std::move(tuple), + flag); +} + +} // namespace mbgl -- cgit v1.2.1