From 1da0b751de51e6654813f59e03a8d1bde67f6e8a Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Wed, 11 Mar 2020 01:31:13 +0200 Subject: [core] Add a callback for platform RunLoop integration Platform integration callback for platforms that do not have full run loop integration or don't want to block at the Mapbox GL Native loop. It will be called from any thread and is up to the platform to, after receiving the callback, call RunLoop::runOnce() from the same thread as the Map object lives. --- include/mbgl/util/run_loop.hpp | 12 +++++++++++ test/util/run_loop.test.cpp | 49 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/include/mbgl/util/run_loop.hpp b/include/mbgl/util/run_loop.hpp index 5cde95a531..c89b8bd795 100644 --- a/include/mbgl/util/run_loop.hpp +++ b/include/mbgl/util/run_loop.hpp @@ -48,6 +48,15 @@ public: void runOnce(); void stop(); + using PlatformCallback = std::function; + + // Platform integration callback for platforms that do not have full + // run loop integration or don't want to block at the Mapbox GL Native + // loop. It will be called from any thread and is up to the platform + // to, after receiving the callback, call RunLoop::runOnce() from the + // same thread as the Map object lives. + void setPlatformCallback(PlatformCallback&& callback) { platformCallback = std::move(callback); } + // So far only needed by the libcurl backend. void addWatch(int fd, Event, std::function&& callback); void removeWatch(int fd); @@ -95,6 +104,7 @@ private: defaultQueue.emplace(std::move(task)); } wake(); + platformCallback(); } void process() { @@ -117,6 +127,8 @@ private: } } + PlatformCallback platformCallback = [] {}; + Queue defaultQueue; Queue highPriorityQueue; std::mutex mutex; diff --git a/test/util/run_loop.test.cpp b/test/util/run_loop.test.cpp index 4d2c704421..62bfbb0fc1 100644 --- a/test/util/run_loop.test.cpp +++ b/test/util/run_loop.test.cpp @@ -3,6 +3,10 @@ #include +#include +#include +#include + using namespace mbgl::util; TEST(RunLoop, Stop) { @@ -64,3 +68,48 @@ TEST(RunLoop, Priorities) { EXPECT_EQ((std::vector{ 2, 4, 1, 3 }), order); } + +TEST(RunLoop, PlatformIntegration) { + std::atomic count1(0); + + // No need to be atomic, it will run + // on the main thread. + int count2(0); + + std::thread::id mainThread = std::this_thread::get_id(); + + RunLoop loop; + + std::mutex mutex; + std::condition_variable cv; + + loop.setPlatformCallback([&] { + EXPECT_NE(mainThread, std::this_thread::get_id()); + count1++; + cv.notify_one(); + }); + + auto threadBody = [&]() { + for (unsigned i = 0; i < 100000; ++i) { + loop.invoke([&] { + EXPECT_EQ(mainThread, std::this_thread::get_id()); + count2++; + }); + } + }; + + std::thread thread1(threadBody); + std::thread thread2(threadBody); + + while (count2 < 200000) { + std::unique_lock lock(mutex); + cv.wait(lock); + loop.runOnce(); + } + + EXPECT_EQ(count1, 200000); + EXPECT_EQ(count2, 200000); + + thread1.join(); + thread2.join(); +} -- cgit v1.2.1