diff --git a/common/lib_table_base.cpp b/common/lib_table_base.cpp index 525d9ddfd6..8b72713027 100644 --- a/common/lib_table_base.cpp +++ b/common/lib_table_base.cpp @@ -185,6 +185,8 @@ LIB_TABLE_ROW* LIB_TABLE::findRow( const wxString& aNickName, bool aCheckIfEnabl LIB_TABLE_ROW* row = nullptr; LIB_TABLE* cur = (LIB_TABLE*) this; + std::lock_guard lock( m_nickIndexMutex ); + do { cur->ensureIndex(); @@ -301,6 +303,8 @@ std::vector LIB_TABLE::GetLogicalLibs() bool LIB_TABLE::InsertRow( LIB_TABLE_ROW* aRow, bool doReplace ) { + std::lock_guard lock( m_nickIndexMutex ); + ensureIndex(); INDEX_CITER it = nickIndex.find( aRow->GetNickName() ); diff --git a/common/template_fieldnames.cpp b/common/template_fieldnames.cpp index f114f37f7c..3375638ee3 100644 --- a/common/template_fieldnames.cpp +++ b/common/template_fieldnames.cpp @@ -22,6 +22,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#include + #include #include #include @@ -33,6 +35,8 @@ using namespace TFIELD_T; #define FTPCANONICAL "Footprint" #define DSHCANONICAL "Datasheet" +static std::mutex s_defaultFieldMutex; + const wxString TEMPLATE_FIELDNAME::GetDefaultFieldName( int aFieldNdx, bool aTranslate ) { static void* locale = nullptr; @@ -53,6 +57,10 @@ const wxString TEMPLATE_FIELDNAME::GetDefaultFieldName( int aFieldNdx, bool aTra } } + // Mutex protection is needed so that multiple loader threads don't write to the static variables + // at once + std::lock_guard lock( s_defaultFieldMutex ); + // Fetching translations can take a surprising amount of time when loading libraries, // so only do it when necessary. if( Pgm().GetLocale() != locale ) diff --git a/eeschema/class_library.cpp b/eeschema/class_library.cpp index 234281d8f5..1d00a366c2 100644 --- a/eeschema/class_library.cpp +++ b/eeschema/class_library.cpp @@ -56,7 +56,7 @@ PART_LIB::PART_LIB( SCH_LIB_TYPE aType, const wxString& aFileName, SCH_IO_MGR::SCH_FILE_T aPluginType ) : // start @ != 0 so each additional library added // is immediately detectable, zero would not be. - m_mod_hash( PART_LIBS::s_modify_generation ), + m_mod_hash( PART_LIBS::GetModifyGeneration() ), m_pluginType( aPluginType ) { type = aType; @@ -413,7 +413,8 @@ void PART_LIBS::FindLibraryNearEntries( std::vector& aCandidates, } -int PART_LIBS::s_modify_generation = 1; // starts at 1 and goes up +int PART_LIBS::s_modify_generation = 1; // starts at 1 and goes up +std::mutex PART_LIBS::s_generationMutex; int PART_LIBS::GetModifyHash() @@ -428,7 +429,7 @@ int PART_LIBS::GetModifyHash() // Rebuilding the cache (m_cache) does not change the GetModHash() value, // but changes PART_LIBS::s_modify_generation. // Take this change in account: - hash += PART_LIBS::s_modify_generation; + hash += PART_LIBS::GetModifyGeneration(); return hash; } diff --git a/eeschema/class_library.h b/eeschema/class_library.h index cc6f27a027..40e2e65631 100644 --- a/eeschema/class_library.h +++ b/eeschema/class_library.h @@ -32,6 +32,7 @@ #define CLASS_LIBRARY_H #include +#include #include #include @@ -197,11 +198,24 @@ class PART_LIBS : public PART_LIBS_BASE, public PROJECT::_ELEM public: KICAD_T Type() override { return PART_LIBS_T; } - static int s_modify_generation; ///< helper for GetModifyHash() + static int s_modify_generation; ///< helper for GetModifyHash() + static std::mutex s_generationMutex; PART_LIBS() { - ++s_modify_generation; + IncrementModifyGeneration(); + } + + static void IncrementModifyGeneration() + { + std::lock_guard mut( PART_LIBS::s_generationMutex ); + ++PART_LIBS::s_modify_generation; + } + + static int GetModifyGeneration() + { + std::lock_guard mut( PART_LIBS::s_generationMutex ); + return PART_LIBS::s_modify_generation; } /// Return the modification hash for all libraries. The value returned diff --git a/eeschema/eeschema_config.cpp b/eeschema/eeschema_config.cpp index b4d90b883d..4378bba585 100644 --- a/eeschema/eeschema_config.cpp +++ b/eeschema/eeschema_config.cpp @@ -21,6 +21,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#include + #include #include #include @@ -224,8 +226,14 @@ void SYMBOL_EDIT_FRAME::InstallPreferences( PAGED_DIALOG* aParent, } +static std::mutex s_symbolTableMutex; + + SYMBOL_LIB_TABLE* PROJECT::SchSymbolLibTable() { + wxLogDebug( "Getting symbol lib table" ); + std::lock_guard lock( s_symbolTableMutex ); + // This is a lazy loading function, it loads the project specific table when // that table is asked for, not before. SYMBOL_LIB_TABLE* tbl = (SYMBOL_LIB_TABLE*) GetElem( ELEM_SYMBOL_LIB_TABLE ); diff --git a/eeschema/sch_plugins/kicad/sch_sexpr_plugin.cpp b/eeschema/sch_plugins/kicad/sch_sexpr_plugin.cpp index f45133c0c8..f71fc517df 100644 --- a/eeschema/sch_plugins/kicad/sch_sexpr_plugin.cpp +++ b/eeschema/sch_plugins/kicad/sch_sexpr_plugin.cpp @@ -777,7 +777,7 @@ void SCH_SEXPR_PLUGIN::Format( SCH_SHEET* aSheet ) } -void SCH_SEXPR_PLUGIN::Format( EE_SELECTION* aSelection, SCH_SHEET_PATH* aSheetPath, +void SCH_SEXPR_PLUGIN::Format( EE_SELECTION* aSelection, SCH_SHEET_PATH* aSheetPath, OUTPUTFORMATTER* aFormatter ) { wxCHECK( aSelection && aFormatter, /* void */ ); @@ -2094,7 +2094,7 @@ void SCH_SEXPR_PLUGIN::cacheLib( const wxString& aLibraryFileName, const PROPERT // Because m_cache is rebuilt, increment PART_LIBS::s_modify_generation // to modify the hash value that indicate component to symbol links // must be updated. - PART_LIBS::s_modify_generation++; + PART_LIBS::IncrementModifyGeneration(); if( !isBuffering( aProperties ) ) m_cache->Load(); diff --git a/eeschema/sch_plugins/legacy/sch_legacy_plugin.cpp b/eeschema/sch_plugins/legacy/sch_legacy_plugin.cpp index cc04ba0ae6..6e61e9d580 100644 --- a/eeschema/sch_plugins/legacy/sch_legacy_plugin.cpp +++ b/eeschema/sch_plugins/legacy/sch_legacy_plugin.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -476,8 +477,7 @@ static void parseQuotedString( wxString& aString, LINE_READER& aReader, */ class SCH_LEGACY_PLUGIN_CACHE { - static int m_modHash; // Keep track of the modification status of the library. - + static int s_modHash; // Keep track of the modification status of the library. wxString m_fileName; // Absolute path and file name. wxFileName m_libFileName; // Absolute path and file name is required here. wxDateTime m_fileModTime; @@ -523,11 +523,23 @@ class SCH_LEGACY_PLUGIN_CACHE friend SCH_LEGACY_PLUGIN; + static std::mutex s_modHashMutex; + public: SCH_LEGACY_PLUGIN_CACHE( const wxString& aLibraryPath ); ~SCH_LEGACY_PLUGIN_CACHE(); - int GetModifyHash() const { return m_modHash; } + static void IncrementModifyHash() + { + std::lock_guard mut( SCH_LEGACY_PLUGIN_CACHE::s_modHashMutex ); + SCH_LEGACY_PLUGIN_CACHE::s_modHash++; + } + + static int GetModifyHash() + { + std::lock_guard mut( SCH_LEGACY_PLUGIN_CACHE::s_modHashMutex ); + return SCH_LEGACY_PLUGIN_CACHE::s_modHash; + } // Most all functions in this class throw IO_ERROR exceptions. There are no // error codes nor user interface calls from here, nor in any SCH_PLUGIN objects. @@ -2395,7 +2407,8 @@ void SCH_LEGACY_PLUGIN::saveBusAlias( std::shared_ptr aAlias ) } -int SCH_LEGACY_PLUGIN_CACHE::m_modHash = 1; // starts at 1 and goes up +int SCH_LEGACY_PLUGIN_CACHE::s_modHash = 1; // starts at 1 and goes up +std::mutex SCH_LEGACY_PLUGIN_CACHE::s_modHashMutex; SCH_LEGACY_PLUGIN_CACHE::SCH_LEGACY_PLUGIN_CACHE( const wxString& aFullPathAndFileName ) : @@ -2533,7 +2546,7 @@ LIB_PART* SCH_LEGACY_PLUGIN_CACHE::removeSymbol( LIB_PART* aPart ) m_symbols.erase( it ); delete aPart; m_isModified = true; - ++m_modHash; + SCH_LEGACY_PLUGIN_CACHE::IncrementModifyHash(); return firstChild; } @@ -2551,7 +2564,7 @@ void SCH_LEGACY_PLUGIN_CACHE::AddSymbol( const LIB_PART* aPart ) m_symbols[ name ] = const_cast< LIB_PART* >( aPart ); m_isModified = true; - ++m_modHash; + SCH_LEGACY_PLUGIN_CACHE::IncrementModifyHash(); } @@ -2631,7 +2644,7 @@ void SCH_LEGACY_PLUGIN_CACHE::Load() } } - ++m_modHash; + SCH_LEGACY_PLUGIN_CACHE::IncrementModifyHash(); // Remember the file modification time of library file when the // cache snapshot was made, so that in a networked environment we will @@ -4199,7 +4212,7 @@ void SCH_LEGACY_PLUGIN_CACHE::DeleteSymbol( const wxString& aSymbolName ) delete part; } - ++m_modHash; + SCH_LEGACY_PLUGIN_CACHE::IncrementModifyHash(); m_isModified = true; } @@ -4215,7 +4228,7 @@ void SCH_LEGACY_PLUGIN::cacheLib( const wxString& aLibraryFileName, const PROPER // Because m_cache is rebuilt, increment PART_LIBS::s_modify_generation // to modify the hash value that indicate component to symbol links // must be updated. - PART_LIBS::s_modify_generation++; + PART_LIBS::IncrementModifyGeneration(); if( !isBuffering( aProperties ) ) m_cache->Load(); @@ -4243,7 +4256,7 @@ bool SCH_LEGACY_PLUGIN::isBuffering( const PROPERTIES* aProperties ) int SCH_LEGACY_PLUGIN::GetModifyHash() const { if( m_cache ) - return m_cache->GetModifyHash(); + return SCH_LEGACY_PLUGIN_CACHE::GetModifyHash(); // If the cache hasn't been loaded, it hasn't been modified. return 0; diff --git a/include/lib_table_base.h b/include/lib_table_base.h index 382087f9b8..fbd4f9af2b 100644 --- a/include/lib_table_base.h +++ b/include/lib_table_base.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -318,6 +319,8 @@ public: /// Delete all rows. void Clear() { + std::lock_guard lock( m_nickIndexMutex ); + rows.clear(); nickIndex.clear(); } @@ -501,6 +504,8 @@ protected: void reindex() { + std::lock_guard lock( m_nickIndexMutex ); + nickIndex.clear(); for( LIB_TABLE_ROWS_ITER it = rows.begin(); it != rows.end(); ++it ) @@ -509,6 +514,8 @@ protected: void ensureIndex() { + std::lock_guard lock( m_nickIndexMutex ); + // The dialog lib table editor may not maintain the nickIndex. // Lazy indexing may be required. To handle lazy indexing, we must enforce // that "nickIndex" is either empty or accurate, but never inaccurate. @@ -533,6 +540,9 @@ protected: INDEX nickIndex; LIB_TABLE* fallBack; + + /// Mutex to protect access to the nickIndex variable + mutable std::recursive_mutex m_nickIndexMutex; }; #endif // _LIB_TABLE_BASE_H_