summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/curl_request.cpp2
-rw-r--r--common/glfw_view.cpp102
-rw-r--r--common/glfw_view.hpp7
-rw-r--r--include/llmr/platform/platform.hpp3
-rw-r--r--linux/llmr-app.gyp4
-rw-r--r--linux/main.cpp62
-rw-r--r--linux/request.cpp119
-rw-r--r--linux/request.hpp50
-rw-r--r--macosx/main.mm38
9 files changed, 107 insertions, 280 deletions
diff --git a/common/curl_request.cpp b/common/curl_request.cpp
index dc9db0269c..7cfe8fcabd 100644
--- a/common/curl_request.cpp
+++ b/common/curl_request.cpp
@@ -341,6 +341,8 @@ void async_cancel_cb(uv_async_t * /*async*/) {
}
void thread_init_cb() {
+ curl_global_init(CURL_GLOBAL_ALL);
+
loop = uv_loop_new();
uv_async_init(loop, &async_add, async_add_cb);
uv_async_init(loop, &async_cancel, async_cancel_cb);
diff --git a/common/glfw_view.cpp b/common/glfw_view.cpp
index c4fafb69ac..82e9aad745 100644
--- a/common/glfw_view.cpp
+++ b/common/glfw_view.cpp
@@ -1,7 +1,40 @@
#include "glfw_view.hpp"
+
+#ifndef HAVE_KQUEUE
+# if defined(__APPLE__) || \
+ defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__OpenBSD__) || \
+ defined(__NetBSD__)
+# define HAVE_KQUEUE 1
+# endif
+#endif
+
+#ifndef HAVE_EPOLL
+# if defined(__linux__)
+# define HAVE_EPOLL 1
+# endif
+#endif
+
+#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
+
+#if defined(HAVE_KQUEUE)
+# include <sys/types.h>
+# include <sys/event.h>
+# include <sys/time.h>
+#endif
+
+#if defined(HAVE_EPOLL)
+# include <sys/epoll.h>
+#endif
+
+#endif
+
+
MapView::MapView(llmr::Settings &settings, bool fullscreen)
- : fullscreen(fullscreen), settings(settings), map(settings) {}
+ : fullscreen(fullscreen), settings(settings), map(settings),
+ stop_event_listener(false) {}
MapView::~MapView() { glfwTerminate(); }
@@ -163,28 +196,70 @@ void MapView::mousemove(GLFWwindow *window, double x, double y) {
mapView->last_y = y;
}
+void MapView::eventloop(void *arg) {
+ MapView *view = static_cast<MapView *>(arg);
+ int r = 0;
+ int fd = 0;
+ int timeout;
+
+ while (!view->stop_event_listener) {
+ fd = uv_backend_fd(uv_default_loop());
+ timeout = uv_backend_timeout(uv_default_loop());
+
+ do {
+#if defined(HAVE_KQUEUE)
+ struct timespec ts;
+ ts.tv_sec = timeout / 1000;
+ ts.tv_nsec = (timeout % 1000) * 1000000;
+ r = kevent(fd, NULL, 0, NULL, 0, &ts);
+#elif defined(HAVE_EPOLL)
+ {
+ struct epoll_event ev;
+ r = epoll_wait(fd, &ev, 1, timeout);
+ }
+#endif
+ } while (r == -1 && errno == EINTR);
+ glfwPostEmptyEvent();
+ uv_sem_wait(&view->event_listener);
+ }
+}
+
int MapView::run() {
+ uv_thread_t embed_thread;
+
+ uv_run(uv_default_loop(), UV_RUN_NOWAIT);
+
+ /* Start worker that will interrupt external loop */
+ stop_event_listener = false;
+ uv_sem_init(&event_listener, 0);
+ uv_thread_create(&embed_thread, eventloop, this);
+
while (!glfwWindowShouldClose(window)) {
- llmr::platform::cleanup();
- if (dirty) {
- try {
- dirty = map.render();
- }
- catch (std::exception &ex) {
- fprintf(stderr, "exception: %s\n", ex.what());
- }
- glfwSwapBuffers(window);
- fps();
+ bool dirty = false;
+ try {
+ dirty = map.render();
}
+ catch (std::exception &ex) {
+ fprintf(stderr, "exception: %s\n", ex.what());
+ }
+ glfwSwapBuffers(window);
+ fps();
if (dirty) {
glfwPollEvents();
} else {
glfwWaitEvents();
}
+
+ uv_run(uv_default_loop(), UV_RUN_NOWAIT);
+ uv_sem_post(&event_listener);
}
+ stop_event_listener = true;
+
+ uv_thread_join(&embed_thread);
+
return 0;
}
@@ -234,5 +309,10 @@ void show_debug_image(std::string name, const char *data, size_t width, size_t h
glfwMakeContextCurrent(current_window);
}
+
+void restart() {
+ glfwPostEmptyEvent();
+}
+
}
}
diff --git a/common/glfw_view.hpp b/common/glfw_view.hpp
index d72debb11d..8647c8ad67 100644
--- a/common/glfw_view.hpp
+++ b/common/glfw_view.hpp
@@ -3,6 +3,7 @@
#include <llmr/llmr.hpp>
#include <GLFW/glfw3.h>
+#include <uv.h>
class MapView {
public:
@@ -17,13 +18,14 @@ public:
static void mouseclick(GLFWwindow *window, int button, int action, int modifiers);
static void mousemove(GLFWwindow *window, double x, double y);
+ static void eventloop(void *arg);
+
int run();
void fps();
public:
bool fullscreen = false;
- bool dirty = true;
double last_x = 0, last_y = 0;
bool tracking = false;
@@ -34,6 +36,9 @@ public:
GLFWwindow *window = nullptr;
llmr::Settings &settings;
llmr::Map map;
+
+ uv_sem_t event_listener;
+ std::atomic<bool> stop_event_listener;
};
#endif
diff --git a/include/llmr/platform/platform.hpp b/include/llmr/platform/platform.hpp
index 4b18021188..4536bf0453 100644
--- a/include/llmr/platform/platform.hpp
+++ b/include/llmr/platform/platform.hpp
@@ -38,9 +38,6 @@ void cancel_request_http(const std::shared_ptr<Request> &req);
// Returns a relative timestamp in seconds. This value must be monotonic.
double elapsed();
-// Performs routine cleanup operation and is called on every loop iteration.
-void cleanup();
-
// Shows an RGBA image with the specified dimensions in a named window.
void show_debug_image(std::string name, const char *data, size_t width, size_t height);
diff --git a/linux/llmr-app.gyp b/linux/llmr-app.gyp
index e12737b92c..1bd6d55b18 100644
--- a/linux/llmr-app.gyp
+++ b/linux/llmr-app.gyp
@@ -12,10 +12,10 @@
'./main.cpp',
'./settings.cpp',
'./settings.hpp',
- './request.cpp',
- './request.hpp',
'../common/glfw_view.hpp',
'../common/glfw_view.cpp',
+ '../common/curl_request.hpp',
+ '../common/curl_request.cpp',
],
'conditions': [
diff --git a/linux/main.cpp b/linux/main.cpp
index 42aa579b8c..49de8a2ac8 100644
--- a/linux/main.cpp
+++ b/linux/main.cpp
@@ -6,15 +6,8 @@
#include "settings.hpp"
#include "../common/glfw_view.hpp"
-#include "request.hpp"
-
-
MapView *mapView = nullptr;
-std::forward_list<std::shared_ptr<llmr::platform::Request>> requests;
-
-
-
void quit_handler(int s) {
if (mapView) {
@@ -26,10 +19,6 @@ void quit_handler(int s) {
}
}
-
-
-
-
int main(int argc, char *argv[]) {
int fullscreen_flag = 0;
@@ -51,13 +40,6 @@ int main(int argc, char *argv[]) {
sigIntHandler.sa_flags = 0;
sigaction(SIGINT, &sigIntHandler, NULL);
-
- // curl init
- curl_global_init(CURL_GLOBAL_ALL);
-
- llmr::platform::Request::initialize();
-
-
// main loop
llmr::Settings_JSON settings;
mapView = new MapView(settings, fullscreen_flag);
@@ -66,49 +48,5 @@ int main(int argc, char *argv[]) {
mapView->settings.sync();
delete mapView;
-
- llmr::platform::Request::finish();
-
- curl_global_cleanup();
return ret;
}
-
-namespace llmr {
-
-void platform::cleanup() {
- bool& dirty = mapView->dirty;
- requests.remove_if([&dirty](std::shared_ptr<llmr::platform::Request> &req) {
- if (req->done) {
- req->foreground_callback();
- dirty = true;
- return true;
- } else {
- return false;
- }
- });
-}
-
-void platform::restart() {
- if (mapView) {
- mapView->dirty = true;
- }
-}
-
-std::shared_ptr<platform::Request>
-platform::request_http(const std::string &url, std::function<void(Response *)> background_function,
- std::function<void()> foreground_callback) {
- std::shared_ptr<Request> req =
- std::make_shared<Request>(url, background_function, foreground_callback);
- requests.push_front(req);
- return req;
-}
-
-// Cancels an HTTP request.
-void platform::cancel_request_http(const std::shared_ptr<Request> &req) {
- if (req) {
- req->cancel();
- }
-}
-
-
-}
diff --git a/linux/request.cpp b/linux/request.cpp
deleted file mode 100644
index 617ee5e063..0000000000
--- a/linux/request.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-#include "request.hpp"
-
-#include <atomic>
-#include <cassert>
-
-#include <llmr/util/threadpool.hpp>
-#include <llmr/platform/platform.hpp>
-
-using namespace llmr::platform;
-
-
-CURLSH *Request::curl_share = nullptr;
-pthread_mutex_t Request::curl_share_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-void Request::curl_share_lock(CURL *, curl_lock_data, curl_lock_access, void *) {
- pthread_mutex_lock(&curl_share_mutex);
-}
-
-void Request::curl_share_unlock(CURL *, curl_lock_data, void *) {
- pthread_mutex_unlock(&curl_share_mutex);
-}
-
-size_t Request::curl_write_callback(void *contents, size_t size, size_t nmemb, void *userp) {
- ((std::string *)userp)->append((char *)contents, size * nmemb);
- return size * nmemb;
-}
-
-int Request::curl_progress_callback(void *ptr, double dltotal, double dlnow, double ultotal, double ulnow) {
- Request *req = static_cast<Request *>(ptr);
- return req->cancelled;
-}
-
-void Request::initialize() {
- // curl init
- curl_global_init(CURL_GLOBAL_ALL);
-
- curl_share = curl_share_init();
- curl_share_setopt(curl_share, CURLSHOPT_LOCKFUNC, curl_share_lock);
- curl_share_setopt(curl_share, CURLSHOPT_UNLOCKFUNC, curl_share_unlock);
-}
-
-void Request::finish() {
- pthread_key_delete(key);
- curl_share_cleanup(curl_share);
-}
-
-Request::Request(std::string url, std::function<void(platform::Response *)> bg, std::function<void()> fg)
- : done(false),
- cancelled(false),
- url(url),
- background_function(bg),
- foreground_callback(fg) {
- llmr::util::threadpool->add(request, this);
-}
-
-pthread_key_t Request::key;
-pthread_once_t Request::key_once = PTHREAD_ONCE_INIT;
-
-void Request::create_key() {
- pthread_key_create(&key, delete_key);
-}
-
-void Request::delete_key(void *ptr) {
- if (ptr != nullptr) {
- curl_easy_cleanup(ptr);
- }
-}
-
-void Request::request(void *ptr) {
- assert(curl_share);
-
- Request *req = static_cast<Request *>(ptr);
- Response res;
-
- pthread_once(&key_once, create_key);
- // TODO: use curl multi to be able to cancel, or to
-
- CURL *curl = nullptr;
- if ((curl = pthread_getspecific(key)) == nullptr) {
- curl = curl_easy_init();
-
- // stopgap to avoid libcurl crashes:
- // see https://stackoverflow.com/q/9191668
- curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
-
- pthread_setspecific(key, curl);
- }
-
- curl_easy_reset(curl);
-
- CURLcode code;
-
- curl_easy_setopt(curl, CURLOPT_URL, req->url.c_str());
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_callback);
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, &res.body);
- curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, curl_progress_callback);
- curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, req);
- curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
- curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "deflate");
- curl_easy_setopt(curl, CURLOPT_SHARE, curl_share);
- code = curl_easy_perform(curl);
- curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res.code);
-
- // Add human-readable error code
- if (code != CURLE_OK) {
- res.error_message = curl_easy_strerror(code);
- res.code = -1;
- }
-
- if (code != CURLE_ABORTED_BY_CALLBACK) {
- req->background_function(&res);
- }
-
- req->done = true;
-}
-
-void Request::cancel() {
- cancelled = true;
-}
diff --git a/linux/request.hpp b/linux/request.hpp
deleted file mode 100644
index 8350d9d459..0000000000
--- a/linux/request.hpp
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef LLMR_LINUX_REQUEST
-#define LLMR_LINUX_REQUEST
-
-#include <string>
-#include <functional>
-#include <atomic>
-#include <curl/curl.h>
-
-
-namespace llmr {
-namespace platform {
-
-struct Response;
-
-class Request {
-public:
- Request(std::string url, std::function<void(platform::Response *)> bg, std::function<void()> fg);
-
- static void initialize();
- static void finish();
-
- void cancel();
-
-private:
- static void create_key();
- static void delete_key(void *ptr);
- static void request(void *);
- static size_t curl_write_callback(void *, size_t, size_t, void *);
- static int curl_progress_callback(void *, double, double, double, double);
- static void curl_share_lock(CURL *, curl_lock_data, curl_lock_access, void *);
- static void curl_share_unlock(CURL *, curl_lock_data, void *);
-
-public:
- static pthread_key_t key;
- static pthread_once_t key_once;
- std::atomic<bool> done;
- std::atomic<bool> cancelled;
- const std::string url;
- const std::function<void(platform::Response *)> background_function;
- const std::function<void()> foreground_callback;
-
-private:
- static CURLSH *curl_share;
- static pthread_mutex_t curl_share_mutex;
-};
-
-}
-}
-
-#endif
diff --git a/macosx/main.mm b/macosx/main.mm
index c6cc04d843..8d2b0d8ce9 100644
--- a/macosx/main.mm
+++ b/macosx/main.mm
@@ -1,40 +1,14 @@
-#import <Foundation/Foundation.h>
-#import <AppKit/AppKit.h>
+// #import <Foundation/Foundation.h>
+// #import <AppKit/AppKit.h>
#include "settings.hpp"
#include "../common/glfw_view.hpp"
-#include <cstdio>
-
-#include <thread>
-
-MapView *mapView = nullptr;
-
int main() {
llmr::Settings_MacOSX settings;
- mapView = new MapView(settings);
- mapView->init();
- int ret = mapView->run();
- mapView->settings.sync();
- delete mapView;
+ MapView view(settings);
+ view.init();
+ int ret = view.run();
+ settings.sync();
return ret;
}
-
-
-
-namespace llmr {
-
-void platform::cleanup() {
- // noop
-}
-
-void platform::restart() {
- if (mapView) {
- mapView->dirty = true;
- CGEventRef event = CGEventCreate(NULL);
- CGEventSetType(event, kCGEventMouseMoved);
- [[NSApplication sharedApplication] postEvent: [NSEvent eventWithCGEvent:event] atStart:NO];
- }
-}
-
-}