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.
116 lines
2.5 KiB
C++
116 lines
2.5 KiB
C++
#include <mbgl/util/run_loop.hpp>
|
|
#include <mbgl/util/timer.hpp>
|
|
|
|
#include <mbgl/test/util.hpp>
|
|
|
|
#include <atomic>
|
|
#include <condition_variable>
|
|
#include <thread>
|
|
|
|
using namespace mbgl::util;
|
|
|
|
TEST(RunLoop, Stop) {
|
|
RunLoop loop(RunLoop::Type::New);
|
|
|
|
Timer timer;
|
|
timer.start(mbgl::Duration::zero(), mbgl::Duration::zero(), [&] {
|
|
loop.stop();
|
|
});
|
|
|
|
loop.run();
|
|
}
|
|
|
|
TEST(RunLoop, MultipleStop) {
|
|
RunLoop loop(RunLoop::Type::New);
|
|
|
|
Timer timer;
|
|
timer.start(mbgl::Duration::zero(), mbgl::Duration::zero(), [&] {
|
|
loop.stop();
|
|
loop.stop();
|
|
loop.stop();
|
|
loop.stop();
|
|
});
|
|
|
|
loop.run();
|
|
}
|
|
|
|
TEST(RunLoop, MultipleRun) {
|
|
RunLoop loop(RunLoop::Type::New);
|
|
|
|
Timer timer;
|
|
timer.start(mbgl::Duration::zero(), mbgl::Duration::zero(), [&] {
|
|
loop.stop();
|
|
});
|
|
|
|
loop.run();
|
|
|
|
bool secondTimeout = false;
|
|
timer.start(mbgl::Duration::zero(), mbgl::Duration::zero(), [&] {
|
|
secondTimeout = true;
|
|
loop.stop();
|
|
});
|
|
|
|
loop.run();
|
|
|
|
EXPECT_TRUE(secondTimeout);
|
|
}
|
|
|
|
TEST(RunLoop, Priorities) {
|
|
std::vector<int> order;
|
|
|
|
RunLoop loop(RunLoop::Type::New);
|
|
loop.invoke([&] { order.push_back(1); });
|
|
loop.invoke(RunLoop::Priority::High, [&] { order.push_back(2); });
|
|
loop.invoke([&] { order.push_back(3); });
|
|
loop.invoke(RunLoop::Priority::High, [&] { order.push_back(4); });
|
|
loop.invoke(RunLoop::Priority::Default, [&] { loop.stop(); });
|
|
loop.run();
|
|
|
|
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();
|
|
}
|