summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--platform/android/src/run_loop.cpp110
-rw-r--r--platform/android/src/run_loop_impl.hpp7
2 files changed, 95 insertions, 22 deletions
diff --git a/platform/android/src/run_loop.cpp b/platform/android/src/run_loop.cpp
index e05d27a088..4bd0480219 100644
--- a/platform/android/src/run_loop.cpp
+++ b/platform/android/src/run_loop.cpp
@@ -8,18 +8,101 @@
#include <algorithm>
#include <cassert>
#include <functional>
+#include <stdexcept>
#include <vector>
+#include <fcntl.h>
+#include <unistd.h>
+
+#define PIPE_OUT 0
+#define PIPE_IN 1
+
namespace {
using namespace mbgl::util;
static ThreadLocal<RunLoop>& current = *new ThreadLocal<RunLoop>;
+int looperCallbackNew(int fd, int, void* data) {
+ int buffer[1];
+ while (read(fd, buffer, sizeof(buffer)) > 0) {}
+
+ auto loop = reinterpret_cast<ALooper*>(data);
+ ALooper_wake(loop);
+
+ return 1;
+}
+
+int looperCallbackDefault(int fd, int, void* data) {
+ int buffer[1];
+ while (read(fd, buffer, sizeof(buffer)) > 0) {}
+
+ auto runLoop = reinterpret_cast<RunLoop*>(data);
+ runLoop->runOnce();
+
+ return 1;
+}
+
} // namespace
namespace mbgl {
namespace util {
+RunLoop::Impl::Impl(RunLoop* runLoop, RunLoop::Type type) {
+ using namespace mbgl::android;
+ detach = attach_jni_thread(theJVM, &env, ThreadContext::getName());
+
+ loop = ALooper_prepare(0);
+ assert(loop);
+
+ ALooper_acquire(loop);
+
+ if (pipe(fds)) {
+ throw std::runtime_error("Failed to create pipe.");
+ }
+
+ if (fcntl(fds[PIPE_OUT], F_SETFL, O_NONBLOCK)) {
+ throw std::runtime_error("Failed to set pipe read end non-blocking.");
+ }
+
+ int ret = 0;
+
+ switch (type) {
+ case Type::New:
+ ret = ALooper_addFd(loop, fds[PIPE_OUT], ALOOPER_POLL_CALLBACK,
+ ALOOPER_EVENT_INPUT, looperCallbackNew, loop);
+ break;
+ case Type::Default:
+ ret = ALooper_addFd(loop, fds[PIPE_OUT], ALOOPER_POLL_CALLBACK,
+ ALOOPER_EVENT_INPUT, looperCallbackDefault, runLoop);
+ break;
+ }
+
+ if (ret != 1) {
+ throw std::runtime_error("Failed to add file descriptor to Looper.");
+ }
+}
+
+RunLoop::Impl::~Impl() {
+ if (ALooper_removeFd(loop, fds[PIPE_OUT]) != 1) {
+ throw std::runtime_error("Failed to remove file descriptor from Looper.");
+ }
+
+ if (close(fds[PIPE_IN]) || close(fds[PIPE_OUT])) {
+ throw std::runtime_error("Failed to close file descriptor.");
+ }
+
+ ALooper_release(loop);
+
+ using namespace mbgl::android;
+ detach_jni_thread(theJVM, &env, detach);
+}
+
+void RunLoop::Impl::wake() {
+ if (write(fds[PIPE_IN], "\n", 1) == -1) {
+ throw std::runtime_error("Failed to write to file descriptor.");
+ }
+}
+
void RunLoop::Impl::addRunnable(Runnable* runnable) {
std::lock_guard<std::recursive_mutex> lock(mtx);
@@ -28,7 +111,7 @@ void RunLoop::Impl::addRunnable(Runnable* runnable) {
runnable->iter = std::move(iter);
}
- ALooper_wake(loop);
+ wake();
}
void RunLoop::Impl::removeRunnable(Runnable* runnable) {
@@ -74,25 +157,12 @@ RunLoop* RunLoop::Get() {
return current.get();
}
-RunLoop::RunLoop(Type) : impl(std::make_unique<Impl>()) {
- using namespace mbgl::android;
- impl->detach = attach_jni_thread(theJVM, &impl->env, ThreadContext::getName());
-
- impl->loop = ALooper_prepare(0);
- assert(impl->loop);
-
- ALooper_acquire(impl->loop);
-
+RunLoop::RunLoop(Type type) : impl(std::make_unique<Impl>(this, type)) {
current.set(this);
}
RunLoop::~RunLoop() {
current.set(nullptr);
-
- ALooper_release(impl->loop);
-
- using namespace mbgl::android;
- detach_jni_thread(theJVM, &impl->env, impl->detach);
}
LOOP_HANDLE RunLoop::getLoopHandle() {
@@ -101,7 +171,7 @@ LOOP_HANDLE RunLoop::getLoopHandle() {
void RunLoop::push(std::shared_ptr<WorkTask> task) {
withMutex([&] { queue.push(std::move(task)); });
- ALooper_wake(impl->loop);
+ impl->wake();
}
void RunLoop::run() {
@@ -122,17 +192,13 @@ void RunLoop::run() {
void RunLoop::runOnce() {
MBGL_VERIFY_THREAD(tid);
- int outFd, outEvents;
- char *outData = nullptr;
-
process();
- impl->processRunnables().count();
- ALooper_pollOnce(0, &outFd, &outEvents, reinterpret_cast<void**>(&outData));
+ impl->processRunnables();
}
void RunLoop::stop() {
impl->running = false;
- ALooper_wake(impl->loop);
+ impl->wake();
}
void RunLoop::addWatch(int, Event, std::function<void(int, Event)>&&) {
diff --git a/platform/android/src/run_loop_impl.hpp b/platform/android/src/run_loop_impl.hpp
index 2dd912994f..5cf7231175 100644
--- a/platform/android/src/run_loop_impl.hpp
+++ b/platform/android/src/run_loop_impl.hpp
@@ -27,6 +27,11 @@ public:
std::list<Runnable*>::iterator iter;
};
+ Impl(RunLoop*, RunLoop::Type);
+ ~Impl();
+
+ void wake();
+
void addRunnable(Runnable*);
void removeRunnable(Runnable*);
void initRunnable(Runnable*);
@@ -36,6 +41,8 @@ public:
private:
friend RunLoop;
+ int fds[2];
+
JNIEnv *env = nullptr;
bool detach = false;