summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2014-09-16 18:23:42 +0200
committerKonstantin Käfer <mail@kkaefer.com>2014-09-24 16:14:09 +0200
commitfd2b2e208229259630f92bd7615f9197c163d27f (patch)
tree48cc7012e05c9c09e4bf437e0bab6598025e3f55 /src
parentf26bb724dc164b69b5358f30c6248fdf5cbd076b (diff)
downloadqtlocation-mapboxgl-fd2b2e208229259630f92bd7615f9197c163d27f.tar.gz
use separate workers for tile parsing to avoid blocking the threadpool for other libuv actions
Diffstat (limited to 'src')
-rw-r--r--src/map/map.cpp8
-rw-r--r--src/map/tile_data.cpp2
-rw-r--r--src/storage/sqlite_store.cpp2
-rw-r--r--src/util/uv-channel.c14
-rw-r--r--src/util/uv-worker.c41
5 files changed, 59 insertions, 8 deletions
diff --git a/src/map/map.cpp b/src/map/map.cpp
index ecf4eb2837..93e1bea536 100644
--- a/src/map/map.cpp
+++ b/src/map/map.cpp
@@ -60,6 +60,13 @@ Map::~Map() {
}
}
+uv::worker &Map::getWorker() {
+ if (!workers) {
+ workers = std::make_unique<uv::worker>(**loop, 4, "Tile Worker");
+ }
+ return *workers;
+}
+
void Map::start() {
assert(uv_thread_self() == main_thread);
assert(!async);
@@ -198,6 +205,7 @@ void Map::terminate(uv_async_t *async) {
map->glyphStore.reset();
map->fileSource.reset();
map->style.reset();
+ map->workers.reset();
map->activeSources.clear();
uv_close((uv_handle_t *)map->async_cleanup.get(), nullptr);
diff --git a/src/map/tile_data.cpp b/src/map/tile_data.cpp
index 2a0e96cad6..ecb05d5b26 100644
--- a/src/map/tile_data.cpp
+++ b/src/map/tile_data.cpp
@@ -87,7 +87,7 @@ void TileData::reparse() {
// We're creating a new work request. The work request deletes itself after it executed
// the after work handler
new uv::work<util::ptr<TileData>>(
- map.getLoop(),
+ map.getWorker(),
[](util::ptr<TileData> &tile) {
tile->parse();
},
diff --git a/src/storage/sqlite_store.cpp b/src/storage/sqlite_store.cpp
index baa599eef9..d44520a95e 100644
--- a/src/storage/sqlite_store.cpp
+++ b/src/storage/sqlite_store.cpp
@@ -32,7 +32,7 @@ SQLiteStore::SQLiteStore(uv_loop_t *loop, const std::string &path)
db(std::make_shared<Database>(path.c_str(), ReadWrite | Create)) {
createSchema();
worker = new uv_worker_t;
- uv_worker_init_named(worker, loop, "SQLite");
+ uv_worker_init(worker, loop, 1, "SQLite");
}
SQLiteStore::~SQLiteStore() {
diff --git a/src/util/uv-channel.c b/src/util/uv-channel.c
index 3d0483fd70..2936b01c53 100644
--- a/src/util/uv-channel.c
+++ b/src/util/uv-channel.c
@@ -49,7 +49,21 @@ void *uv_chan_receive(uv_chan_t *chan) {
return data;
}
+void uv_chan_clear(uv_chan_t *chan) {
+ uv_mutex_lock(&chan->mutex);
+ uv__chan_item_t *item = NULL;
+ QUEUE *head = NULL;
+ while (!QUEUE_EMPTY(&chan->q)) {
+ head = QUEUE_HEAD(&chan->q);
+ item = QUEUE_DATA(head, uv__chan_item_t, active_queue);
+ QUEUE_REMOVE(head);
+ free(item);
+ }
+ uv_mutex_unlock(&chan->mutex);
+}
+
void uv_chan_destroy(uv_chan_t *chan) {
+ uv_chan_clear(chan);
uv_cond_destroy(&chan->cond);
uv_mutex_destroy(&chan->mutex);
}
diff --git a/src/util/uv-worker.c b/src/util/uv-worker.c
index d0e2550b73..c47b0ffed2 100644
--- a/src/util/uv-worker.c
+++ b/src/util/uv-worker.c
@@ -1,5 +1,6 @@
#include <mbgl/util/uv-worker.h>
#include <mbgl/util/uv-messenger.h>
+#include <mbgl/util/queue.h>
#include <stdio.h>
@@ -10,6 +11,12 @@ struct uv__worker_item_s {
uv_worker_after_cb after_work_cb;
};
+typedef struct uv__work_thread_s uv__work_thread_t;
+struct uv__work_thread_s {
+ uv_thread_t thread;
+ void *queue[2];
+};
+
void uv__worker_after(void *ptr) {
uv__worker_item_t *item = (uv__worker_item_t *)ptr;
item->after_work_cb(item->data);
@@ -30,20 +37,29 @@ void uv__worker_thread_loop(void *ptr) {
item->work_cb(item->data);
uv_messenger_send(worker->msgr, item);
}
-}
-int uv_worker_init(uv_worker_t *worker, uv_loop_t *loop) {
- return uv_worker_init_named(worker, loop, NULL);
+ // Make sure to close all other workers too.
+ uv_chan_send(&worker->chan, NULL);
}
-int uv_worker_init_named(uv_worker_t *worker, uv_loop_t *loop, const char *name) {
+int uv_worker_init(uv_worker_t *worker, uv_loop_t *loop, int count, const char *name) {
worker->name = name;
worker->msgr = malloc(sizeof(uv_messenger_t));
int ret = uv_messenger_init(loop, worker->msgr, uv__worker_after);
if (ret < 0) return ret;
ret = uv_chan_init(&worker->chan);
if (ret < 0) return ret;
- return uv_thread_create(&worker->thread, uv__worker_thread_loop, worker);
+
+ // Initialize worker threads.
+ QUEUE_INIT(&worker->threads);
+ for (int i = 0; i < count; i++) {
+ uv__work_thread_t *work_thread = malloc(sizeof(uv__work_thread_t));
+ ret = uv_thread_create(&work_thread->thread, uv__worker_thread_loop, worker);
+ if (ret < 0) return ret;
+ QUEUE_INSERT_TAIL(&worker->threads, &work_thread->queue);
+ }
+
+ return 0;
}
void uv_worker_send(uv_worker_t *worker, void *data, uv_worker_cb work_cb,
@@ -55,8 +71,21 @@ void uv_worker_send(uv_worker_t *worker, void *data, uv_worker_cb work_cb,
uv_chan_send(&worker->chan, item);
}
+void uv_worker_join_all(uv_worker_t *worker) {
+ QUEUE *head = NULL;
+ uv__work_thread_t *item = NULL;
+ while (!QUEUE_EMPTY(&worker->threads)) {
+ head = QUEUE_HEAD(&worker->threads);
+ item = QUEUE_DATA(head, uv__work_thread_t, queue);
+ QUEUE_REMOVE(head);
+ uv_thread_join(&item->thread);
+ free(item);
+ }
+}
+
void uv_worker_close(uv_worker_t *worker) {
uv_chan_send(&worker->chan, NULL);
- uv_thread_join(&worker->thread);
+ uv_worker_join_all(worker);
+ uv_chan_destroy(&worker->chan);
uv_messenger_stop(worker->msgr);
}