~Object is likely to join threads that want to dispatch results
back to this RunLoop. This happens, for example, when MapContext
is destructed: it joins the worker threads, which need to complete
work before shutting down.
Even though we only bind the shared_ptr in the after callback, the
worker thread was still copying the callback and therefore gaining
a shared reference. Here we try to eliminate the copies.
The previous implementation, based on thread-local storage, did not
ensure that the context was destructed before the FileSource run loop.
This resulted in implementations attempting to uv_close handles for a
loop that had already been destroyed.
This change also fixes#1262.
Both Android and iOS now use pause/resume. The map thread is
always running, and be able to receive messages. When paused,
it will just refuse to render.
The Thread object gets access via its constructor. No other object
should have access; off-thread objects can't safely do anything with
it except pass it back to the thread.
Implements a Thread<>::invoke interface that only permits calling
member functions with bound arguments.
Also introduce invokeWithResult, which accepts a callback and invokes
it, passing the result, on the invoking thread's RunLoop. This closes
the loop of two evented threads doing message passing.
Thread<T> is a generic thread management object that starts a thread, creates an object T in that thread and calls its .start() function. When the Thread<T> object is destructed (which must happen in the thread that created it), it'll call the object's .stop() function, and wait for thread termination. The .stop() function must somehow get the thread to terminate. Note that object T's constructor/destructor/start()/stop() must be protected/private, and Thread<T> must be declared as a friend class. All public functions may be called from any thread and are exposed through operator->().
RunLoop encapsulates a libuv runloop and has a facility of dispatching function objects to the thread. It can be used either as a worker thread class by itself, or it can be derived from. This commit converts SQLiteCache to derive from RunLoop and removes the custom code used previously for managing the cache thread.
On iOS, the main thread does framebuffer operations just before it requests a rerender of the view contents. This means that GL operations on the Map thread will interfere with that and cause a crash. While most GL operations happen throughout rendering (which is synchronized with the main thread), deletion of shared_ptrs release in turn their OpenGL objects. This may happen at any time and isn't synced with rendering.
This patch changes this so instead of deleting all objects immediately, we are collecting all abandoned IDs and delete them in bulk once the main thread has given us permission to use OpenGL calls (i.e. during render()).