diff options
-rw-r--r-- | include/mbgl/util/run_loop.hpp | 6 | ||||
-rw-r--r-- | include/mbgl/util/work_task.hpp | 6 | ||||
-rw-r--r-- | include/mbgl/util/work_task_impl.hpp | 24 | ||||
-rw-r--r-- | platform/android/src/asset_file_source.cpp | 2 | ||||
-rw-r--r-- | platform/default/asset_file_source.cpp | 2 | ||||
-rw-r--r-- | platform/default/default_file_source.cpp | 2 | ||||
-rw-r--r-- | src/mbgl/util/thread.hpp | 15 | ||||
-rw-r--r-- | src/mbgl/util/worker.cpp | 18 | ||||
-rw-r--r-- | test/util/thread.cpp | 28 |
9 files changed, 60 insertions, 43 deletions
diff --git a/include/mbgl/util/run_loop.hpp b/include/mbgl/util/run_loop.hpp index af1053dfdc..6559b72ef8 100644 --- a/include/mbgl/util/run_loop.hpp +++ b/include/mbgl/util/run_loop.hpp @@ -61,10 +61,10 @@ public: } // Invoke fn(args...) on this RunLoop, then invoke callback(results...) on the current RunLoop. - template <class Fn, class Cb, class... Args> + template <class Fn, class... Args> std::unique_ptr<AsyncRequest> - invokeWithCallback(Fn&& fn, Cb&& callback, Args&&... args) { - std::shared_ptr<WorkTask> task = WorkTask::makeWithCallback(std::forward<Fn>(fn), std::forward<Cb>(callback), std::forward<Args>(args)...); + invokeWithCallback(Fn&& fn, Args&&... args) { + std::shared_ptr<WorkTask> task = WorkTask::makeWithCallback(std::forward<Fn>(fn), std::forward<Args>(args)...); push(task); return std::make_unique<WorkRequest>(task); } diff --git a/include/mbgl/util/work_task.hpp b/include/mbgl/util/work_task.hpp index e9c2062d9c..dda8e5d00f 100644 --- a/include/mbgl/util/work_task.hpp +++ b/include/mbgl/util/work_task.hpp @@ -17,10 +17,10 @@ public: virtual void cancel() = 0; template <class Fn, class... Args> - static std::shared_ptr<WorkTask> make(Fn&& fn, Args&&... args); + static std::shared_ptr<WorkTask> make(Fn&&, Args&&...); - template <class Fn, class Cb, class... Args> - static std::shared_ptr<WorkTask> makeWithCallback(Fn&& fn, Cb&& callback, Args&&... args); + template <class Fn, class... Args> + static std::shared_ptr<WorkTask> makeWithCallback(Fn&&, Args&&...); }; } // namespace mbgl diff --git a/include/mbgl/util/work_task_impl.hpp b/include/mbgl/util/work_task_impl.hpp index 2c016601bb..a2f55e00c5 100644 --- a/include/mbgl/util/work_task_impl.hpp +++ b/include/mbgl/util/work_task_impl.hpp @@ -62,10 +62,12 @@ std::shared_ptr<WorkTask> WorkTask::make(Fn&& fn, Args&&... args) { flag); } -template <class Fn, class Cb, class... Args> -std::shared_ptr<WorkTask> WorkTask::makeWithCallback(Fn&& fn, Cb&& callback, Args&&... args) { - auto flag = std::make_shared<std::atomic<bool>>(); - *flag = false; +namespace detail { +template <class Tuple, size_t... Indexes> +auto packageArgumentsAndCallback(std::shared_ptr<std::atomic<bool>> flag, + Tuple&& args, + std::index_sequence<Indexes...>) { + auto callback = std::get<sizeof...(Indexes)>(args); // 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 @@ -82,7 +84,19 @@ std::shared_ptr<WorkTask> WorkTask::makeWithCallback(Fn&& fn, Cb&& callback, Arg } }; - auto tuple = std::make_tuple(std::move(args)..., after); + return std::make_tuple(std::move(std::get<Indexes>(args))..., after); +} +} // namespace detail + +template <class Fn, class... Args> +std::shared_ptr<WorkTask> WorkTask::makeWithCallback(Fn&& fn, Args&&... args) { + auto flag = std::make_shared<std::atomic<bool>>(); + *flag = false; + + auto tuple = detail::packageArgumentsAndCallback(flag, + std::forward_as_tuple(std::forward<Args>(args)...), + std::make_index_sequence<sizeof...(Args) - 1>()); + return std::make_shared<WorkTaskImpl<Fn, decltype(tuple)>>( std::move(fn), std::move(tuple), diff --git a/platform/android/src/asset_file_source.cpp b/platform/android/src/asset_file_source.cpp index ec4925a02e..c72b86af5c 100644 --- a/platform/android/src/asset_file_source.cpp +++ b/platform/android/src/asset_file_source.cpp @@ -107,7 +107,7 @@ AssetFileSource::AssetFileSource(const std::string& root) AssetFileSource::~AssetFileSource() = default; std::unique_ptr<AsyncRequest> AssetFileSource::request(const Resource& resource, Callback callback) { - return thread->invokeWithCallback(&Impl::request, callback, resource.url); + return thread->invokeWithCallback(&Impl::request, resource.url, callback); } } diff --git a/platform/default/asset_file_source.cpp b/platform/default/asset_file_source.cpp index 2872c6bb3a..1832818378 100644 --- a/platform/default/asset_file_source.cpp +++ b/platform/default/asset_file_source.cpp @@ -64,7 +64,7 @@ AssetFileSource::AssetFileSource(const std::string& root) AssetFileSource::~AssetFileSource() = default; std::unique_ptr<AsyncRequest> AssetFileSource::request(const Resource& resource, Callback callback) { - return thread->invokeWithCallback(&Impl::request, callback, resource.url); + return thread->invokeWithCallback(&Impl::request, resource.url, callback); } } // namespace mbgl diff --git a/platform/default/default_file_source.cpp b/platform/default/default_file_source.cpp index 6a94fa3866..9465728509 100644 --- a/platform/default/default_file_source.cpp +++ b/platform/default/default_file_source.cpp @@ -164,7 +164,7 @@ std::unique_ptr<AsyncRequest> DefaultFileSource::request(const Resource& resourc public: DefaultFileRequest(Resource resource_, FileSource::Callback callback_, util::Thread<DefaultFileSource::Impl>& thread_) : thread(thread_), - workRequest(thread.invokeWithCallback(&DefaultFileSource::Impl::request, callback_, this, resource_)) { + workRequest(thread.invokeWithCallback(&DefaultFileSource::Impl::request, this, resource_, callback_)) { } ~DefaultFileRequest() override { diff --git a/src/mbgl/util/thread.hpp b/src/mbgl/util/thread.hpp index 31a56a4834..91eef745fa 100644 --- a/src/mbgl/util/thread.hpp +++ b/src/mbgl/util/thread.hpp @@ -30,20 +30,23 @@ public: Thread(const ThreadContext&, Args&&... args); ~Thread(); - // Invoke object->fn(args...) in the runloop thread. + // Invoke object->fn(args...) asynchronously. template <typename Fn, class... Args> void invoke(Fn fn, Args&&... args) { loop->invoke(bind(fn), std::forward<Args>(args)...); } - // Invoke object->fn(args...) in the runloop thread, then invoke callback(result) in the current thread. - template <typename Fn, class Cb, class... Args> + // Invoke object->fn(args...) asynchronously. The final argument to fn must be a callback. + // The provided callback is wrapped such that it is invoked, in the current thread (which + // must have a RunLoop), once for each time the invocation of fn invokes the wrapper, each + // time forwarding the passed arguments, until such time as the AsyncRequest is cancelled. + template <typename Fn, class... Args> std::unique_ptr<AsyncRequest> - invokeWithCallback(Fn fn, Cb&& callback, Args&&... args) { - return loop->invokeWithCallback(bind(fn), callback, std::forward<Args>(args)...); + invokeWithCallback(Fn fn, Args&&... args) { + return loop->invokeWithCallback(bind(fn), std::forward<Args>(args)...); } - // Invoke object->fn(args...) in the runloop thread, and wait for the result. + // Invoke object->fn(args...) asynchronously, but wait for the result. template <typename Fn, class... Args> auto invokeSync(Fn fn, Args&&... args) { using R = std::result_of_t<Fn(Object, Args&&...)>; diff --git a/src/mbgl/util/worker.cpp b/src/mbgl/util/worker.cpp index e05a5cf837..f28e6e17b8 100644 --- a/src/mbgl/util/worker.cpp +++ b/src/mbgl/util/worker.cpp @@ -84,8 +84,8 @@ Worker::parseRasterTile(std::unique_ptr<RasterBucket> bucket, const std::shared_ptr<const std::string> data, std::function<void(RasterTileParseResult)> callback) { current = (current + 1) % threads.size(); - return threads[current]->invokeWithCallback(&Worker::Impl::parseRasterTile, callback, bucket, - data); + return threads[current]->invokeWithCallback(&Worker::Impl::parseRasterTile, bucket, + data, callback); } std::unique_ptr<AsyncRequest> @@ -95,8 +95,8 @@ Worker::parseGeometryTile(TileWorker& worker, PlacementConfig config, std::function<void(TileParseResult)> callback) { current = (current + 1) % threads.size(); - return threads[current]->invokeWithCallback(&Worker::Impl::parseGeometryTile, callback, &worker, - std::move(layers), std::move(tileData), config); + return threads[current]->invokeWithCallback(&Worker::Impl::parseGeometryTile, &worker, + std::move(layers), std::move(tileData), config, callback); } std::unique_ptr<AsyncRequest> @@ -105,7 +105,7 @@ Worker::parsePendingGeometryTileLayers(TileWorker& worker, std::function<void(TileParseResult)> callback) { current = (current + 1) % threads.size(); return threads[current]->invokeWithCallback(&Worker::Impl::parsePendingGeometryTileLayers, - callback, &worker, config); + &worker, config, callback); } std::unique_ptr<AsyncRequest> @@ -114,8 +114,8 @@ Worker::redoLayout(TileWorker& worker, PlacementConfig config, std::function<void(TileParseResult)> callback) { current = (current + 1) % threads.size(); - return threads[current]->invokeWithCallback(&Worker::Impl::redoLayout, callback, &worker, - std::move(layers), config); + return threads[current]->invokeWithCallback(&Worker::Impl::redoLayout, &worker, + std::move(layers), config, callback); } std::unique_ptr<AsyncRequest> @@ -124,8 +124,8 @@ Worker::redoPlacement(TileWorker& worker, PlacementConfig config, std::function<void(std::unique_ptr<CollisionTile>)> callback) { current = (current + 1) % threads.size(); - return threads[current]->invokeWithCallback(&Worker::Impl::redoPlacement, callback, &worker, - &buckets, config); + return threads[current]->invokeWithCallback(&Worker::Impl::redoPlacement, &worker, + &buckets, config, callback); } } // end namespace mbgl diff --git a/test/util/thread.cpp b/test/util/thread.cpp index bf76ec4aef..fc41fd4b78 100644 --- a/test/util/thread.cpp +++ b/test/util/thread.cpp @@ -83,10 +83,10 @@ TEST(Thread, invoke) { EXPECT_EQ(*result, 1); })); - requests.push_back(thread.invokeWithCallback(&TestObject::transferInOut, [&] (std::unique_ptr<int> result) { + requests.push_back(thread.invokeWithCallback(&TestObject::transferInOut, std::make_unique<int>(1), [&] (std::unique_ptr<int> result) { EXPECT_EQ(tid, std::this_thread::get_id()); EXPECT_EQ(*result, 1); - }, std::make_unique<int>(1))); + })); thread.invoke(&TestObject::transferInShared, std::make_shared<int>(1)); requests.push_back(thread.invokeWithCallback(&TestObject::transferOutShared, [&] (std::shared_ptr<int> result) { @@ -100,11 +100,11 @@ TEST(Thread, invoke) { }); std::string test("test"); - requests.push_back(thread.invokeWithCallback(&TestObject::transferString, [&] (std::string result){ + requests.push_back(thread.invokeWithCallback(&TestObject::transferString, test, [&] (std::string result){ EXPECT_EQ(tid, std::this_thread::get_id()); EXPECT_EQ(result, "test"); loop.stop(); - }, test)); + })); test.clear(); }); @@ -147,10 +147,10 @@ TEST(Thread, ExecutesAfter) { bool didAfter = false; auto request = thread.invokeWithCallback(&TestWorker::send, [&] { + didWork = true; + }, [&] { didAfter = true; loop.stop(); - }, [&] { - didWork = true; }); loop.run(); @@ -167,11 +167,11 @@ TEST(Thread, WorkRequestDeletionWaitsForWorkToComplete) { std::promise<void> started; bool didWork = false; - auto request = thread.invokeWithCallback(&TestWorker::send, [&] {}, [&] { + auto request = thread.invokeWithCallback(&TestWorker::send, [&] { started.set_value(); usleep(10000); didWork = true; - }); + }, [&] {}); started.get_future().get(); request.reset(); @@ -186,9 +186,9 @@ TEST(Thread, WorkRequestDeletionCancelsAfter) { bool didAfter = false; auto request = thread.invokeWithCallback(&TestWorker::send, [&] { - didAfter = true; - }, [&] { started.set_value(); + }, [&] { + didAfter = true; }); started.get_future().get(); @@ -203,14 +203,14 @@ TEST(Thread, WorkRequestDeletionCancelsImmediately) { std::promise<void> started; - auto request1 = thread.invokeWithCallback(&TestWorker::send, [&] {}, [&] { + auto request1 = thread.invokeWithCallback(&TestWorker::send, [&] { usleep(10000); started.set_value(); - }); + }, [&] {}); - auto request2 = thread.invokeWithCallback(&TestWorker::send, [&] {}, [&] { + auto request2 = thread.invokeWithCallback(&TestWorker::send, [&] { ADD_FAILURE() << "Second work item should not be invoked"; - }); + }, [&] {}); request2.reset(); started.get_future().get(); |