diff --git a/common/glfw_view.cpp b/common/glfw_view.cpp index f53090a00..fb54d55f3 100644 --- a/common/glfw_view.cpp +++ b/common/glfw_view.cpp @@ -183,7 +183,7 @@ int GLFWView::run() { glfwWaitEvents(); } - map->stop(); + map->stop(glfwWaitEvents); return 0; } @@ -192,6 +192,10 @@ void GLFWView::make_active() { glfwMakeContextCurrent(window); } +void GLFWView::notify() { + glfwPostEmptyEvent(); +} + void GLFWView::swap() { glfwPostEmptyEvent(); diff --git a/common/glfw_view.hpp b/common/glfw_view.hpp index d2f6872fc..481b1598b 100644 --- a/common/glfw_view.hpp +++ b/common/glfw_view.hpp @@ -17,6 +17,7 @@ public: void initialize(mbgl::Map *map); void swap(); void make_active(); + void notify(); void notify_map_change(mbgl::MapChange change, mbgl::timestamp delay = 0); static void key(GLFWwindow *window, int key, int scancode, int action, int mods); diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index c389d898b..48c4e89cc 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -31,6 +31,8 @@ class FileSource; class View; class Map : private util::noncopyable { + typedef void (*stop_callback)(); + public: explicit Map(View &view); ~Map(); @@ -38,7 +40,7 @@ public: // Start/stop the map render thread. the start() call is asynchronous, while the stop() call // will block until the map rendering thread stopped. void start(); - void stop(); + void stop(stop_callback cb = nullptr); // Runs the map event loop. ONLY run this function when you want to get render a single frame // with this map object. It will *not* spawn a separate thread and instead block until the @@ -179,6 +181,9 @@ private: // ready for rendering. std::atomic_flag is_rendered = ATOMIC_FLAG_INIT; + // Stores whether the map thread has been stopped already. + std::atomic_bool is_stopped; + public: View &view; diff --git a/include/mbgl/map/view.hpp b/include/mbgl/map/view.hpp index 92d60d4d0..bbdcd97c7 100644 --- a/include/mbgl/map/view.hpp +++ b/include/mbgl/map/view.hpp @@ -41,6 +41,8 @@ public: return 0; } + virtual void notify() = 0; + // Notifies a watcher of map x/y/scale/rotation changes. // Must only be called from the same thread that caused the change. // Must not be called from the render thread. diff --git a/src/map/map.cpp b/src/map/map.cpp index 93e1bea53..b1a7b1c2f 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -75,6 +75,9 @@ void Map::start() { // updated rendering. Only in these cases, we attach the async handlers. async = true; + // Reset the flag. + is_stopped = false; + // Setup async notifications uv_async_init(**loop, async_terminate.get(), terminate); async_terminate->data = this; @@ -97,15 +100,23 @@ void Map::start() { #ifndef NDEBUG map->map_thread = -1; #endif + map->is_stopped = true; }, this); } -void Map::stop() { +void Map::stop(stop_callback cb) { assert(uv_thread_self() == main_thread); assert(main_thread != map_thread); + assert(async); uv_async_send(async_terminate.get()); + if (cb) { + while (!is_stopped) { + cb(); + } + } + uv_thread_join(*thread); async = false;