From c6b98a504f95f128e65ecdb6718614086c642c5d Mon Sep 17 00:00:00 2001 From: Georg Baum Date: Mon, 8 Dec 2014 22:25:40 +0100 Subject: [PATCH] Make Encoding class thread-safe Now all const methods may be called without additional locking. This is assumed by the threaded LaTeX export, which always useses a globally unique instance for each encoding. --- src/Encoding.cpp | 35 +++++++++++++++++++++++++++-------- src/Encoding.h | 12 ++++++++---- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/src/Encoding.cpp b/src/Encoding.cpp index 2d5e32b3e2..c4fb1d581a 100644 --- a/src/Encoding.cpp +++ b/src/Encoding.cpp @@ -19,6 +19,7 @@ #include "support/debug.h" #include "support/gettext.h" #include "support/lstrings.h" +#include "support/mutex.h" #include "support/textutils.h" #include "support/unicode.h" @@ -105,10 +106,28 @@ Encoding::Encoding(string const & n, string const & l, string const & g, void Encoding::init() const { + // Since the the constructor is the only method which sets complete_ + // to false the test for complete_ is thread-safe without mutex. if (complete_) return; - start_encodable_ = 0; + static Mutex mutex; + Mutex::Locker lock(&mutex); + + // We need to test again for complete_, since another thread could + // have set it to true while we were waiting for the lock and we must + // not modify an encoding which is already complete. + if (complete_) + return; + + // We do not make any member mutable so that it can be easily verified + // that all const methods are thread-safe: init() is the only const + // method which changes complete_, encodable_ and start_encodable_, and + // it uses a mutex to ensure thread-safety. + CharSet & encodable = const_cast(this)->encodable_; + char_type & start_encodable = const_cast(this)->start_encodable_; + + start_encodable = 0; // temporarily switch off lyxerr, since we will generate iconv errors lyxerr.disable(); if (fixedwidth_) { @@ -122,10 +141,10 @@ void Encoding::init() const char_type const uc = ucs4[0]; CharInfoMap::const_iterator const it = unicodesymbols.find(uc); if (it == unicodesymbols.end()) - encodable_.insert(uc); + encodable.insert(uc); else if (!it->second.force()) { if (forced_->empty() || forced_->find(uc) == forced_->end()) - encodable_.insert(uc); + encodable.insert(uc); } } } else { @@ -138,10 +157,10 @@ void Encoding::init() const if (!eightbit.empty()) { CharInfoMap::const_iterator const it = unicodesymbols.find(c); if (it == unicodesymbols.end()) - encodable_.insert(c); + encodable.insert(c); else if (!it->second.force()) { if (forced_->empty() || forced_->find(c) == forced_->end()) - encodable_.insert(c); + encodable.insert(c); } } } @@ -149,11 +168,11 @@ void Encoding::init() const lyxerr.enable(); CharSet::iterator it = encodable_.find(start_encodable_); while (it != encodable_.end()) { - encodable_.erase(it); - ++start_encodable_; + encodable.erase(it); + ++start_encodable; it = encodable_.find(start_encodable_); } - complete_ = true; + const_cast(this)->complete_ = true; } diff --git a/src/Encoding.h b/src/Encoding.h index ebdfb98b0c..00d0106b54 100644 --- a/src/Encoding.h +++ b/src/Encoding.h @@ -109,7 +109,11 @@ private: }; -/// +/** + * An encoding as defined in lib/encodings. + * All const methods are thread-safe, so the caller does not need any locking. + * This property must be kept when changing the class. + */ class Encoding { public: /// Which LaTeX package handles this encoding? @@ -195,13 +199,13 @@ private: typedef std::set CharSet; /// Set of UCS4 characters that we can encode (for singlebyte /// encodings only) - mutable CharSet encodable_; + CharSet encodable_; /// Set of UCS4 characters that we can't encode CharSet const * forced_; /// All code points below this are encodable. This helps us to avoid /// lokup of ASCII characters in encodable_ and gives about 1 sec /// speedup on export of the Userguide. - mutable char_type start_encodable_; + char_type start_encodable_; /// Which LaTeX package handles this encoding? Package package_; /** @@ -211,7 +215,7 @@ private: * This is needed especially for the multibyte encodings, if we * complete all encoding info on startup it takes 2-3 minutes. */ - mutable bool complete_; + bool complete_; }; class Encodings {