diff --git a/include/mbgl/util/uv.hpp b/include/mbgl/util/uv.hpp index 169bee19124..1183394681b 100644 --- a/include/mbgl/util/uv.hpp +++ b/include/mbgl/util/uv.hpp @@ -60,6 +60,39 @@ class writelock { rwlock *mtx = nullptr; }; +template +class exclusive { +public: + exclusive(T& val, mutex &mtx) : ptr(&val), lock(mtx) {} + exclusive(T *val, mutex &mtx) : ptr(val), lock(mtx) {} + exclusive(mutex &mtx) : lock(mtx) {} + exclusive(const std::unique_ptr &mtx) : lock(mtx) {} + exclusive(const exclusive &) = delete; + exclusive(exclusive &&) = default; + exclusive &operator=(const exclusive &) = delete; + exclusive &operator=(exclusive &&) = default; + + T *operator->() { return ptr; } + const T *operator->() const { return ptr; } + T *operator*() { return ptr; } + const T *operator*() const { return ptr; } + operator T&() { return *ptr; } + operator const T&() const { return *ptr; } + + void operator<<(T& val) { operator<<(&val); } + void operator<<(T *val) { + if (ptr) { + throw std::runtime_error("exclusive<> was assigned before"); + } + ptr = val; + } + +private: + T *ptr = nullptr; + lock lock; +}; + + const char *getFileRequestError(uv_fs_t *req); diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/symbol_bucket.cpp index 99961759980..63630e1c06c 100644 --- a/src/mbgl/renderer/symbol_bucket.cpp +++ b/src/mbgl/renderer/symbol_bucket.cpp @@ -172,7 +172,7 @@ void SymbolBucket::addFeatures(const VectorTileLayer &layer, const FilterExpress if (layout.text.justify == TextJustifyType::Right) justify = 1; else if (layout.text.justify == TextJustifyType::Left) justify = 0; - const FontStack &fontStack = glyphStore.getFontStack(layout.text.font); + const auto &fontStack = glyphStore.getFontStack(layout.text.font); for (const SymbolFeature &feature : features) { if (!feature.geometry.size()) continue; @@ -183,7 +183,7 @@ void SymbolBucket::addFeatures(const VectorTileLayer &layer, const FilterExpress // if feature has text, shape the text if (feature.label.length()) { - shaping = fontStack.getShaping( + shaping = fontStack->getShaping( /* string */ feature.label, /* maxWidth: ems */ layout.text.max_width * 24, /* lineHeight: ems */ layout.text.line_height * 24, diff --git a/src/mbgl/text/glyph_store.cpp b/src/mbgl/text/glyph_store.cpp index 0d9e70d556c..f89f42e909b 100644 --- a/src/mbgl/text/glyph_store.cpp +++ b/src/mbgl/text/glyph_store.cpp @@ -223,7 +223,7 @@ void GlyphPBF::parse(FontStack &stack) { data.clear(); } -GlyphStore::GlyphStore(FileSource& fileSource_) : fileSource(fileSource_) {} +GlyphStore::GlyphStore(FileSource& fileSource_) : fileSource(fileSource_), mtx(util::make_unique()) {} void GlyphStore::setURL(const std::string &url) { glyphURL = url; @@ -237,15 +237,14 @@ void GlyphStore::waitForGlyphRanges(const std::string &fontStack, const std::set return; } - FontStack *stack = nullptr; + uv::exclusive stack(mtx); std::vector> futures; futures.reserve(glyphRanges.size()); { - std::lock_guard lock(mtx); auto &rangeSets = ranges[fontStack]; - stack = &createFontStack(fontStack); + stack << createFontStack(fontStack); // Attempt to load the glyph range. If the GlyphSet already exists, we are getting back // the same shared_future. @@ -258,7 +257,7 @@ void GlyphStore::waitForGlyphRanges(const std::string &fontStack, const std::set // When we get a result (or the GlyphSet is aready loaded), we are attempting to parse the // GlyphSet. for (std::shared_future &future : futures) { - future.get().parse(*stack); + future.get().parse(stack); } } @@ -277,12 +276,14 @@ FontStack &GlyphStore::createFontStack(const std::string &fontStack) { if (stack_it == stacks.end()) { stack_it = stacks.emplace(fontStack, util::make_unique()).first; } + return *stack_it->second.get(); } -FontStack &GlyphStore::getFontStack(const std::string &fontStack) { - std::lock_guard lock(mtx); - return createFontStack(fontStack); +uv::exclusive GlyphStore::getFontStack(const std::string &fontStack) { + uv::exclusive stack(mtx); + stack << createFontStack(fontStack); + return stack; } diff --git a/src/mbgl/text/glyph_store.hpp b/src/mbgl/text/glyph_store.hpp index 95ab92f307c..6839045d61c 100644 --- a/src/mbgl/text/glyph_store.hpp +++ b/src/mbgl/text/glyph_store.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -76,7 +77,7 @@ class GlyphStore { // Block until all specified GlyphRanges of the specified font stack are loaded. void waitForGlyphRanges(const std::string &fontStack, const std::set &glyphRanges); - FontStack &getFontStack(const std::string &fontStack); + uv::exclusive getFontStack(const std::string &fontStack); void setURL(const std::string &url); @@ -90,7 +91,7 @@ class GlyphStore { FileSource& fileSource; std::unordered_map>> ranges; std::unordered_map> stacks; - std::mutex mtx; + std::unique_ptr mtx; };