diff options
author | Thiago Marcos P. Santos <thiago@mapbox.com> | 2015-06-23 20:08:30 +0300 |
---|---|---|
committer | Thiago Marcos P. Santos <thiago@mapbox.com> | 2015-06-25 16:26:21 +0300 |
commit | a8b6b67dfeb79a2e7904a2aec6354161c4eb1b16 (patch) | |
tree | ffe6ebd296b440287979f8df74b9f59da0ee998d | |
parent | 7bb86368d4730c889f9b1f7007a7bada580db8ea (diff) | |
download | qtlocation-mapboxgl-a8b6b67dfeb79a2e7904a2aec6354161c4eb1b16.tar.gz |
Introduce the ThreadContext
mbgl::Thread will keep a ThreadContext for each running instance
in a thread_local so we don't need to lookup a man in the Environment
every time we need some info about the current thread.
This patch is moving the ::currentlyOn check used on Debug build from
the Environment class to the ThreadContext.
-rw-r--r-- | platform/default/sqlite_cache.cpp | 2 | ||||
-rw-r--r-- | src/mbgl/map/map.cpp | 2 | ||||
-rw-r--r-- | src/mbgl/map/map_context.cpp | 22 | ||||
-rw-r--r-- | src/mbgl/storage/default_file_source.cpp | 2 | ||||
-rw-r--r-- | src/mbgl/style/style.cpp | 6 | ||||
-rw-r--r-- | src/mbgl/util/thread.hpp | 26 | ||||
-rw-r--r-- | src/mbgl/util/thread_context.cpp | 34 | ||||
-rw-r--r-- | src/mbgl/util/thread_context.hpp | 55 | ||||
-rw-r--r-- | src/mbgl/util/uv_detail.hpp | 4 | ||||
-rw-r--r-- | src/mbgl/util/worker.cpp | 3 | ||||
-rw-r--r-- | test/miscellaneous/map_context.cpp | 2 | ||||
-rw-r--r-- | test/miscellaneous/thread.cpp | 2 | ||||
-rw-r--r-- | test/style/mock_file_source.cpp | 2 | ||||
-rw-r--r-- | test/style/resource_loading.cpp | 2 |
14 files changed, 128 insertions, 36 deletions
diff --git a/platform/default/sqlite_cache.cpp b/platform/default/sqlite_cache.cpp index 06d168ce4e..a2d2c6815d 100644 --- a/platform/default/sqlite_cache.cpp +++ b/platform/default/sqlite_cache.cpp @@ -62,7 +62,7 @@ std::string unifyMapboxURLs(const std::string &url) { using namespace mapbox::sqlite; SQLiteCache::SQLiteCache(const std::string& path_) - : thread(std::make_unique<util::Thread<Impl>>("SQLite Cache", util::ThreadPriority::Low, path_)) { + : thread(std::make_unique<util::Thread<Impl>>(util::ThreadContext{"SQLite Cache", util::ThreadType::Unknown, util::ThreadPriority::Low}, path_)) { } SQLiteCache::~SQLiteCache() = default; diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 17bcd29893..c25d307c6e 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -12,7 +12,7 @@ namespace mbgl { Map::Map(View& view, FileSource& fileSource, MapMode mode) : data(std::make_unique<MapData>(view, mode)), - context(std::make_unique<util::Thread<MapContext>>("Map", util::ThreadPriority::Regular, view, fileSource, *data)) + context(std::make_unique<util::Thread<MapContext>>(util::ThreadContext{"Map", util::ThreadType::Map, util::ThreadPriority::Regular}, view, fileSource, *data)) { view.initialize(this); } diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index 69d3c7e215..ecb9d84639 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -33,7 +33,7 @@ MapContext::MapContext(uv_loop_t* loop, View& view_, FileSource& fileSource, Map updated(static_cast<UpdateType>(Update::Nothing)), asyncUpdate(std::make_unique<uv::async>(loop, [this] { update(); })), texturePool(std::make_unique<TexturePool>()) { - assert(Environment::currentlyOn(ThreadType::Map)); + assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); asyncUpdate->unref(); @@ -108,7 +108,7 @@ void MapContext::setStyleJSON(const std::string& json, const std::string& base) } void MapContext::loadStyleJSON(const std::string& json, const std::string& base) { - assert(Environment::currentlyOn(ThreadType::Map)); + assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); style.reset(); style = std::make_unique<Style>(json, base, asyncUpdate->get()->loop, env); @@ -125,13 +125,13 @@ void MapContext::loadStyleJSON(const std::string& json, const std::string& base) } void MapContext::updateTiles() { - assert(Environment::currentlyOn(ThreadType::Map)); + assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); style->update(data, transformState, *texturePool); } void MapContext::updateAnnotationTiles(const std::unordered_set<TileID, TileID::Hash>& ids) { - assert(Environment::currentlyOn(ThreadType::Map)); + assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); data.annotationManager.markStaleTiles(ids); @@ -232,7 +232,7 @@ void MapContext::recalculateStyle(TimePoint now) { } void MapContext::update() { - assert(Environment::currentlyOn(ThreadType::Map)); + assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); const auto now = Clock::now(); data.setAnimationTime(now); @@ -303,7 +303,7 @@ void MapContext::renderStill(StillImageCallback fn) { } void MapContext::render() { - assert(Environment::currentlyOn(ThreadType::Map)); + assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); // Cleanup OpenGL objects that we abandoned since the last render call. env.performCleanup(); @@ -335,13 +335,13 @@ void MapContext::render() { } double MapContext::getTopOffsetPixelsForAnnotationSymbol(const std::string& symbol) { - assert(Environment::currentlyOn(ThreadType::Map)); + assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); const SpritePosition pos = style->sprite->getSpritePosition(symbol); return -pos.height / pos.pixelRatio / 2; } void MapContext::setSourceTileCacheSize(size_t size) { - assert(Environment::currentlyOn(ThreadType::Map)); + assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); if (size != sourceCacheSize) { sourceCacheSize = size; if (!style) return; @@ -353,7 +353,7 @@ void MapContext::setSourceTileCacheSize(size_t size) { } void MapContext::onLowMemory() { - assert(Environment::currentlyOn(ThreadType::Map)); + assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); if (!style) return; for (const auto &source : style->sources) { source->onLowMemory(); @@ -362,12 +362,12 @@ void MapContext::onLowMemory() { } void MapContext::onTileDataChanged() { - assert(Environment::currentlyOn(ThreadType::Map)); + assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); triggerUpdate(); } void MapContext::onResourceLoadingFailed(std::exception_ptr error) { - assert(Environment::currentlyOn(ThreadType::Map)); + assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); if (data.mode == MapMode::Still && callback) { callback(error, nullptr); diff --git a/src/mbgl/storage/default_file_source.cpp b/src/mbgl/storage/default_file_source.cpp index b46696aaa3..dcd0090da1 100644 --- a/src/mbgl/storage/default_file_source.cpp +++ b/src/mbgl/storage/default_file_source.cpp @@ -28,7 +28,7 @@ namespace algo = boost::algorithm; namespace mbgl { DefaultFileSource::DefaultFileSource(FileCache* cache, const std::string& root) - : thread(std::make_unique<util::Thread<Impl>>("FileSource", util::ThreadPriority::Low, cache, root)) { + : thread(std::make_unique<util::Thread<Impl>>(util::ThreadContext{"FileSource", util::ThreadType::Unknown, util::ThreadPriority::Low}, cache, root)) { } DefaultFileSource::~DefaultFileSource() { diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index 0713bda0a2..24771e1859 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -159,7 +159,7 @@ bool Style::isLoaded() const { } void Style::setObserver(Observer* observer_) { - assert(Environment::currentlyOn(ThreadType::Map)); + assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); assert(!observer); observer = observer_; @@ -206,7 +206,7 @@ void Style::onSpriteLoadingFailed(std::exception_ptr error) { } void Style::emitTileDataChanged() { - assert(Environment::currentlyOn(ThreadType::Map)); + assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); if (observer) { observer->onTileDataChanged(); @@ -214,7 +214,7 @@ void Style::emitTileDataChanged() { } void Style::emitResourceLoadingFailed(std::exception_ptr error) { - assert(Environment::currentlyOn(ThreadType::Map)); + assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); try { if (error) { diff --git a/src/mbgl/util/thread.hpp b/src/mbgl/util/thread.hpp index f3a9baa6f3..5bd856cbbc 100644 --- a/src/mbgl/util/thread.hpp +++ b/src/mbgl/util/thread.hpp @@ -8,6 +8,7 @@ #include <functional> #include <mbgl/util/run_loop.hpp> +#include <mbgl/util/thread_context.hpp> #include <mbgl/platform/platform.hpp> namespace mbgl { @@ -21,16 +22,11 @@ namespace util { // Thread<> constructor blocks until the thread and the Object are fully created, so after the // object creation, it's safe to obtain the Object stored in this thread. -enum class ThreadPriority : bool { - Regular, - Low, -}; - template <class Object> class Thread { public: template <class... Args> - Thread(const std::string& name, ThreadPriority priority, Args&&... args); + Thread(const ThreadContext&, Args&&... args); ~Thread(); // Invoke object->fn(args...) in the runloop thread. @@ -81,7 +77,7 @@ private: } template <typename P, std::size_t... I> - void run(P&& params, std::index_sequence<I...>); + void run(ThreadContext, P&& params, std::index_sequence<I...>); std::promise<void> running; std::promise<void> joinable; @@ -94,23 +90,21 @@ private: template <class Object> template <class... Args> -Thread<Object>::Thread(const std::string& name, ThreadPriority priority, Args&&... args) { +Thread<Object>::Thread(const ThreadContext& context, Args&&... args) { // Note: We're using std::tuple<> to store the arguments because GCC 4.9 has a bug // when expanding parameters packs captured in lambdas. std::tuple<Args...> params = std::forward_as_tuple(::std::forward<Args>(args)...); thread = std::thread([&] { #ifdef __APPLE__ - pthread_setname_np(name.c_str()); - #else - (void(name)); + pthread_setname_np(context.name.c_str()); #endif - if (priority == ThreadPriority::Low) { + if (context.priority == ThreadPriority::Low) { platform::makeThreadLowPriority(); } - run(std::move(params), std::index_sequence_for<Args...>{}); + run(context, std::move(params), std::index_sequence_for<Args...>{}); }); running.get_future().get(); @@ -118,10 +112,12 @@ Thread<Object>::Thread(const std::string& name, ThreadPriority priority, Args&&. template <class Object> template <typename P, std::size_t... I> -void Thread<Object>::run(P&& params, std::index_sequence<I...>) { +void Thread<Object>::run(ThreadContext context, P&& params, std::index_sequence<I...>) { uv::loop l; { + ThreadContext::current.set(&context); + RunLoop loop_(l.get()); loop = &loop_; @@ -133,6 +129,8 @@ void Thread<Object>::run(P&& params, std::index_sequence<I...>) { loop = nullptr; object = nullptr; + + ThreadContext::current.set(nullptr); } // Run the loop again to ensure that async close callbacks have been called. diff --git a/src/mbgl/util/thread_context.cpp b/src/mbgl/util/thread_context.cpp new file mode 100644 index 0000000000..6742d5e75e --- /dev/null +++ b/src/mbgl/util/thread_context.cpp @@ -0,0 +1,34 @@ +#include <mbgl/util/thread_context.hpp> + +namespace mbgl { +namespace util { + +class MainThreadContextRegistrar { +public: + MainThreadContextRegistrar() : context("Main", ThreadType::Main, ThreadPriority::Regular) { + ThreadContext::current.set(&context); + } + + ~MainThreadContextRegistrar() { + ThreadContext::current.set(nullptr); + } + +private: + ThreadContext context; +}; + +ThreadContext::ThreadContext(const std::string& name_, ThreadType type_, ThreadPriority priority_) + : name(name_), + type(type_), + priority(priority_) { +} + +uv::tls<ThreadContext> ThreadContext::current; + +// Will auto register the main thread context +// at startup. Must be instantiated after the +// ThreadContext::current object. +MainThreadContextRegistrar registrar; + +} +} diff --git a/src/mbgl/util/thread_context.hpp b/src/mbgl/util/thread_context.hpp new file mode 100644 index 0000000000..d4b56cafa8 --- /dev/null +++ b/src/mbgl/util/thread_context.hpp @@ -0,0 +1,55 @@ +#ifndef MBGL_UTIL_THREAD_CONTEXT +#define MBGL_UTIL_THREAD_CONTEXT + +#include <mbgl/util/uv_detail.hpp> + +#include <cstdint> +#include <string> +#include <thread> + +namespace mbgl { +namespace util { + +enum class ThreadPriority : bool { + Regular, + Low, +}; + +enum class ThreadType : uint8_t { + Main, + Map, + Worker, + Unknown, +}; + +struct ThreadContext { +public: + ThreadContext(const std::string& name, ThreadType type, ThreadPriority priority); + + static bool currentlyOn(ThreadType type) { + return current.get()->type == type; + } + + static std::string getName() { + return current.get()->name; + } + + static ThreadPriority getPriority() { + return current.get()->priority; + } + +private: + std::string name; + ThreadType type; + ThreadPriority priority; + + static uv::tls<ThreadContext> current; + + friend class MainThreadContextRegistrar; + template <class Object> friend class Thread; +}; + +} +} + +#endif diff --git a/src/mbgl/util/uv_detail.hpp b/src/mbgl/util/uv_detail.hpp index 7e2c16a2a3..fc72ab6401 100644 --- a/src/mbgl/util/uv_detail.hpp +++ b/src/mbgl/util/uv_detail.hpp @@ -191,6 +191,10 @@ private: template <class T> class tls : public mbgl::util::noncopyable { public: + inline tls(T* val) { + tls(); + set(val); + } inline tls() { if (uv_key_create(&key) != 0) { throw std::runtime_error("failed to initialize thread local storage key"); diff --git a/src/mbgl/util/worker.cpp b/src/mbgl/util/worker.cpp index 3022d30277..1806ba78ce 100644 --- a/src/mbgl/util/worker.cpp +++ b/src/mbgl/util/worker.cpp @@ -18,8 +18,9 @@ public: }; Worker::Worker(std::size_t count) { + util::ThreadContext context = {"Worker", util::ThreadType::Worker, util::ThreadPriority::Low}; for (std::size_t i = 0; i < count; i++) { - threads.emplace_back(std::make_unique<util::Thread<Impl>>("Worker", util::ThreadPriority::Low)); + threads.emplace_back(std::make_unique<util::Thread<Impl>>(context)); } } diff --git a/test/miscellaneous/map_context.cpp b/test/miscellaneous/map_context.cpp index 15061b1225..6e9ed85c3f 100644 --- a/test/miscellaneous/map_context.cpp +++ b/test/miscellaneous/map_context.cpp @@ -15,7 +15,7 @@ TEST(MapContext, DoubleStyleLoad) { DefaultFileSource fileSource(nullptr); MapData data(view, MapMode::Continuous); - util::Thread<MapContext> context("Map", util::ThreadPriority::Regular, view, fileSource, data); + util::Thread<MapContext> context({"Map", util::ThreadType::Map, util::ThreadPriority::Regular}, view, fileSource, data); context.invokeSync(&MapContext::setStyleJSON, "", ""); context.invokeSync(&MapContext::setStyleJSON, "", ""); diff --git a/test/miscellaneous/thread.cpp b/test/miscellaneous/thread.cpp index b0dd2210e9..9767bc4b79 100644 --- a/test/miscellaneous/thread.cpp +++ b/test/miscellaneous/thread.cpp @@ -64,7 +64,7 @@ TEST(Thread, invoke) { loop.invoke([&] { EXPECT_EQ(tid, std::this_thread::get_id()); - Thread<TestObject> thread("Test", ThreadPriority::Regular, tid); + Thread<TestObject> thread({"Test", ThreadType::Map, ThreadPriority::Regular}, tid); thread.invoke(&TestObject::fn1, 1); thread.invokeWithResult<int>(&TestObject::fn2, [&] (int result) { diff --git a/test/style/mock_file_source.cpp b/test/style/mock_file_source.cpp index 0f2d93f71f..6aa735d0ea 100644 --- a/test/style/mock_file_source.cpp +++ b/test/style/mock_file_source.cpp @@ -133,7 +133,7 @@ void MockFileSource::Impl::dispatchPendingRequests() { } MockFileSource::MockFileSource(Type type, const std::string& match) - : thread_(std::make_unique<util::Thread<Impl>>("FileSource", util::ThreadPriority::Low, type, match)) { + : thread_(std::make_unique<util::Thread<Impl>>(util::ThreadContext{"FileSource", util::ThreadType::Unknown, util::ThreadPriority::Low}, type, match)) { } void MockFileSource::setOnRequestDelayedCallback(std::function<void(void)> callback) { diff --git a/test/style/resource_loading.cpp b/test/style/resource_loading.cpp index fb6ba744a9..158af25909 100644 --- a/test/style/resource_loading.cpp +++ b/test/style/resource_loading.cpp @@ -117,7 +117,7 @@ void runTestCase(MockFileSource::Type type, std::unique_ptr<util::Thread<MockMapContext>> context( std::make_unique<util::Thread<MockMapContext>>( - "Map", util::ThreadPriority::Regular, view, fileSource, callback)); + util::ThreadContext{"Map", util::ThreadType::Map, util::ThreadPriority::Regular}, view, fileSource, callback)); uv_run(loop.get(), UV_RUN_DEFAULT); |