diff options
-rw-r--r-- | common/curl_request.cpp | 2 | ||||
-rw-r--r-- | common/glfw_view.cpp | 102 | ||||
-rw-r--r-- | common/glfw_view.hpp | 7 | ||||
-rw-r--r-- | include/llmr/platform/platform.hpp | 3 | ||||
-rw-r--r-- | linux/llmr-app.gyp | 4 | ||||
-rw-r--r-- | linux/main.cpp | 62 | ||||
-rw-r--r-- | linux/request.cpp | 119 | ||||
-rw-r--r-- | linux/request.hpp | 50 | ||||
-rw-r--r-- | macosx/main.mm | 38 |
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]; - } -} - -} |