summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/glfw_view.cpp4
-rw-r--r--include/mbgl/map/map.hpp13
-rw-r--r--src/map/map.cpp15
3 files changed, 25 insertions, 7 deletions
diff --git a/common/glfw_view.cpp b/common/glfw_view.cpp
index fb54d55f39..edfb3a6a6f 100644
--- a/common/glfw_view.cpp
+++ b/common/glfw_view.cpp
@@ -183,7 +183,9 @@ int GLFWView::run() {
glfwWaitEvents();
}
- map->stop(glfwWaitEvents);
+ map->stop([](void *) {
+ glfwWaitEvents();
+ });
return 0;
}
diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp
index 48c4e89cc9..85c9e8e6a5 100644
--- a/include/mbgl/map/map.hpp
+++ b/include/mbgl/map/map.hpp
@@ -31,16 +31,21 @@ class FileSource;
class View;
class Map : private util::noncopyable {
- typedef void (*stop_callback)();
+ typedef void (*stop_callback)(void *);
public:
explicit Map(View &view);
~Map();
- // Start/stop the map render thread. the start() call is asynchronous, while the stop() call
- // will block until the map rendering thread stopped.
+ // Start the map render thread. It is asynchronous.
void start();
- void stop(stop_callback cb = nullptr);
+
+ // Stop the map render thread. This call will block until the map rendering thread stopped.
+ // The optional callback function will be invoked repeatedly until the map thread is stopped.
+ // The callback function should wait until it is woken up again by view.notify(), otherwise
+ // this will be a busy waiting loop. The optional data parameter will be passed to the callback
+ // function.
+ void stop(stop_callback cb = nullptr, void *data = 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
diff --git a/src/map/map.cpp b/src/map/map.cpp
index b1a7b1c2fd..eabf7b8fe8 100644
--- a/src/map/map.cpp
+++ b/src/map/map.cpp
@@ -100,11 +100,14 @@ void Map::start() {
#ifndef NDEBUG
map->map_thread = -1;
#endif
+
+ // Make sure that the stop() function knows when to stop invoking the callback function.
map->is_stopped = true;
+ map->view.notify();
}, this);
}
-void Map::stop(stop_callback cb) {
+void Map::stop(stop_callback cb, void *data) {
assert(uv_thread_self() == main_thread);
assert(main_thread != map_thread);
assert(async);
@@ -112,11 +115,19 @@ void Map::stop(stop_callback cb) {
uv_async_send(async_terminate.get());
if (cb) {
+ // Wait until the render thread stopped. We are using this construct instead of plainly
+ // relying on the thread_join because the system might need to run things in the current
+ // thread that is required for the render thread to terminate correctly. This is for example
+ // the case with Cocoa's NSURLRequest. Otherwise, we will eventually deadlock because this
+ // thread (== main thread) is blocked. The callback function should use an efficient waiting
+ // function to avoid a busy waiting loop.
while (!is_stopped) {
- cb();
+ cb(data);
}
}
+ // If a callback function was provided, this should return immediately because the thread has
+ // already finished executing.
uv_thread_join(*thread);
async = false;