From bc126388f883ee299573054a31f53e248b5153c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Wed, 11 Jan 2017 12:05:19 +0100 Subject: [PATCH 1/5] [core] add support for naming thread pool threads and setting them to low priority adds parity with util::Thread --- benchmark/api/query.benchmark.cpp | 2 +- bin/render.cpp | 2 +- platform/android/src/native_map_view.cpp | 2 +- platform/default/mbgl/util/default_thread_pool.cpp | 10 ++++++++-- platform/default/mbgl/util/default_thread_pool.hpp | 3 ++- platform/glfw/main.cpp | 2 +- platform/ios/src/MGLMapView.mm | 2 +- platform/macos/src/MGLMapView.mm | 2 +- platform/qt/src/qmapboxgl.cpp | 2 +- test/actor/actor.test.cpp | 8 ++++---- test/actor/actor_ref.test.cpp | 2 +- test/api/annotations.test.cpp | 2 +- test/api/api_misuse.test.cpp | 4 ++-- test/api/custom_layer.test.cpp | 2 +- test/api/query.test.cpp | 2 +- test/api/render_missing.test.cpp | 2 +- test/api/repeated_render.test.cpp | 2 +- test/map/map.test.cpp | 4 ++-- test/style/source.test.cpp | 2 +- test/tile/geojson_tile.test.cpp | 2 +- test/tile/raster_tile.test.cpp | 2 +- test/tile/vector_tile.test.cpp | 2 +- test/util/memory.test.cpp | 2 +- 23 files changed, 36 insertions(+), 29 deletions(-) diff --git a/benchmark/api/query.benchmark.cpp b/benchmark/api/query.benchmark.cpp index ba696876cd6..456f43af7e7 100644 --- a/benchmark/api/query.benchmark.cpp +++ b/benchmark/api/query.benchmark.cpp @@ -36,7 +36,7 @@ class QueryBenchmark { HeadlessBackend backend; OffscreenView view{ backend.getContext(), { 1000, 1000 } }; DefaultFileSource fileSource{ "benchmark/fixtures/api/cache.db", "." }; - ThreadPool threadPool{ 4 }; + ThreadPool threadPool{ 4, { "Worker" } }; Map map{ backend, view.size, 1, fileSource, threadPool, MapMode::Still }; ScreenBox box{{ 0, 0 }, { 1000, 1000 }}; }; diff --git a/bin/render.cpp b/bin/render.cpp index d275b445d2d..0f6ff5f2079 100644 --- a/bin/render.cpp +++ b/bin/render.cpp @@ -86,7 +86,7 @@ int main(int argc, char *argv[]) { HeadlessBackend backend; OffscreenView view(backend.getContext(), { width * pixelRatio, height * pixelRatio }); - ThreadPool threadPool(4); + ThreadPool threadPool(4, { "Worker" }); Map map(backend, mbgl::Size { width, height }, pixelRatio, fileSource, threadPool, MapMode::Still); if (util::isURL(style_path)) { diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp index 8234b74af29..d2ee1a64fe5 100755 --- a/platform/android/src/native_map_view.cpp +++ b/platform/android/src/native_map_view.cpp @@ -41,7 +41,7 @@ NativeMapView::NativeMapView(JNIEnv *env_, jobject obj_, float pixelRatio, int a : env(env_), availableProcessors(availableProcessors_), totalMemory(totalMemory_), - threadPool(4) { + threadPool(4, { "Worker" }) { mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::NativeMapView"); assert(env_ != nullptr); diff --git a/platform/default/mbgl/util/default_thread_pool.cpp b/platform/default/mbgl/util/default_thread_pool.cpp index 92c0f067456..0d02c875387 100644 --- a/platform/default/mbgl/util/default_thread_pool.cpp +++ b/platform/default/mbgl/util/default_thread_pool.cpp @@ -1,12 +1,18 @@ #include #include +#include namespace mbgl { -ThreadPool::ThreadPool(std::size_t count) { +ThreadPool::ThreadPool(std::size_t count, const util::ThreadContext& context) { threads.reserve(count); for (std::size_t i = 0; i < count; ++i) { - threads.emplace_back([this] () { + threads.emplace_back([this, context] () { + platform::setCurrentThreadName(context.name); + if (context.priority == util::ThreadPriority::Low) { + platform::makeThreadLowPriority(); + } + while (true) { std::unique_lock lock(mutex); diff --git a/platform/default/mbgl/util/default_thread_pool.hpp b/platform/default/mbgl/util/default_thread_pool.hpp index a14d16d7713..f86da5b50cf 100644 --- a/platform/default/mbgl/util/default_thread_pool.hpp +++ b/platform/default/mbgl/util/default_thread_pool.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -11,7 +12,7 @@ namespace mbgl { class ThreadPool : public Scheduler { public: - ThreadPool(std::size_t count); + ThreadPool(std::size_t count, const util::ThreadContext&); ~ThreadPool() override; void schedule(std::weak_ptr) override; diff --git a/platform/glfw/main.cpp b/platform/glfw/main.cpp index 1f683b185f9..f9b1ec93cc1 100644 --- a/platform/glfw/main.cpp +++ b/platform/glfw/main.cpp @@ -118,7 +118,7 @@ int main(int argc, char *argv[]) { fileSource.setAccessToken(std::string(token)); } - mbgl::ThreadPool threadPool(4); + mbgl::ThreadPool threadPool(4, { "Worker" }); mbgl::Map map(backend, view->getSize(), view->getPixelRatio(), fileSource, threadPool); diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 608acf016da..4866dd5783c 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -421,7 +421,7 @@ - (void)commonInit // setup mbgl map mbgl::DefaultFileSource *mbglFileSource = [MGLOfflineStorage sharedOfflineStorage].mbglFileSource; const float scaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale]; - _mbglThreadPool = new mbgl::ThreadPool(4); + _mbglThreadPool = new mbgl::ThreadPool(4, { "Worker" }); _mbglMap = new mbgl::Map(*_mbglView, self.size, scaleFactor, *mbglFileSource, *_mbglThreadPool, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None, mbgl::ViewportMode::Default); [self validateTileCacheSize]; diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm index 92aa0a6c6b8..5df5a1f9577 100644 --- a/platform/macos/src/MGLMapView.mm +++ b/platform/macos/src/MGLMapView.mm @@ -259,7 +259,7 @@ - (void)commonInit { mbgl::DefaultFileSource* mbglFileSource = [MGLOfflineStorage sharedOfflineStorage].mbglFileSource; - _mbglThreadPool = new mbgl::ThreadPool(4); + _mbglThreadPool = new mbgl::ThreadPool(4, { "Worker" }); _mbglMap = new mbgl::Map(*_mbglView, self.size, [NSScreen mainScreen].backingScaleFactor, *mbglFileSource, *_mbglThreadPool, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None, mbgl::ViewportMode::Default); [self validateTileCacheSize]; diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp index 86604a945f8..9d3b5dc099d 100644 --- a/platform/qt/src/qmapboxgl.cpp +++ b/platform/qt/src/qmapboxgl.cpp @@ -1498,7 +1498,7 @@ QMapboxGLPrivate::QMapboxGLPrivate(QMapboxGL *q, const QMapboxGLSettings &settin settings.cacheDatabasePath().toStdString(), settings.assetPath().toStdString(), settings.cacheDatabaseMaximumSize())) - , threadPool(4) + , threadPool(4, { "Worker" }) , mapObj(std::make_unique( *this, mbgl::Size{ static_cast(size.width()), static_cast(size.height()) }, pixelRatio, *fileSourceObj, threadPool, diff --git a/test/actor/actor.test.cpp b/test/actor/actor.test.cpp index 03f41a6e64d..ad8d91f6b53 100644 --- a/test/actor/actor.test.cpp +++ b/test/actor/actor.test.cpp @@ -19,7 +19,7 @@ TEST(Actor, Construction) { }; }; - ThreadPool pool { 1 }; + ThreadPool pool { 1, { "ActorConstruction" } }; bool constructed = false; Actor test(pool, std::ref(constructed)); @@ -52,7 +52,7 @@ TEST(Actor, DestructionClosesMailbox) { } }; - ThreadPool pool { 1 }; + ThreadPool pool { 1, { "ActorDestructionClosesMailbox" } }; std::promise enteredPromise; std::future enteredFuture = enteredPromise.get_future(); @@ -88,7 +88,7 @@ TEST(Actor, OrderedMailbox) { } }; - ThreadPool pool { 1 }; + ThreadPool pool { 1, { "ActorOrderedMailbox" } }; std::promise endedPromise; std::future endedFuture = endedPromise.get_future(); @@ -124,7 +124,7 @@ TEST(Actor, NonConcurrentMailbox) { } }; - ThreadPool pool { 10 }; + ThreadPool pool { 10, { "ActorNonConcurrentMailbox" } }; std::promise endedPromise; std::future endedFuture = endedPromise.get_future(); diff --git a/test/actor/actor_ref.test.cpp b/test/actor/actor_ref.test.cpp index 78721c965e9..8877e3aaf8c 100644 --- a/test/actor/actor_ref.test.cpp +++ b/test/actor/actor_ref.test.cpp @@ -30,7 +30,7 @@ TEST(ActorRef, CanOutliveActor) { } }; - ThreadPool pool { 1 }; + ThreadPool pool { 1, { "ActorRefCanOutliveActor" } }; bool died = false; ActorRef test = [&] () { diff --git a/test/api/annotations.test.cpp b/test/api/annotations.test.cpp index 72a2d62bde3..6e5351a91de 100644 --- a/test/api/annotations.test.cpp +++ b/test/api/annotations.test.cpp @@ -26,7 +26,7 @@ class AnnotationTest { HeadlessBackend backend { test::sharedDisplay() }; OffscreenView view { backend.getContext() }; StubFileSource fileSource; - ThreadPool threadPool { 4 }; + ThreadPool threadPool { 4, { "Worker" } }; Map map { backend, view.size, 1, fileSource, threadPool, MapMode::Still }; void checkRendering(const char * name) { diff --git a/test/api/api_misuse.test.cpp b/test/api/api_misuse.test.cpp index 34272f53664..5ecba8be5d8 100644 --- a/test/api/api_misuse.test.cpp +++ b/test/api/api_misuse.test.cpp @@ -24,7 +24,7 @@ TEST(API, RenderWithoutCallback) { HeadlessBackend backend { test::sharedDisplay() }; OffscreenView view { backend.getContext(), { 128, 512 } }; StubFileSource fileSource; - ThreadPool threadPool(4); + ThreadPool threadPool{ 4, { "Worker" } }; std::unique_ptr map = std::make_unique(backend, view.size, 1, fileSource, threadPool, MapMode::Still); @@ -49,7 +49,7 @@ TEST(API, RenderWithoutStyle) { HeadlessBackend backend { test::sharedDisplay() }; OffscreenView view { backend.getContext(), { 128, 512 } }; StubFileSource fileSource; - ThreadPool threadPool(4); + ThreadPool threadPool{ 4, { "Worker" } }; Map map(backend, view.size, 1, fileSource, threadPool, MapMode::Still); diff --git a/test/api/custom_layer.test.cpp b/test/api/custom_layer.test.cpp index 73b4e94af5c..227523d90a0 100644 --- a/test/api/custom_layer.test.cpp +++ b/test/api/custom_layer.test.cpp @@ -95,7 +95,7 @@ TEST(CustomLayer, Basic) { DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets"); #endif - ThreadPool threadPool(4); + ThreadPool threadPool{ 4, { "Worker" } }; Map map(backend, view.size, 1, fileSource, threadPool, MapMode::Still); map.setStyleJSON(util::read_file("test/fixtures/api/water.json")); diff --git a/test/api/query.test.cpp b/test/api/query.test.cpp index 86687fc8182..964ae7caea7 100644 --- a/test/api/query.test.cpp +++ b/test/api/query.test.cpp @@ -29,7 +29,7 @@ class QueryTest { HeadlessBackend backend { test::sharedDisplay() }; OffscreenView view { backend.getContext() }; StubFileSource fileSource; - ThreadPool threadPool { 4 }; + ThreadPool threadPool { 4, { "Worker" } }; Map map { backend, view.size, 1, fileSource, threadPool, MapMode::Still }; }; diff --git a/test/api/render_missing.test.cpp b/test/api/render_missing.test.cpp index a5c59913bc1..9c53f35102e 100644 --- a/test/api/render_missing.test.cpp +++ b/test/api/render_missing.test.cpp @@ -34,7 +34,7 @@ TEST(API, TEST_REQUIRES_SERVER(RenderMissingTile)) { DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets"); #endif - ThreadPool threadPool(4); + ThreadPool threadPool{ 4, { "Worker" } }; Log::setObserver(std::make_unique()); diff --git a/test/api/repeated_render.test.cpp b/test/api/repeated_render.test.cpp index 49b9a31b0b9..4ece3c3150c 100644 --- a/test/api/repeated_render.test.cpp +++ b/test/api/repeated_render.test.cpp @@ -30,7 +30,7 @@ TEST(API, RepeatedRender) { DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets"); #endif - ThreadPool threadPool(4); + ThreadPool threadPool{ 4, { "Worker" } }; Log::setObserver(std::make_unique()); diff --git a/test/map/map.test.cpp b/test/map/map.test.cpp index 8eedeb3c014..9ee2d45a811 100644 --- a/test/map/map.test.cpp +++ b/test/map/map.test.cpp @@ -26,7 +26,7 @@ struct MapTest { HeadlessBackend backend { test::sharedDisplay() }; OffscreenView view { backend.getContext() }; StubFileSource fileSource; - ThreadPool threadPool { 4 }; + ThreadPool threadPool{ 4, { "Worker" } }; }; TEST(Map, LatLngBehavior) { @@ -475,7 +475,7 @@ TEST(Map, TEST_DISABLED_ON_CI(ContinuousRendering)) { util::RunLoop runLoop; MockBackend backend { test::sharedDisplay() }; OffscreenView view { backend.getContext() }; - ThreadPool threadPool { 4 }; + ThreadPool threadPool{ 4, { "Worker" } }; #ifdef MBGL_ASSET_ZIP // Regenerate with `cd test/fixtures/api/ && zip -r assets.zip assets/` diff --git a/test/style/source.test.cpp b/test/style/source.test.cpp index 01f54d6b186..69fb5c368ca 100644 --- a/test/style/source.test.cpp +++ b/test/style/source.test.cpp @@ -31,7 +31,7 @@ class SourceTest { StubStyleObserver observer; Transform transform; TransformState transformState; - ThreadPool threadPool { 1 }; + ThreadPool threadPool{ 1, { "Worker" } }; AnnotationManager annotationManager { 1.0 }; style::Style style { fileSource, 1.0 }; diff --git a/test/tile/geojson_tile.test.cpp b/test/tile/geojson_tile.test.cpp index 920e946a2b3..dbebbe57071 100644 --- a/test/tile/geojson_tile.test.cpp +++ b/test/tile/geojson_tile.test.cpp @@ -22,7 +22,7 @@ class GeoJSONTileTest { FakeFileSource fileSource; TransformState transformState; util::RunLoop loop; - ThreadPool threadPool { 1 }; + ThreadPool threadPool{ 1, { "Worker" } }; AnnotationManager annotationManager { 1.0 }; style::Style style { fileSource, 1.0 }; Tileset tileset { { "https://example.com" }, { 0, 22 }, "none" }; diff --git a/test/tile/raster_tile.test.cpp b/test/tile/raster_tile.test.cpp index 0d599ceae09..5181d7052f3 100644 --- a/test/tile/raster_tile.test.cpp +++ b/test/tile/raster_tile.test.cpp @@ -17,7 +17,7 @@ class RasterTileTest { FakeFileSource fileSource; TransformState transformState; util::RunLoop loop; - ThreadPool threadPool { 1 }; + ThreadPool threadPool{ 1, { "Worker" } }; AnnotationManager annotationManager { 1.0 }; style::Style style { fileSource, 1.0 }; Tileset tileset { { "https://example.com" }, { 0, 22 }, "none" }; diff --git a/test/tile/vector_tile.test.cpp b/test/tile/vector_tile.test.cpp index e34629bdbaf..909a0887946 100644 --- a/test/tile/vector_tile.test.cpp +++ b/test/tile/vector_tile.test.cpp @@ -23,7 +23,7 @@ class VectorTileTest { FakeFileSource fileSource; TransformState transformState; util::RunLoop loop; - ThreadPool threadPool { 1 }; + ThreadPool threadPool{ 1, { "Worker" } }; AnnotationManager annotationManager { 1.0 }; style::Style style { fileSource, 1.0 }; Tileset tileset { { "https://example.com" }, { 0, 22 }, "none" }; diff --git a/test/util/memory.test.cpp b/test/util/memory.test.cpp index 984e7a3e242..fdade220e68 100644 --- a/test/util/memory.test.cpp +++ b/test/util/memory.test.cpp @@ -59,7 +59,7 @@ class MemoryTest { HeadlessBackend backend { test::sharedDisplay() }; OffscreenView view{ backend.getContext(), { 512, 512 } }; StubFileSource fileSource; - ThreadPool threadPool { 4 }; + ThreadPool threadPool{ 4, { "Worker" } }; private: Response response(const std::string& path) { From a5e284d1ccec30cb4da0a45af9d644c6a7abf3a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Wed, 11 Jan 2017 12:05:52 +0100 Subject: [PATCH 2/5] [android] remove unused code --- platform/android/src/asset_file_source.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/platform/android/src/asset_file_source.cpp b/platform/android/src/asset_file_source.cpp index c72b86af5c9..d677d326d8d 100644 --- a/platform/android/src/asset_file_source.cpp +++ b/platform/android/src/asset_file_source.cpp @@ -35,15 +35,6 @@ struct ZipFileHolder { namespace mbgl { -class AssetFileRequest : public AsyncRequest { -public: - AssetFileRequest(std::unique_ptr workRequest_) - : workRequest(std::move(workRequest_)) { - } - - std::unique_ptr workRequest; -}; - class AssetFileSource::Impl { public: Impl(const std::string& root_) From d90998c7bb5f8d1548ad5394b7fb77be33f403fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Wed, 11 Jan 2017 15:00:54 +0100 Subject: [PATCH 3/5] [core] require a Scheduler (=ThreadPool) for DefaultFileSource construction this is a preparatory commit; the Scheduler is currently unused --- benchmark/api/query.benchmark.cpp | 2 +- bin/offline.cpp | 4 +- bin/render.cpp | 4 +- include/mbgl/storage/default_file_source.hpp | 5 ++- platform/android/src/jni.cpp | 4 +- platform/android/src/native_map_view.cpp | 7 ++-- platform/android/src/native_map_view.hpp | 2 - platform/android/src/shared_thread_pool.hpp | 15 +++++++ platform/darwin/src/MGLOfflineStorage.mm | 5 ++- platform/darwin/src/MGLThreadPool.mm | 39 ++++++++++++++++++ platform/darwin/src/MGLThreadPool_Private.h | 18 +++++++++ platform/default/default_file_source.cpp | 3 +- platform/glfw/main.cpp | 6 +-- platform/ios/ios.xcodeproj/project.pbxproj | 12 ++++++ .../macos/macos.xcodeproj/project.pbxproj | 8 ++++ platform/macos/src/MGLMapView.mm | 16 ++++---- platform/qt/src/qmapboxgl.cpp | 3 +- platform/qt/src/qmapboxgl_p.hpp | 2 +- test/api/custom_layer.test.cpp | 7 ++-- test/api/render_missing.test.cpp | 7 ++-- test/api/repeated_render.test.cpp | 8 ++-- test/map/map.test.cpp | 6 +-- test/storage/default_file_source.test.cpp | 40 +++++++++++++------ 23 files changed, 167 insertions(+), 56 deletions(-) create mode 100644 platform/android/src/shared_thread_pool.hpp create mode 100644 platform/darwin/src/MGLThreadPool.mm create mode 100644 platform/darwin/src/MGLThreadPool_Private.h diff --git a/benchmark/api/query.benchmark.cpp b/benchmark/api/query.benchmark.cpp index 456f43af7e7..928386c596a 100644 --- a/benchmark/api/query.benchmark.cpp +++ b/benchmark/api/query.benchmark.cpp @@ -35,8 +35,8 @@ class QueryBenchmark { util::RunLoop loop; HeadlessBackend backend; OffscreenView view{ backend.getContext(), { 1000, 1000 } }; - DefaultFileSource fileSource{ "benchmark/fixtures/api/cache.db", "." }; ThreadPool threadPool{ 4, { "Worker" } }; + DefaultFileSource fileSource{ threadPool, "benchmark/fixtures/api/cache.db", "." }; Map map{ backend, view.size, 1, fileSource, threadPool, MapMode::Still }; ScreenBox box{{ 0, 0 }, { 1000, 1000 }}; }; diff --git a/bin/offline.cpp b/bin/offline.cpp index 502561d0a19..068de9ee8d0 100644 --- a/bin/offline.cpp +++ b/bin/offline.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -55,7 +56,8 @@ int main(int argc, char *argv[]) { using namespace mbgl; util::RunLoop loop; - DefaultFileSource fileSource(output, "."); + ThreadPool threadPool{ 2, { "Worker" } }; + DefaultFileSource fileSource(threadPool, output, "."); std::unique_ptr region; fileSource.setAccessToken(token); diff --git a/bin/render.cpp b/bin/render.cpp index 0f6ff5f2079..aa2a3408a2a 100644 --- a/bin/render.cpp +++ b/bin/render.cpp @@ -69,7 +69,8 @@ int main(int argc, char *argv[]) { using namespace mbgl; util::RunLoop loop; - DefaultFileSource fileSource(cache_file, asset_root); + ThreadPool threadPool(4, { "Worker" }); + DefaultFileSource fileSource(threadPool, cache_file, asset_root); // Try to load the token from the environment. if (!token.size()) { @@ -86,7 +87,6 @@ int main(int argc, char *argv[]) { HeadlessBackend backend; OffscreenView view(backend.getContext(), { width * pixelRatio, height * pixelRatio }); - ThreadPool threadPool(4, { "Worker" }); Map map(backend, mbgl::Size { width, height }, pixelRatio, fileSource, threadPool, MapMode::Still); if (util::isURL(style_path)) { diff --git a/include/mbgl/storage/default_file_source.hpp b/include/mbgl/storage/default_file_source.hpp index b8f5e1167ef..4bf1681c77a 100644 --- a/include/mbgl/storage/default_file_source.hpp +++ b/include/mbgl/storage/default_file_source.hpp @@ -8,6 +8,8 @@ namespace mbgl { +class Scheduler; + namespace util { template class Thread; } // namespace util @@ -21,7 +23,8 @@ class DefaultFileSource : public FileSource { * regions, we want the database to remain fairly small (order tens or low hundreds * of megabytes). */ - DefaultFileSource(const std::string& cachePath, + DefaultFileSource(Scheduler&, + const std::string& cachePath, const std::string& assetRoot, uint64_t maximumCacheSize = util::DEFAULT_MAX_CACHE_SIZE); ~DefaultFileSource() override; diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp index 5182e268f39..d3bd4e02dda 100755 --- a/platform/android/src/jni.cpp +++ b/platform/android/src/jni.cpp @@ -11,6 +11,7 @@ #include "jni.hpp" #include "java_types.hpp" #include "native_map_view.hpp" +#include "shared_thread_pool.hpp" #include "connectivity_listener.hpp" #include "style/layers/layers.hpp" #include "style/sources/sources.hpp" @@ -1236,7 +1237,8 @@ void nativeScheduleTakeSnapshot(JNIEnv *env, jni::jobject* obj, jlong nativeMapV jlong createDefaultFileSource(JNIEnv *env, jni::jobject* obj, jni::jstring* cachePath_, jni::jstring* assetRoot_, jlong maximumCacheSize) { std::string cachePath = std_string_from_jstring(env, cachePath_); std::string assetRoot = std_string_from_jstring(env, assetRoot_); - mbgl::DefaultFileSource *defaultFileSource = new mbgl::DefaultFileSource(cachePath, assetRoot, maximumCacheSize); + mbgl::DefaultFileSource* defaultFileSource = new mbgl::DefaultFileSource( + mbgl::android::sharedThreadPool(), cachePath, assetRoot, maximumCacheSize); jlong defaultFileSourcePtr = reinterpret_cast(defaultFileSource); return defaultFileSourcePtr; } diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp index d2ee1a64fe5..6293aed7597 100755 --- a/platform/android/src/native_map_view.cpp +++ b/platform/android/src/native_map_view.cpp @@ -1,5 +1,6 @@ #include "native_map_view.hpp" #include "jni.hpp" +#include "shared_thread_pool.hpp" #include #include @@ -40,8 +41,7 @@ void log_egl_string(EGLDisplay display, EGLint name, const char *label) { NativeMapView::NativeMapView(JNIEnv *env_, jobject obj_, float pixelRatio, int availableProcessors_, size_t totalMemory_) : env(env_), availableProcessors(availableProcessors_), - totalMemory(totalMemory_), - threadPool(4, { "Worker" }) { + totalMemory(totalMemory_) { mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::NativeMapView"); assert(env_ != nullptr); @@ -59,12 +59,13 @@ NativeMapView::NativeMapView(JNIEnv *env_, jobject obj_, float pixelRatio, int a } fileSource = std::make_unique( + sharedThreadPool(), mbgl::android::cachePath + "/mbgl-offline.db", mbgl::android::apkPath); map = std::make_unique( *this, mbgl::Size{ static_cast(width), static_cast(height) }, - pixelRatio, *fileSource, threadPool, MapMode::Continuous); + pixelRatio, *fileSource, sharedThreadPool(), MapMode::Continuous); float zoomFactor = map->getMaxZoom() - map->getMinZoom() + 1; float cpuFactor = availableProcessors; diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp index e7379700a93..b7513dc572f 100755 --- a/platform/android/src/native_map_view.hpp +++ b/platform/android/src/native_map_view.hpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include @@ -97,7 +96,6 @@ class NativeMapView : public mbgl::View, public mbgl::Backend { // Ensure these are initialised last std::unique_ptr fileSource; - mbgl::ThreadPool threadPool; std::unique_ptr map; mbgl::EdgeInsets insets; diff --git a/platform/android/src/shared_thread_pool.hpp b/platform/android/src/shared_thread_pool.hpp new file mode 100644 index 00000000000..3229c03193f --- /dev/null +++ b/platform/android/src/shared_thread_pool.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +namespace mbgl { +namespace android { + +// May only be called from the main/UI thread. +inline ThreadPool& sharedThreadPool() { + static ThreadPool threadPool{ 4, { "Worker" } }; + return threadPool; +} + +} +} diff --git a/platform/darwin/src/MGLOfflineStorage.mm b/platform/darwin/src/MGLOfflineStorage.mm index 10acc58b250..81219ec8209 100644 --- a/platform/darwin/src/MGLOfflineStorage.mm +++ b/platform/darwin/src/MGLOfflineStorage.mm @@ -5,6 +5,7 @@ #import "MGLNetworkConfiguration.h" #import "MGLOfflinePack_Private.h" #import "MGLOfflineRegion_Private.h" +#import "MGLThreadPool_Private.h" #import "MGLTilePyramidOfflineRegion.h" #import "NSValue+MGLAdditions.h" @@ -130,7 +131,9 @@ - (instancetype)init { [[NSFileManager defaultManager] moveItemAtPath:subdirectorylessCacheURL.path toPath:cachePath error:NULL]; } - _mbglFileSource = new mbgl::DefaultFileSource(cachePath.UTF8String, [NSBundle mainBundle].resourceURL.path.UTF8String); + _mbglFileSource = new mbgl::DefaultFileSource( + *[MGLThreadPool sharedPool].mbglThreadPool, cachePath.UTF8String, + [NSBundle mainBundle].resourceURL.path.UTF8String); // Observe for changes to the API base URL (and find out the current one). [[MGLNetworkConfiguration sharedManager] addObserver:self diff --git a/platform/darwin/src/MGLThreadPool.mm b/platform/darwin/src/MGLThreadPool.mm new file mode 100644 index 00000000000..fa57233fb8f --- /dev/null +++ b/platform/darwin/src/MGLThreadPool.mm @@ -0,0 +1,39 @@ +#import "MGLThreadPool_Private.h" + +#import "NSProcessInfo+MGLAdditions.h" + +@interface MGLThreadPool () + +@property (nonatomic) mbgl::ThreadPool *mbglThreadPool; + +@end + +@implementation MGLThreadPool + +#pragma mark - Internal + ++ (instancetype)sharedPool { + if (NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent) { + return nil; + } + static dispatch_once_t onceToken; + static MGLThreadPool *sharedThreadPool; + dispatch_once(&onceToken, ^{ + sharedThreadPool = [[self alloc] init]; + }); + return sharedThreadPool; +} + +- (instancetype)init { + if (self = [super init]) { + _mbglThreadPool = new mbgl::ThreadPool(4, { "Worker" }); + } + return self; +} + +- (void)dealloc { + delete _mbglThreadPool; + _mbglThreadPool = nullptr; +} + +@end diff --git a/platform/darwin/src/MGLThreadPool_Private.h b/platform/darwin/src/MGLThreadPool_Private.h new file mode 100644 index 00000000000..c1420ab3107 --- /dev/null +++ b/platform/darwin/src/MGLThreadPool_Private.h @@ -0,0 +1,18 @@ +#import + +#include + +@interface MGLThreadPool : NSObject +@end + +@interface MGLThreadPool (Private) + +/// Returns the shared instance of the `MGLThreadPool` class. ++ (instancetype)sharedPool; + +/** + The shared thread pool object owned by the shared thread pool object. + */ +@property (nonatomic) mbgl::ThreadPool *mbglThreadPool; + +@end diff --git a/platform/default/default_file_source.cpp b/platform/default/default_file_source.cpp index c4222b5a120..80ddb230504 100644 --- a/platform/default/default_file_source.cpp +++ b/platform/default/default_file_source.cpp @@ -160,7 +160,8 @@ class DefaultFileSource::Impl { std::unordered_map> downloads; }; -DefaultFileSource::DefaultFileSource(const std::string& cachePath, +DefaultFileSource::DefaultFileSource(Scheduler&, + const std::string& cachePath, const std::string& assetRoot, uint64_t maximumCacheSize) : thread(std::make_unique>(util::ThreadContext{"DefaultFileSource", util::ThreadPriority::Low}, diff --git a/platform/glfw/main.cpp b/platform/glfw/main.cpp index f9b1ec93cc1..bd7c6e72161 100644 --- a/platform/glfw/main.cpp +++ b/platform/glfw/main.cpp @@ -108,7 +108,9 @@ int main(int argc, char *argv[]) { GLFWView backend(fullscreen, benchmark); view = &backend; - mbgl::DefaultFileSource fileSource("/tmp/mbgl-cache.db", "."); + mbgl::ThreadPool threadPool(4, { "Worker" }); + + mbgl::DefaultFileSource fileSource(threadPool, "/tmp/mbgl-cache.db", "."); // Set access token if present const char *token = getenv("MAPBOX_ACCESS_TOKEN"); @@ -118,8 +120,6 @@ int main(int argc, char *argv[]) { fileSource.setAccessToken(std::string(token)); } - mbgl::ThreadPool threadPool(4, { "Worker" }); - mbgl::Map map(backend, view->getSize(), view->getPixelRatio(), fileSource, threadPool); backend.setMap(&map); diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj index 6f2ee38e945..3595e917b4e 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -162,6 +162,10 @@ 40F887701D7A1E58008ECB67 /* MGLShapeSource_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 40F8876F1D7A1DB8008ECB67 /* MGLShapeSource_Private.h */; }; 40F887711D7A1E59008ECB67 /* MGLShapeSource_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 40F8876F1D7A1DB8008ECB67 /* MGLShapeSource_Private.h */; }; 40FDA76B1CCAAA6800442548 /* MBXAnnotationView.m in Sources */ = {isa = PBXBuildFile; fileRef = 40FDA76A1CCAAA6800442548 /* MBXAnnotationView.m */; }; + 553B1F0B1E267D9500606163 /* MGLThreadPool_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 553B1F091E267D9500606163 /* MGLThreadPool_Private.h */; }; + 553B1F0C1E267D9500606163 /* MGLThreadPool_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 553B1F091E267D9500606163 /* MGLThreadPool_Private.h */; }; + 553B1F0D1E267D9500606163 /* MGLThreadPool.mm in Sources */ = {isa = PBXBuildFile; fileRef = 553B1F0A1E267D9500606163 /* MGLThreadPool.mm */; }; + 553B1F0E1E267D9500606163 /* MGLThreadPool.mm in Sources */ = {isa = PBXBuildFile; fileRef = 553B1F0A1E267D9500606163 /* MGLThreadPool.mm */; }; 554180421D2E97DE00012372 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 554180411D2E97DE00012372 /* OpenGLES.framework */; }; 556660CA1E1BF3A900E2C41B /* MGLFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = 556660C91E1BF3A900E2C41B /* MGLFoundation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 556660D81E1D085500E2C41B /* MGLVersionNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 556660D71E1D085500E2C41B /* MGLVersionNumber.m */; }; @@ -611,6 +615,8 @@ 40F8876F1D7A1DB8008ECB67 /* MGLShapeSource_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLShapeSource_Private.h; sourceTree = ""; }; 40FDA7691CCAAA6800442548 /* MBXAnnotationView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MBXAnnotationView.h; sourceTree = ""; }; 40FDA76A1CCAAA6800442548 /* MBXAnnotationView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MBXAnnotationView.m; sourceTree = ""; }; + 553B1F091E267D9500606163 /* MGLThreadPool_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLThreadPool_Private.h; sourceTree = ""; }; + 553B1F0A1E267D9500606163 /* MGLThreadPool.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLThreadPool.mm; sourceTree = ""; }; 554180411D2E97DE00012372 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; 556660C91E1BF3A900E2C41B /* MGLFoundation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLFoundation.h; sourceTree = ""; }; 556660D71E1D085500E2C41B /* MGLVersionNumber.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = MGLVersionNumber.m; path = ../../darwin/test/MGLVersionNumber.m; sourceTree = ""; }; @@ -1149,6 +1155,8 @@ DA8847EC1CBAFA5100AB86E3 /* MGLStyle.h */, 35E0CFE51D3E501500188327 /* MGLStyle_Private.h */, DA88480F1CBAFA6200AB86E3 /* MGLStyle.mm */, + 553B1F091E267D9500606163 /* MGLThreadPool_Private.h */, + 553B1F0A1E267D9500606163 /* MGLThreadPool.mm */, DA8847EE1CBAFA5100AB86E3 /* MGLTypes.h */, DA8848111CBAFA6200AB86E3 /* MGLTypes.m */, DA8848911CBB049300AB86E3 /* reachability */, @@ -1474,6 +1482,7 @@ 3510FFF01D6D9D8C00F413B2 /* NSExpression+MGLAdditions.h in Headers */, 353AFA141D65AB17005A69F4 /* NSDate+MGLAdditions.h in Headers */, DA8848531CBAFB9800AB86E3 /* MGLCompactCalloutView.h in Headers */, + 553B1F0B1E267D9500606163 /* MGLThreadPool_Private.h in Headers */, DA8847FB1CBAFA5100AB86E3 /* MGLShape.h in Headers */, 353933F51D3FB785003F57D7 /* MGLBackgroundStyleLayer.h in Headers */, DA88485A1CBAFB9800AB86E3 /* MGLUserLocation_Private.h in Headers */, @@ -1568,6 +1577,7 @@ 35B82BF91D6C5F8400B1B721 /* NSPredicate+MGLAdditions.h in Headers */, DA35A2CA1CCAAAD200E826B2 /* NSValue+MGLAdditions.h in Headers */, 350098BC1D480108004B2AF0 /* MGLVectorSource.h in Headers */, + 553B1F0C1E267D9500606163 /* MGLThreadPool_Private.h in Headers */, 353933FC1D3FB7C0003F57D7 /* MGLRasterStyleLayer.h in Headers */, 3566C76D1D4A8DFA008152BC /* MGLRasterSource.h in Headers */, DAED38641D62D0FC00D7640F /* NSURL+MGLAdditions.h in Headers */, @@ -2003,6 +2013,7 @@ 350098BD1D480108004B2AF0 /* MGLVectorSource.mm in Sources */, 3566C76E1D4A8DFA008152BC /* MGLRasterSource.mm in Sources */, DA88488C1CBB037E00AB86E3 /* SMCalloutView.m in Sources */, + 553B1F0D1E267D9500606163 /* MGLThreadPool.mm in Sources */, 35136D4E1D4277FC00C20EFD /* MGLSource.mm in Sources */, DA35A2B81CCA9A5D00E826B2 /* MGLClockDirectionFormatter.m in Sources */, DAD1657A1CF4CDFF001FF4B9 /* MGLShapeCollection.mm in Sources */, @@ -2078,6 +2089,7 @@ 350098BE1D480108004B2AF0 /* MGLVectorSource.mm in Sources */, 3566C76F1D4A8DFA008152BC /* MGLRasterSource.mm in Sources */, DAA4E4351CBB730400178DFB /* SMCalloutView.m in Sources */, + 553B1F0E1E267D9500606163 /* MGLThreadPool.mm in Sources */, 35136D4F1D4277FC00C20EFD /* MGLSource.mm in Sources */, DA35A2B91CCA9A5D00E826B2 /* MGLClockDirectionFormatter.m in Sources */, DAD1657B1CF4CDFF001FF4B9 /* MGLShapeCollection.mm in Sources */, diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj index 6f6aad2436a..dc0aa5e8e24 100644 --- a/platform/macos/macos.xcodeproj/project.pbxproj +++ b/platform/macos/macos.xcodeproj/project.pbxproj @@ -57,6 +57,8 @@ 40B77E461DB11BCD003DA2FE /* NSArray+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 40B77E421DB11BB0003DA2FE /* NSArray+MGLAdditions.mm */; }; 40E1601D1DF217D6005EA6D9 /* MGLStyleLayerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 40E1601B1DF216E6005EA6D9 /* MGLStyleLayerTests.m */; }; 52BECB0A1CC5A26F009CD791 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52BECB091CC5A26F009CD791 /* SystemConfiguration.framework */; }; + 553B1F051E267AD900606163 /* MGLThreadPool_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 553B1F021E267AD900606163 /* MGLThreadPool_Private.h */; }; + 553B1F071E267AD900606163 /* MGLThreadPool.mm in Sources */ = {isa = PBXBuildFile; fileRef = 553B1F041E267AD900606163 /* MGLThreadPool.mm */; }; 5548BE781D09E718005DDE81 /* libmbgl-core.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAE6C3451CC31D1200DB3429 /* libmbgl-core.a */; }; 556660C61E1BEA0100E2C41B /* MGLFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = 556660C51E1BEA0100E2C41B /* MGLFoundation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 556660D61E1D07E400E2C41B /* MGLVersionNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 556660D51E1D07E400E2C41B /* MGLVersionNumber.m */; }; @@ -305,6 +307,8 @@ 40E1601A1DF216E6005EA6D9 /* MGLStyleLayerTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLStyleLayerTests.h; sourceTree = ""; }; 40E1601B1DF216E6005EA6D9 /* MGLStyleLayerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLStyleLayerTests.m; sourceTree = ""; }; 52BECB091CC5A26F009CD791 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; + 553B1F021E267AD900606163 /* MGLThreadPool_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLThreadPool_Private.h; sourceTree = ""; }; + 553B1F041E267AD900606163 /* MGLThreadPool.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLThreadPool.mm; sourceTree = ""; }; 5548BE791D0ACBB2005DDE81 /* libmbgl-loop-darwin.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libmbgl-loop-darwin.a"; path = "cmake/Debug/libmbgl-loop-darwin.a"; sourceTree = ""; }; 5548BE7B1D0ACBBD005DDE81 /* libmbgl-loop-darwin.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libmbgl-loop-darwin.a"; path = "cmake/Debug/libmbgl-loop-darwin.a"; sourceTree = ""; }; 556660C51E1BEA0100E2C41B /* MGLFoundation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLFoundation.h; sourceTree = ""; }; @@ -916,6 +920,8 @@ DAE6C3571CC31E0400DB3429 /* MGLStyle.h */, 3537CA731D3F93A600380318 /* MGLStyle_Private.h */, DAE6C37A1CC31E2A00DB3429 /* MGLStyle.mm */, + 553B1F021E267AD900606163 /* MGLThreadPool_Private.h */, + 553B1F041E267AD900606163 /* MGLThreadPool.mm */, DAE6C3591CC31E0400DB3429 /* MGLTypes.h */, DAE6C37C1CC31E2A00DB3429 /* MGLTypes.m */, DA87A99F1DC9DC6200810D09 /* MGLValueEvaluator.h */, @@ -1009,6 +1015,7 @@ 352742811D4C243B00A1ECE6 /* MGLSource.h in Headers */, DAE6C3C21CC31F4500DB3429 /* Mapbox.h in Headers */, DAE6C3641CC31E0400DB3429 /* MGLPolygon.h in Headers */, + 553B1F051E267AD900606163 /* MGLThreadPool_Private.h in Headers */, DA35A2BF1CCA9B1A00E826B2 /* MGLClockDirectionFormatter.h in Headers */, 35602BFA1D3EA99F0050646F /* MGLFillStyleLayer.h in Headers */, DA35A2A41CC9EB1A00E826B2 /* MGLCoordinateFormatter.h in Headers */, @@ -1267,6 +1274,7 @@ DA35A2D01CCAAED300E826B2 /* NSValue+MGLAdditions.m in Sources */, 3538AA241D542685008EC33D /* MGLStyleLayer.mm in Sources */, DA35A2C01CCA9B1A00E826B2 /* MGLClockDirectionFormatter.m in Sources */, + 553B1F071E267AD900606163 /* MGLThreadPool.mm in Sources */, DAE6C3BA1CC31EF300DB3429 /* MGLOpenGLLayer.mm in Sources */, DAE6C38A1CC31E2A00DB3429 /* MGLMultiPoint.mm in Sources */, DAE6C3961CC31E2A00DB3429 /* MGLTypes.m in Sources */, diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm index 5df5a1f9577..a66f9666b17 100644 --- a/platform/macos/src/MGLMapView.mm +++ b/platform/macos/src/MGLMapView.mm @@ -10,6 +10,7 @@ #import "MGLGeometry_Private.h" #import "MGLMultiPoint_Private.h" #import "MGLOfflineStorage_Private.h" +#import "MGLThreadPool_Private.h" #import "MGLStyle_Private.h" #import "MGLAccountManager.h" @@ -23,7 +24,6 @@ #import #import #import -#import #import #import #import @@ -150,7 +150,6 @@ @implementation MGLMapView { /// Cross-platform map view controller. mbgl::Map *_mbglMap; MGLMapViewImpl *_mbglView; - mbgl::ThreadPool *_mbglThreadPool; NSPanGestureRecognizer *_panGestureRecognizer; NSMagnificationGestureRecognizer *_magnificationGestureRecognizer; @@ -257,10 +256,13 @@ - (void)commonInit { NSURL *legacyCacheURL = [cachesDirectoryURL URLByAppendingPathComponent:@"cache.db"]; [[NSFileManager defaultManager] removeItemAtURL:legacyCacheURL error:NULL]; - mbgl::DefaultFileSource* mbglFileSource = [MGLOfflineStorage sharedOfflineStorage].mbglFileSource; + mbgl::DefaultFileSource* mbglFileSource = + [MGLOfflineStorage sharedOfflineStorage].mbglFileSource; - _mbglThreadPool = new mbgl::ThreadPool(4, { "Worker" }); - _mbglMap = new mbgl::Map(*_mbglView, self.size, [NSScreen mainScreen].backingScaleFactor, *mbglFileSource, *_mbglThreadPool, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None, mbgl::ViewportMode::Default); + _mbglMap = new mbgl::Map(*_mbglView, self.size, [NSScreen mainScreen].backingScaleFactor, + *mbglFileSource, *[MGLThreadPool sharedPool].mbglThreadPool, + mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, + mbgl::ConstrainMode::None, mbgl::ViewportMode::Default); [self validateTileCacheSize]; // Install the OpenGL layer. Interface Builder’s synchronous drawing means @@ -510,10 +512,6 @@ - (void)dealloc { delete _mbglView; _mbglView = nullptr; } - if (_mbglThreadPool) { - delete _mbglThreadPool; - _mbglThreadPool = nullptr; - } } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(__unused NSDictionary *)change context:(void *)context { diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp index 9d3b5dc099d..87eb77554b0 100644 --- a/platform/qt/src/qmapboxgl.cpp +++ b/platform/qt/src/qmapboxgl.cpp @@ -1494,11 +1494,12 @@ QMapboxGLPrivate::QMapboxGLPrivate(QMapboxGL *q, const QMapboxGLSettings &settin : QObject(q) , size(size_) , q_ptr(q) + , threadPool(4, { "Worker" }) , fileSourceObj(std::make_unique( + threadPool, settings.cacheDatabasePath().toStdString(), settings.assetPath().toStdString(), settings.cacheDatabaseMaximumSize())) - , threadPool(4, { "Worker" }) , mapObj(std::make_unique( *this, mbgl::Size{ static_cast(size.width()), static_cast(size.height()) }, pixelRatio, *fileSourceObj, threadPool, diff --git a/platform/qt/src/qmapboxgl_p.hpp b/platform/qt/src/qmapboxgl_p.hpp index 3d2be90273a..f6c13a8e5bd 100644 --- a/platform/qt/src/qmapboxgl_p.hpp +++ b/platform/qt/src/qmapboxgl_p.hpp @@ -37,8 +37,8 @@ class QMapboxGLPrivate : public QObject, public mbgl::View, public mbgl::Backend QMapboxGL *q_ptr { nullptr }; - std::unique_ptr fileSourceObj; mbgl::ThreadPool threadPool; + std::unique_ptr fileSourceObj; std::unique_ptr mapObj; bool dirty { false }; diff --git a/test/api/custom_layer.test.cpp b/test/api/custom_layer.test.cpp index 227523d90a0..afeb87a97e3 100644 --- a/test/api/custom_layer.test.cpp +++ b/test/api/custom_layer.test.cpp @@ -84,19 +84,18 @@ class TestLayer { TEST(CustomLayer, Basic) { util::RunLoop loop; + ThreadPool threadPool{ 4, { "Worker" } }; HeadlessBackend backend { test::sharedDisplay() }; OffscreenView view { backend.getContext() }; #ifdef MBGL_ASSET_ZIP // Regenerate with `cd test/fixtures/api/ && zip -r assets.zip assets/` - DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets.zip"); + DefaultFileSource fileSource(threadPool, ":memory:", "test/fixtures/api/assets.zip"); #else - DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets"); + DefaultFileSource fileSource(threadPool, ":memory:", "test/fixtures/api/assets"); #endif - ThreadPool threadPool{ 4, { "Worker" } }; - Map map(backend, view.size, 1, fileSource, threadPool, MapMode::Still); map.setStyleJSON(util::read_file("test/fixtures/api/water.json")); map.setLatLngZoom({ 37.8, -122.5 }, 10); diff --git a/test/api/render_missing.test.cpp b/test/api/render_missing.test.cpp index 9c53f35102e..8414acc1918 100644 --- a/test/api/render_missing.test.cpp +++ b/test/api/render_missing.test.cpp @@ -22,6 +22,7 @@ TEST(API, TEST_REQUIRES_SERVER(RenderMissingTile)) { using namespace mbgl; util::RunLoop loop; + ThreadPool threadPool{ 4, { "Worker" } }; const auto style = util::read_file("test/fixtures/api/water_missing_tiles.json"); @@ -29,13 +30,11 @@ TEST(API, TEST_REQUIRES_SERVER(RenderMissingTile)) { OffscreenView view { backend.getContext(), { 256, 512 } }; #ifdef MBGL_ASSET_ZIP // Regenerate with `cd test/fixtures/api/ && zip -r assets.zip assets/` - DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets.zip"); + DefaultFileSource fileSource(threadPool, ":memory:", "test/fixtures/api/assets.zip"); #else - DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets"); + DefaultFileSource fileSource(threadPool, ":memory:", "test/fixtures/api/assets"); #endif - ThreadPool threadPool{ 4, { "Worker" } }; - Log::setObserver(std::make_unique()); Map map(backend, view.size, 1, fileSource, threadPool, MapMode::Still); diff --git a/test/api/repeated_render.test.cpp b/test/api/repeated_render.test.cpp index 4ece3c3150c..e0cf3d427fc 100644 --- a/test/api/repeated_render.test.cpp +++ b/test/api/repeated_render.test.cpp @@ -16,8 +16,8 @@ using namespace mbgl; TEST(API, RepeatedRender) { - util::RunLoop loop; + ThreadPool threadPool{ 4, { "Worker" } }; const auto style = util::read_file("test/fixtures/api/water.json"); @@ -25,13 +25,11 @@ TEST(API, RepeatedRender) { OffscreenView view { backend.getContext(), { 256, 512 } }; #ifdef MBGL_ASSET_ZIP // Regenerate with `cd test/fixtures/api/ && zip -r assets.zip assets/` - DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets.zip"); + DefaultFileSource fileSource(threadPool, ":memory:", "test/fixtures/api/assets.zip"); #else - DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets"); + DefaultFileSource fileSource(threadPool, ":memory:", "test/fixtures/api/assets"); #endif - ThreadPool threadPool{ 4, { "Worker" } }; - Log::setObserver(std::make_unique()); Map map(backend, view.size, 1, fileSource, threadPool, MapMode::Still); diff --git a/test/map/map.test.cpp b/test/map/map.test.cpp index 9ee2d45a811..6821e1444af 100644 --- a/test/map/map.test.cpp +++ b/test/map/map.test.cpp @@ -47,7 +47,7 @@ TEST(Map, LatLngBehavior) { TEST(Map, Offline) { MapTest test; - DefaultFileSource fileSource(":memory:", "."); + DefaultFileSource fileSource(test.threadPool, ":memory:", "."); auto expiredItem = [] (const std::string& path) { Response response; @@ -479,9 +479,9 @@ TEST(Map, TEST_DISABLED_ON_CI(ContinuousRendering)) { #ifdef MBGL_ASSET_ZIP // Regenerate with `cd test/fixtures/api/ && zip -r assets.zip assets/` - DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets.zip"); + DefaultFileSource fileSource(threadPool, ":memory:", "test/fixtures/api/assets.zip"); #else - DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets"); + DefaultFileSource fileSource(threadPool, ":memory:", "test/fixtures/api/assets"); #endif Map map(backend, view.size, 1, fileSource, threadPool, MapMode::Continuous); diff --git a/test/storage/default_file_source.test.cpp b/test/storage/default_file_source.test.cpp index f4c23c4c7ae..3949b8271cc 100644 --- a/test/storage/default_file_source.test.cpp +++ b/test/storage/default_file_source.test.cpp @@ -1,12 +1,14 @@ #include #include +#include #include using namespace mbgl; TEST(DefaultFileSource, TEST_REQUIRES_SERVER(CacheResponse)) { util::RunLoop loop; - DefaultFileSource fs(":memory:", "."); + ThreadPool threadPool{ 1, { "Worker" } }; + DefaultFileSource fs(threadPool, ":memory:", "."); const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/cache" }; Response response; @@ -44,7 +46,8 @@ TEST(DefaultFileSource, TEST_REQUIRES_SERVER(CacheResponse)) { TEST(DefaultFileSource, TEST_REQUIRES_SERVER(CacheRevalidateSame)) { util::RunLoop loop; - DefaultFileSource fs(":memory:", "."); + ThreadPool threadPool{ 1, { "Worker" } }; + DefaultFileSource fs(threadPool, ":memory:", "."); const Resource revalidateSame { Resource::Unknown, "http://127.0.0.1:3000/revalidate-same" }; std::unique_ptr req1; @@ -88,7 +91,8 @@ TEST(DefaultFileSource, TEST_REQUIRES_SERVER(CacheRevalidateSame)) { TEST(DefaultFileSource, TEST_REQUIRES_SERVER(CacheRevalidateModified)) { util::RunLoop loop; - DefaultFileSource fs(":memory:", "."); + ThreadPool threadPool{ 1, { "Worker" } }; + DefaultFileSource fs(threadPool, ":memory:", "."); const Resource revalidateModified{ Resource::Unknown, "http://127.0.0.1:3000/revalidate-modified" }; @@ -132,7 +136,8 @@ TEST(DefaultFileSource, TEST_REQUIRES_SERVER(CacheRevalidateModified)) { TEST(DefaultFileSource, TEST_REQUIRES_SERVER(CacheRevalidateEtag)) { util::RunLoop loop; - DefaultFileSource fs(":memory:", "."); + ThreadPool threadPool{ 1, { "Worker" } }; + DefaultFileSource fs(threadPool, ":memory:", "."); const Resource revalidateEtag { Resource::Unknown, "http://127.0.0.1:3000/revalidate-etag" }; std::unique_ptr req1; @@ -187,7 +192,8 @@ TEST(DefaultFileSource, TEST_REQUIRES_SERVER(CacheRevalidateEtag)) { TEST(DefaultFileSource, TEST_REQUIRES_SERVER(HTTPIssue1369)) { util::RunLoop loop; - DefaultFileSource fs(":memory:", "."); + ThreadPool threadPool{ 1, { "Worker" } }; + DefaultFileSource fs(threadPool, ":memory:", "."); const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/test" }; @@ -211,7 +217,8 @@ TEST(DefaultFileSource, TEST_REQUIRES_SERVER(HTTPIssue1369)) { TEST(DefaultFileSource, OptionalNonExpired) { util::RunLoop loop; - DefaultFileSource fs(":memory:", "."); + ThreadPool threadPool{ 1, { "Worker" } }; + DefaultFileSource fs(threadPool, ":memory:", "."); const Resource optionalResource { Resource::Unknown, "http://127.0.0.1:3000/test", {}, Resource::Optional }; @@ -240,7 +247,8 @@ TEST(DefaultFileSource, OptionalNonExpired) { TEST(DefaultFileSource, OptionalExpired) { util::RunLoop loop; - DefaultFileSource fs(":memory:", "."); + ThreadPool threadPool{ 1, { "Worker" } }; + DefaultFileSource fs(threadPool, ":memory:", "."); const Resource optionalResource { Resource::Unknown, "http://127.0.0.1:3000/test", {}, Resource::Optional }; @@ -269,7 +277,8 @@ TEST(DefaultFileSource, OptionalExpired) { TEST(DefaultFileSource, OptionalNotFound) { util::RunLoop loop; - DefaultFileSource fs(":memory:", "."); + ThreadPool threadPool{ 1, { "Worker" } }; + DefaultFileSource fs(threadPool, ":memory:", "."); const Resource optionalResource { Resource::Unknown, "http://127.0.0.1:3000/test", {}, Resource::Optional }; @@ -295,7 +304,8 @@ TEST(DefaultFileSource, OptionalNotFound) { // from cache like a regular request TEST(DefaultFileSource, TEST_REQUIRES_SERVER(NoCacheRefreshEtagNotModified)) { util::RunLoop loop; - DefaultFileSource fs(":memory:", "."); + ThreadPool threadPool{ 1, { "Worker" } }; + DefaultFileSource fs(threadPool, ":memory:", "."); Resource resource { Resource::Unknown, "http://127.0.0.1:3000/revalidate-same" }; resource.priorEtag.emplace("snowfall"); @@ -329,7 +339,8 @@ TEST(DefaultFileSource, TEST_REQUIRES_SERVER(NoCacheRefreshEtagNotModified)) { // from cache like a regular request TEST(DefaultFileSource, TEST_REQUIRES_SERVER(NoCacheRefreshEtagModified)) { util::RunLoop loop; - DefaultFileSource fs(":memory:", "."); + ThreadPool threadPool{ 1, { "Worker" } }; + DefaultFileSource fs(threadPool, ":memory:", "."); Resource resource { Resource::Unknown, "http://127.0.0.1:3000/revalidate-same" }; resource.priorEtag.emplace("sunshine"); @@ -363,7 +374,8 @@ TEST(DefaultFileSource, TEST_REQUIRES_SERVER(NoCacheRefreshEtagModified)) { // from cache like a regular request. TEST(DefaultFileSource, TEST_REQUIRES_SERVER(NoCacheFull)) { util::RunLoop loop; - DefaultFileSource fs(":memory:", "."); + ThreadPool threadPool{ 1, { "Worker" } }; + DefaultFileSource fs(threadPool, ":memory:", "."); Resource resource { Resource::Unknown, "http://127.0.0.1:3000/revalidate-same" }; // Setting any prior field results in skipping the cache. @@ -398,7 +410,8 @@ TEST(DefaultFileSource, TEST_REQUIRES_SERVER(NoCacheFull)) { // from cache like a regular request TEST(DefaultFileSource, TEST_REQUIRES_SERVER(NoCacheRefreshModifiedNotModified)) { util::RunLoop loop; - DefaultFileSource fs(":memory:", "."); + ThreadPool threadPool{ 1, { "Worker" } }; + DefaultFileSource fs(threadPool, ":memory:", "."); Resource resource { Resource::Unknown, "http://127.0.0.1:3000/revalidate-modified" }; resource.priorModified.emplace(Seconds(1420070400)); // January 1, 2015 @@ -432,7 +445,8 @@ TEST(DefaultFileSource, TEST_REQUIRES_SERVER(NoCacheRefreshModifiedNotModified)) // from cache like a regular request TEST(DefaultFileSource, TEST_REQUIRES_SERVER(NoCacheRefreshModifiedModified)) { util::RunLoop loop; - DefaultFileSource fs(":memory:", "."); + ThreadPool threadPool{ 1, { "Worker" } }; + DefaultFileSource fs(threadPool, ":memory:", "."); Resource resource { Resource::Unknown, "http://127.0.0.1:3000/revalidate-modified" }; resource.priorModified.emplace(Seconds(1417392000)); // December 1, 2014 From a720cd6b6bf114a67a8136523a23ad86af2fc8b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Wed, 11 Jan 2017 16:25:15 +0100 Subject: [PATCH 4/5] [core] move default AssetFileSource to use actors --- platform/default/asset_file_source.cpp | 127 +++++++++++++++-------- platform/default/default_file_source.cpp | 4 +- src/mbgl/storage/asset_file_source.hpp | 8 +- test/storage/asset_file_source.test.cpp | 19 ++-- 4 files changed, 104 insertions(+), 54 deletions(-) diff --git a/platform/default/asset_file_source.cpp b/platform/default/asset_file_source.cpp index 1832818378c..de7556b656a 100644 --- a/platform/default/asset_file_source.cpp +++ b/platform/default/asset_file_source.cpp @@ -1,70 +1,115 @@ #include #include +#include #include -#include #include #include -#include +#include + +#include +#include -#include #include +#include #include namespace mbgl { class AssetFileSource::Impl { public: - Impl(std::string root_) - : root(std::move(root_)) { - } + Impl(Scheduler&, const std::string& root); - void request(const std::string& url, FileSource::Callback callback) { - std::string path; + class Request; + std::unique_ptr readFile(const Resource&, Callback); + void respond(std::weak_ptr, Response); - if (url.size() <= 8 || url[8] == '/') { - // This is an empty or absolute path. - path = mbgl::util::percentDecode(url.substr(8)); - } else { - // This is a relative path. Prefix with the application root. - path = root + "/" + mbgl::util::percentDecode(url.substr(8)); - } +private: + std::shared_ptr mailbox{ std::make_shared(*util::RunLoop::Get()) }; + class Worker { + public: + Worker(ActorRef, ActorRef, std::string root); - Response response; - - struct stat buf; - int result = stat(path.c_str(), &buf); - - if (result == 0 && S_ISDIR(buf.st_mode)) { - response.error = std::make_unique(Response::Error::Reason::NotFound); - } else if (result == -1 && errno == ENOENT) { - response.error = std::make_unique(Response::Error::Reason::NotFound); - } else { - try { - response.data = std::make_shared(util::read_file(path)); - } catch (...) { - response.error = std::make_unique( - Response::Error::Reason::Other, - util::toString(std::current_exception())); - } - } + void readFile(const std::string& url, std::weak_ptr); + + private: + ActorRef impl; + const std::string root; + }; + Actor worker; +}; - callback(response); +class AssetFileSource::Impl::Request : public AsyncRequest { +public: + Request(std::shared_ptr callback_) : callback(std::move(callback_)) { } private: - std::string root; + std::shared_ptr callback; }; -AssetFileSource::AssetFileSource(const std::string& root) - : thread(std::make_unique>( - util::ThreadContext{"AssetFileSource", util::ThreadPriority::Low}, - root)) { +AssetFileSource::Impl::Worker::Worker(ActorRef, ActorRef impl_, std::string root_) + : impl(std::move(impl_)), root(std::move(root_)) { +} + +void AssetFileSource::Impl::Worker::readFile(const std::string& url, + std::weak_ptr callback) { + std::string path; + + if (url.size() <= 8 || url[8] == '/') { + // This is an empty or absolute path. + path = mbgl::util::percentDecode(url.substr(8)); + } else { + // This is a relative path. Prefix with the application root. + path = root + "/" + mbgl::util::percentDecode(url.substr(8)); + } + + Response response; + + struct stat buf; + int result = stat(path.c_str(), &buf); + + if (result == 0 && S_ISDIR(buf.st_mode)) { + response.error = std::make_unique(Response::Error::Reason::NotFound); + } else if (result == -1 && errno == ENOENT) { + response.error = std::make_unique(Response::Error::Reason::NotFound); + } else { + try { + response.data = std::make_shared(util::read_file(path)); + } catch (...) { + response.error = std::make_unique( + Response::Error::Reason::Other, util::toString(std::current_exception())); + } + } + + impl.invoke(&Impl::respond, callback, response); +} + +AssetFileSource::Impl::Impl(Scheduler& scheduler, const std::string& root) + : worker(scheduler, ActorRef(*this, mailbox), root) { +} + +std::unique_ptr +AssetFileSource::Impl::readFile(const Resource& resource, Callback callback) { + auto cb = std::make_shared(std::move(callback)); + worker.invoke(&Worker::readFile, resource.url, cb); + return std::make_unique(std::move(cb)); +} + +void AssetFileSource::Impl::respond(std::weak_ptr callback, Response response) { + if (auto locked = callback.lock()) { + (*locked)(response); + } +} + +AssetFileSource::AssetFileSource(Scheduler& scheduler, const std::string& root) + : impl(std::make_unique(scheduler, root)) { } AssetFileSource::~AssetFileSource() = default; -std::unique_ptr AssetFileSource::request(const Resource& resource, Callback callback) { - return thread->invokeWithCallback(&Impl::request, resource.url, callback); +std::unique_ptr AssetFileSource::request(const Resource& resource, + Callback callback) { + return impl->readFile(resource, std::move(callback)); } } // namespace mbgl diff --git a/platform/default/default_file_source.cpp b/platform/default/default_file_source.cpp index 80ddb230504..03a75c5f7e7 100644 --- a/platform/default/default_file_source.cpp +++ b/platform/default/default_file_source.cpp @@ -160,13 +160,13 @@ class DefaultFileSource::Impl { std::unordered_map> downloads; }; -DefaultFileSource::DefaultFileSource(Scheduler&, +DefaultFileSource::DefaultFileSource(Scheduler& scheduler, const std::string& cachePath, const std::string& assetRoot, uint64_t maximumCacheSize) : thread(std::make_unique>(util::ThreadContext{"DefaultFileSource", util::ThreadPriority::Low}, cachePath, maximumCacheSize)), - assetFileSource(std::make_unique(assetRoot)), + assetFileSource(std::make_unique(scheduler, assetRoot)), localFileSource(std::make_unique()) { } diff --git a/src/mbgl/storage/asset_file_source.hpp b/src/mbgl/storage/asset_file_source.hpp index 71e5bbdab36..b3f861fb277 100644 --- a/src/mbgl/storage/asset_file_source.hpp +++ b/src/mbgl/storage/asset_file_source.hpp @@ -4,20 +4,18 @@ namespace mbgl { -namespace util { -template class Thread; -} // namespace util +class Scheduler; class AssetFileSource : public FileSource { public: - AssetFileSource(const std::string& assetRoot); + AssetFileSource(Scheduler&, const std::string& assetRoot); ~AssetFileSource() override; std::unique_ptr request(const Resource&, Callback) override; private: class Impl; - std::unique_ptr> thread; + const std::unique_ptr impl; }; } // namespace mbgl diff --git a/test/storage/asset_file_source.test.cpp b/test/storage/asset_file_source.test.cpp index 7e634fc68ef..24a8a71f3d1 100644 --- a/test/storage/asset_file_source.test.cpp +++ b/test/storage/asset_file_source.test.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -24,7 +25,8 @@ using namespace mbgl; TEST(AssetFileSource, Load) { util::RunLoop loop; - AssetFileSource fs(getFileSourceRoot()); + ThreadPool threadPool{ 1, { "Worker" } }; + AssetFileSource fs(threadPool, getFileSourceRoot()); // iOS seems to run out of file descriptors... #if TARGET_OS_IPHONE || __ANDROID__ @@ -91,7 +93,8 @@ TEST(AssetFileSource, Load) { TEST(AssetFileSource, EmptyFile) { util::RunLoop loop; - AssetFileSource fs(getFileSourceRoot()); + ThreadPool threadPool{ 1, { "Worker" } }; + AssetFileSource fs(threadPool, getFileSourceRoot()); std::unique_ptr req = fs.request({ Resource::Unknown, "asset://empty" }, [&](Response res) { req.reset(); @@ -107,7 +110,8 @@ TEST(AssetFileSource, EmptyFile) { TEST(AssetFileSource, NonEmptyFile) { util::RunLoop loop; - AssetFileSource fs(getFileSourceRoot()); + ThreadPool threadPool{ 1, { "Worker" } }; + AssetFileSource fs(threadPool, getFileSourceRoot()); std::unique_ptr req = fs.request({ Resource::Unknown, "asset://nonempty" }, [&](Response res) { req.reset(); @@ -123,7 +127,8 @@ TEST(AssetFileSource, NonEmptyFile) { TEST(AssetFileSource, NonExistentFile) { util::RunLoop loop; - AssetFileSource fs(getFileSourceRoot()); + ThreadPool threadPool{ 1, { "Worker" } }; + AssetFileSource fs(threadPool, getFileSourceRoot()); std::unique_ptr req = fs.request({ Resource::Unknown, "asset://does_not_exist" }, [&](Response res) { req.reset(); @@ -140,7 +145,8 @@ TEST(AssetFileSource, NonExistentFile) { TEST(AssetFileSource, ReadDirectory) { util::RunLoop loop; - AssetFileSource fs(getFileSourceRoot()); + ThreadPool threadPool{ 1, { "Worker" } }; + AssetFileSource fs(threadPool, getFileSourceRoot()); std::unique_ptr req = fs.request({ Resource::Unknown, "asset://directory" }, [&](Response res) { req.reset(); @@ -157,7 +163,8 @@ TEST(AssetFileSource, ReadDirectory) { TEST(AssetFileSource, URLEncoding) { util::RunLoop loop; - AssetFileSource fs(getFileSourceRoot()); + ThreadPool threadPool{ 1, { "Worker" } }; + AssetFileSource fs(threadPool, getFileSourceRoot()); std::unique_ptr req = fs.request({ Resource::Unknown, "asset://%6eonempty" }, [&](Response res) { req.reset(); From 69b188d8b2dc34e232912d6cae01af55c745dbcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Wed, 11 Jan 2017 17:56:03 +0100 Subject: [PATCH 5/5] [core] also conver Android's AssetFileSource to the actor model --- platform/android/src/asset_file_source.cpp | 66 ++++++++--- platform/default/asset_file_source.cpp | 126 +++++++++------------ src/mbgl/storage/asset_file_source.hpp | 10 +- 3 files changed, 112 insertions(+), 90 deletions(-) diff --git a/platform/android/src/asset_file_source.cpp b/platform/android/src/asset_file_source.cpp index d677d326d8d..2f535df9ac4 100644 --- a/platform/android/src/asset_file_source.cpp +++ b/platform/android/src/asset_file_source.cpp @@ -1,9 +1,13 @@ #include #include +#include #include #include #include +#include +#include + #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wshadow" #include @@ -35,13 +39,23 @@ struct ZipFileHolder { namespace mbgl { -class AssetFileSource::Impl { +class AssetFileRequest : public AsyncRequest { +public: + AssetFileRequest(std::shared_ptr callback_) + : callback(std::move(callback_)) { + } + +private: + std::shared_ptr callback; +}; + +class AssetFileSource::Worker { public: - Impl(const std::string& root_) - : root(root_) { + Worker(ActorRef, ActorRef parent_, std::string root_) + : parent(std::move(parent_)), root(std::move(root_)) { } - void request(const std::string& url, FileSource::Callback callback) { + void readFile(const std::string& url, std::weak_ptr callback) { ZipHolder archive = ::zip_open(root.c_str(), 0, nullptr); if (!archive.archive) { reportError(Response::Error::Reason::Other, "Could not open zip archive", callback); @@ -76,29 +90,55 @@ class AssetFileSource::Impl { Response response; response.data = buf; - callback(response); + + parent.invoke(&AssetFileSource::respond, callback, response); } - void reportError(Response::Error::Reason reason, const char * message, FileSource::Callback callback) { + void reportError(Response::Error::Reason reason, + const char* message, + std::weak_ptr callback) { Response response; response.error = std::make_unique(reason, message); - callback(response); + parent.invoke(&AssetFileSource::respond, callback, response); } private: + ActorRef parent; std::string root; }; -AssetFileSource::AssetFileSource(const std::string& root) - : thread(std::make_unique>( - util::ThreadContext{"AssetFileSource", util::ThreadPriority::Low}, - root)) { +// AssetFileSource::AssetFileSource(const std::string& root) +// : thread(std::make_unique>( +// util::ThreadContext{"AssetFileSource", util::ThreadPriority::Low}, +// root)) { +// } + +// AssetFileSource::~AssetFileSource() = default; + +// std::unique_ptr AssetFileSource::request(const Resource& resource, Callback callback) { +// return thread->invokeWithCallback(&Impl::request, resource.url, callback); +// } + + +AssetFileSource::AssetFileSource(Scheduler& scheduler, const std::string& root) + : mailbox(std::make_shared(*util::RunLoop::Get())), + worker(std::make_unique>( + scheduler, ActorRef(*this, mailbox), root)) { } AssetFileSource::~AssetFileSource() = default; -std::unique_ptr AssetFileSource::request(const Resource& resource, Callback callback) { - return thread->invokeWithCallback(&Impl::request, resource.url, callback); +std::unique_ptr AssetFileSource::request(const Resource& resource, + Callback callback) { + auto cb = std::make_shared(std::move(callback)); + worker->invoke(&Worker::readFile, resource.url, cb); + return std::make_unique(std::move(cb)); +} + +void AssetFileSource::respond(std::weak_ptr callback, Response response) { + if (auto locked = callback.lock()) { + (*locked)(response); + } } } diff --git a/platform/default/asset_file_source.cpp b/platform/default/asset_file_source.cpp index de7556b656a..9ca002039b2 100644 --- a/platform/default/asset_file_source.cpp +++ b/platform/default/asset_file_source.cpp @@ -1,10 +1,10 @@ #include #include #include +#include #include #include #include -#include #include #include @@ -15,101 +15,77 @@ namespace mbgl { -class AssetFileSource::Impl { +class AssetFileRequest : public AsyncRequest { public: - Impl(Scheduler&, const std::string& root); - - class Request; - std::unique_ptr readFile(const Resource&, Callback); - void respond(std::weak_ptr, Response); + AssetFileRequest(std::shared_ptr callback_) + : callback(std::move(callback_)) { + } private: - std::shared_ptr mailbox{ std::make_shared(*util::RunLoop::Get()) }; - class Worker { - public: - Worker(ActorRef, ActorRef, std::string root); - - void readFile(const std::string& url, std::weak_ptr); - - private: - ActorRef impl; - const std::string root; - }; - Actor worker; + std::shared_ptr callback; }; -class AssetFileSource::Impl::Request : public AsyncRequest { +class AssetFileSource::Worker { public: - Request(std::shared_ptr callback_) : callback(std::move(callback_)) { + Worker(ActorRef, ActorRef parent_, std::string root_) + : parent(std::move(parent_)), root(std::move(root_)) { } + void readFile(const std::string& url, std::weak_ptr callback) { + std::string path; + + if (url.size() <= 8 || url[8] == '/') { + // This is an empty or absolute path. + path = mbgl::util::percentDecode(url.substr(8)); + } else { + // This is a relative path. Prefix with the application root. + path = root + "/" + mbgl::util::percentDecode(url.substr(8)); + } -private: - std::shared_ptr callback; -}; - -AssetFileSource::Impl::Worker::Worker(ActorRef, ActorRef impl_, std::string root_) - : impl(std::move(impl_)), root(std::move(root_)) { -} - -void AssetFileSource::Impl::Worker::readFile(const std::string& url, - std::weak_ptr callback) { - std::string path; + Response response; + + struct stat buf; + int result = stat(path.c_str(), &buf); + + if (result == 0 && S_ISDIR(buf.st_mode)) { + response.error = std::make_unique(Response::Error::Reason::NotFound); + } else if (result == -1 && errno == ENOENT) { + response.error = std::make_unique(Response::Error::Reason::NotFound); + } else { + try { + response.data = std::make_shared(util::read_file(path)); + } catch (...) { + response.error = std::make_unique( + Response::Error::Reason::Other, util::toString(std::current_exception())); + } + } - if (url.size() <= 8 || url[8] == '/') { - // This is an empty or absolute path. - path = mbgl::util::percentDecode(url.substr(8)); - } else { - // This is a relative path. Prefix with the application root. - path = root + "/" + mbgl::util::percentDecode(url.substr(8)); + parent.invoke(&AssetFileSource::respond, callback, response); } - Response response; - - struct stat buf; - int result = stat(path.c_str(), &buf); - - if (result == 0 && S_ISDIR(buf.st_mode)) { - response.error = std::make_unique(Response::Error::Reason::NotFound); - } else if (result == -1 && errno == ENOENT) { - response.error = std::make_unique(Response::Error::Reason::NotFound); - } else { - try { - response.data = std::make_shared(util::read_file(path)); - } catch (...) { - response.error = std::make_unique( - Response::Error::Reason::Other, util::toString(std::current_exception())); - } - } +private: + ActorRef parent; + const std::string root; +}; - impl.invoke(&Impl::respond, callback, response); +AssetFileSource::AssetFileSource(Scheduler& scheduler, const std::string& root) + : mailbox(std::make_shared(*util::RunLoop::Get())), + worker(std::make_unique>( + scheduler, ActorRef(*this, mailbox), root)) { } -AssetFileSource::Impl::Impl(Scheduler& scheduler, const std::string& root) - : worker(scheduler, ActorRef(*this, mailbox), root) { -} +AssetFileSource::~AssetFileSource() = default; -std::unique_ptr -AssetFileSource::Impl::readFile(const Resource& resource, Callback callback) { +std::unique_ptr AssetFileSource::request(const Resource& resource, + Callback callback) { auto cb = std::make_shared(std::move(callback)); - worker.invoke(&Worker::readFile, resource.url, cb); - return std::make_unique(std::move(cb)); + worker->invoke(&Worker::readFile, resource.url, cb); + return std::make_unique(std::move(cb)); } -void AssetFileSource::Impl::respond(std::weak_ptr callback, Response response) { +void AssetFileSource::respond(std::weak_ptr callback, Response response) { if (auto locked = callback.lock()) { (*locked)(response); } } -AssetFileSource::AssetFileSource(Scheduler& scheduler, const std::string& root) - : impl(std::make_unique(scheduler, root)) { -} - -AssetFileSource::~AssetFileSource() = default; - -std::unique_ptr AssetFileSource::request(const Resource& resource, - Callback callback) { - return impl->readFile(resource, std::move(callback)); -} - } // namespace mbgl diff --git a/src/mbgl/storage/asset_file_source.hpp b/src/mbgl/storage/asset_file_source.hpp index b3f861fb277..461752a1e64 100644 --- a/src/mbgl/storage/asset_file_source.hpp +++ b/src/mbgl/storage/asset_file_source.hpp @@ -4,7 +4,9 @@ namespace mbgl { +template class Actor; class Scheduler; +class Mailbox; class AssetFileSource : public FileSource { public: @@ -14,8 +16,12 @@ class AssetFileSource : public FileSource { std::unique_ptr request(const Resource&, Callback) override; private: - class Impl; - const std::unique_ptr impl; + void respond(std::weak_ptr, Response); + +private: + std::shared_ptr mailbox; + class Worker; + const std::unique_ptr> worker; }; } // namespace mbgl