/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2011 Jean-Pierre Charras, * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck * Copyright (C) 1992-2013 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, you may find one here: * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * or you may search the http://www.gnu.org website for the version 2 license, * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /** * @file footprint_info.cpp */ #define USE_WORKER_THREADS 1 // 1:yes, 0:no. use worker thread to load libraries /* * Functions to read footprint libraries and fill m_footprints by available footprints names * and their documentation (comments and keywords) */ #include #include #include #include #include #include #include #include #include #include #include /* static wxString ToHTMLFragment( const IO_ERROR* aDerivative ) { @todo 1) change up IO_ERROR so it keeps linenumbers, source file name and error message in separate strings. 2) Add a summarizing virtual member like virtual wxString What() to combine all portions of an IO_ERROR's text into a single wxString. 3) Do same for PARSE_ERROR. 4) Add a "reason or error category" to IO_ERROR and thereby also PARSE_ERROR? msg += " for( int i=0; i" ); for ( unsigned ii = 0; ii < strings_list->GetCount(); ii++ ) { msg += wxT( "
  • " ); msg += strings_list->Item( ii ) + wxT( "
  • " ); } msg += wxT( "" ); m_htmlWindow->AppendToPage( msg ); delete strings_list; } */ void FOOTPRINT_INFO::load() { FP_LIB_TABLE* fptable = m_owner->GetTable(); wxASSERT( fptable ); std::auto_ptr m( fptable->FootprintLoad( m_nickname, m_fpname ) ); if( m.get() == NULL ) // Should happen only with malformed/broken libraries { m_pad_count = 0; m_unique_pad_count = 0; } else { m_pad_count = m->GetPadCount( DO_NOT_INCLUDE_NPTH ); m_unique_pad_count = m->GetUniquePadCount( DO_NOT_INCLUDE_NPTH ); m_keywords = m->GetKeywords(); m_doc = m->GetDescription(); // tell ensure_loaded() I'm loaded. m_loaded = true; } } #define JOBZ 6 // no. libraries per worker thread. It takes about // a second to load a GITHUB library, so assigning // this no. libraries to each thread should give a little // over this no. seconds total time if the original delay // were caused by latencies alone. // (If https://github.com does not mind.) #define NTOLERABLE_ERRORS 4 // max errors before aborting, although threads // in progress will still pile on for a bit. e.g. if 9 threads // expect 9 greater than this. void FOOTPRINT_LIST::loader_job( const wxString* aNicknameList, int aJobZ ) { //DBG(printf( "%s: first:'%s' count:%d\n", __func__, (char*) TO_UTF8( *aNicknameList ), aJobZ );) for( int i=0; i= NTOLERABLE_ERRORS ) break; const wxString& nickname = aNicknameList[i]; try { wxArrayString fpnames = m_lib_table->FootprintEnumerate( nickname ); for( unsigned ni=0; ni nicknames; // do all of them nicknames = aTable->GetLogicalLibs(); #if USE_WORKER_THREADS // Even though the PLUGIN API implementation is the place for the // locale toggling, in order to keep LOCAL_IO::C_count at 1 or greater // for the duration of all helper threads, we increment by one here via instantiation. // Only done here because of the multi-threaded nature of this code. // Without this C_count skips in and out of "equal to zero" and causes // needless locale toggling among the threads, based on which of them // are in a PLUGIN::FootprintLoad() function. And that is occasionally // none of them. LOCALE_IO top_most_nesting; // Something which will not invoke a thread copy constructor, one of many ways obviously: typedef boost::ptr_vector< boost::thread > MYTHREADS; MYTHREADS threads; // Give each thread JOBZ nicknames to process. The last portion of, or if the entire // size() is small, I'll do myself. for( unsigned i=0; i= NTOLERABLE_ERRORS ) { // abort the remaining nicknames. retv = false; break; } int jobz = JOBZ; if( i + jobz >= nicknames.size() ) { jobz = nicknames.size() - i; // Only a little bit to do, I'll do it myself, on current thread. loader_job( &nicknames[i], jobz ); } else { // Delegate the job to a worker thread created here. threads.push_back( new boost::thread( &FOOTPRINT_LIST::loader_job, this, &nicknames[i], jobz ) ); } i += jobz; } // Wait for all the worker threads to complete, it does not matter in what order // we wait for them as long as a full sweep is made. Think of the great race, // everyone must finish. for( unsigned i=0; i // until scaffolding goes. void FOOTPRINT_LIST::DisplayErrors( wxTopLevelWindow* aWindow ) { #if 1 // scaffolding until a better one is written, hopefully below. DBG(printf( "m_error_count:%d\n", m_error_count );) wxString msg = _( "Errors were encountered loading footprints" ); msg += wxT( '\n' ); for( unsigned i = 0; i! ? centric output, possibly with // recommendations for remedy of errors. Add numeric error codes // to PARSE_ERROR, and switch on them for remedies, etc. Full // access is provided to everything in every exception! HTML_MESSAGE_BOX dlg( aWindow, _( "Load Error" ) ); dlg.MessageSet( _( "Errors were encountered loading footprints" ) ); wxString msg = my html wizardry. dlg.AddHTML_Text( msg ); dlg.ShowModal(); #endif }