diff options
-rw-r--r-- | include/mbgl/util/run_loop.hpp | 12 | ||||
-rw-r--r-- | test/util/run_loop.test.cpp | 49 |
2 files changed, 61 insertions, 0 deletions
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<void()>; + + // 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<void(int, Event)>&& 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 <mbgl/test/util.hpp> +#include <atomic> +#include <condition_variable> +#include <thread> + using namespace mbgl::util; TEST(RunLoop, Stop) { @@ -64,3 +68,48 @@ TEST(RunLoop, Priorities) { EXPECT_EQ((std::vector<int>{ 2, 4, 1, 3 }), order); } + +TEST(RunLoop, PlatformIntegration) { + std::atomic<int> 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<std::mutex> lock(mutex); + cv.wait(lock); + loop.runOnce(); + } + + EXPECT_EQ(count1, 200000); + EXPECT_EQ(count2, 200000); + + thread1.join(); + thread2.join(); +} |