diff options
author | Thiago Marcos P. Santos <thiago@mapbox.com> | 2016-07-06 16:57:20 +0300 |
---|---|---|
committer | Thiago Marcos P. Santos <thiago@mapbox.com> | 2016-07-06 17:43:19 +0300 |
commit | 480e26c53f48900c5a1bd65aac7411144043cc24 (patch) | |
tree | 61cf455917385ec5c4963075a7af18e5a87a6bb1 | |
parent | 2425cf4ef839bbeec82403ea0bf8b74e68ca0ac8 (diff) | |
download | qtlocation-mapboxgl-480e26c53f48900c5a1bd65aac7411144043cc24.tar.gz |
[android] Add support for timers on the main thread
Wake up the main thread run loop with a file descriptor event from a
thread that exists for this sole purpose.
-rw-r--r-- | platform/android/src/run_loop.cpp | 33 | ||||
-rw-r--r-- | platform/android/src/run_loop_impl.hpp | 5 |
2 files changed, 36 insertions, 2 deletions
diff --git a/platform/android/src/run_loop.cpp b/platform/android/src/run_loop.cpp index 886dcab898..007ea29192 100644 --- a/platform/android/src/run_loop.cpp +++ b/platform/android/src/run_loop.cpp @@ -2,12 +2,14 @@ #include <mbgl/util/thread_context.hpp> #include <mbgl/util/thread_local.hpp> +#include <mbgl/util/timer.hpp> #include <android/looper.h> #include <algorithm> #include <cassert> #include <functional> +#include <memory> #include <stdexcept> #include <vector> @@ -53,6 +55,24 @@ int looperCallbackDefault(int fd, int, void* data) { namespace mbgl { namespace util { +// This is needed only for the RunLoop living on the main thread because of +// how we implement timers. We sleep on `ALooper_pollAll` until the next +// timeout, but on the main thread `ALooper_pollAll` is called by the activity +// automatically, thus we cannot set the timeout. Instead we wake the loop +// with an external file descriptor event coming from this thread. +class Alarm { +public: + Alarm(RunLoop::Impl* loop_) : loop(loop_) {} + + void set(const Milliseconds& timeout) { + alarm.start(timeout, mbgl::Duration::zero(), [this]() { loop->wake(); }); + } + +private: + Timer alarm; + RunLoop::Impl* loop; +}; + RunLoop::Impl::Impl(RunLoop* runLoop_, RunLoop::Type type) : runLoop(runLoop_) { using namespace mbgl::android; detach = attach_jni_thread(theJVM, &env, ""); @@ -80,6 +100,8 @@ RunLoop::Impl::Impl(RunLoop* runLoop_, RunLoop::Type type) : runLoop(runLoop_) { case Type::Default: ret = ALooper_addFd(loop, fds[PIPE_OUT], ALOOPER_POLL_CALLBACK, ALOOPER_EVENT_INPUT, looperCallbackDefault, this); + alarm = std::make_unique<Thread<Alarm>>(ThreadContext{"Alarm"}, this); + running = true; break; } @@ -89,6 +111,8 @@ RunLoop::Impl::Impl(RunLoop* runLoop_, RunLoop::Type type) : runLoop(runLoop_) { } RunLoop::Impl::~Impl() { + alarm.reset(); + if (ALooper_removeFd(loop, fds[PIPE_OUT]) != 1) { throw std::runtime_error("Failed to remove file descriptor from Looper."); } @@ -160,9 +184,14 @@ Milliseconds RunLoop::Impl::processRunnables() { if (runnables.empty() || nextDue == TimePoint::max()) { return Milliseconds(-1); - } else { - return std::chrono::duration_cast<Milliseconds>(nextDue - now); } + + auto timeout = std::chrono::duration_cast<Milliseconds>(nextDue - now); + if (alarm) { + alarm->invoke(&Alarm::set, timeout); + } + + return timeout; } RunLoop* RunLoop::Get() { diff --git a/platform/android/src/run_loop_impl.hpp b/platform/android/src/run_loop_impl.hpp index cb553d1f8a..121a5127d1 100644 --- a/platform/android/src/run_loop_impl.hpp +++ b/platform/android/src/run_loop_impl.hpp @@ -5,6 +5,7 @@ #include <mbgl/util/atomic.hpp> #include <mbgl/util/chrono.hpp> #include <mbgl/util/run_loop.hpp> +#include <mbgl/util/thread.hpp> #include <list> #include <memory> @@ -15,6 +16,8 @@ struct ALooper; namespace mbgl { namespace util { +class Alarm; + class RunLoop::Impl { public: class Runnable { @@ -50,6 +53,8 @@ private: JNIEnv *env = nullptr; bool detach = false; + std::unique_ptr<Thread<Alarm>> alarm; + std::recursive_mutex mtx; std::list<Runnable*> runnables; std::list<Runnable*>::iterator nextRunnable; |