summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mbgl/util/run_loop.hpp12
-rw-r--r--test/util/run_loop.test.cpp49
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();
+}