summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThiago Marcos P. Santos <thiago@mapbox.com>2016-07-06 16:57:20 +0300
committerThiago Marcos P. Santos <thiago@mapbox.com>2016-07-06 17:43:19 +0300
commit480e26c53f48900c5a1bd65aac7411144043cc24 (patch)
tree61cf455917385ec5c4963075a7af18e5a87a6bb1
parent2425cf4ef839bbeec82403ea0bf8b74e68ca0ac8 (diff)
downloadqtlocation-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.cpp33
-rw-r--r--platform/android/src/run_loop_impl.hpp5
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;