kopia lustrzana https://github.com/jamescoxon/dl-fldigi
				
				
				
			KML thread
* Changed thread exit implementation to conditional compile
    -- used for building the OS X dmg
			
			
				pull/1/head
			
			
		
							rodzic
							
								
									edc0c9fbc6
								
							
						
					
					
						commit
						67948117a0
					
				|  | @ -141,6 +141,7 @@ | |||
| #include "flmisc.h" | ||||
| 
 | ||||
| #include "arq_io.h" | ||||
| #include "kmlserver.h" | ||||
| 
 | ||||
| #include "notifydialog.h" | ||||
| #include "macroedit.h" | ||||
|  | @ -2828,6 +2829,8 @@ bool clean_exit(bool ask) { | |||
| 	close_logbook(); | ||||
| 	MilliSleep(50); | ||||
| 
 | ||||
| 	exit_process(); | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -36,6 +36,8 @@ class KmlServer { | |||
| protected: | ||||
| 	/// Counts the number of complete messages written.
 | ||||
| 	int m_nb_broadcasts ; | ||||
| 	int exit_kml_server; | ||||
| 	int request_broadcast; | ||||
| public: | ||||
| 	/// List of key-value pairs displayed for example in Google Earth balloons.
 | ||||
| 	struct CustomDataT : public std::vector< std::pair< std::string, std::string > > { | ||||
|  | @ -55,7 +57,7 @@ public: | |||
| 		} | ||||
| 	}; | ||||
| 
 | ||||
| 	KmlServer() : m_nb_broadcasts(0) {} | ||||
| 	KmlServer() : m_nb_broadcasts(0), exit_kml_server(0), request_broadcast(0) {} | ||||
| 
 | ||||
| 	virtual ~KmlServer() {} | ||||
| 
 | ||||
|  |  | |||
|  | @ -86,6 +86,9 @@ extern bool nbems_dirs_checked; | |||
| // This inits or reinits everything related to KML: Reloads params etc...
 | ||||
| void kml_init(bool load_files = false); | ||||
| 
 | ||||
| // close down remaining threads just before exiting UI
 | ||||
| extern void exit_process(); | ||||
| 
 | ||||
| int directory_is_created( const char * strdir ); | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
							
								
								
									
										11
									
								
								src/main.cxx
								
								
								
								
							
							
						
						
									
										11
									
								
								src/main.cxx
								
								
								
								
							|  | @ -522,8 +522,13 @@ int main(int argc, char ** argv) | |||
| 
 | ||||
| 	int ret = Fl::run(); | ||||
| 
 | ||||
| 	arq_close(); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| void exit_process() { | ||||
| 
 | ||||
| 	KmlServer::Exit(); | ||||
| 	arq_close(); | ||||
| 	XML_RPC_Server::stop(); | ||||
| 
 | ||||
| 	if (progdefaults.usepskrep) | ||||
|  | @ -533,11 +538,9 @@ int main(int argc, char ** argv) | |||
| 		cbq[i]->detach(); | ||||
| 		delete cbq[i]; | ||||
| 	} | ||||
| 
 | ||||
| 	FSEL::destroy(); | ||||
| 
 | ||||
| 	KmlServer::Exit(); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| void generate_option_help(void) { | ||||
|  |  | |||
|  | @ -46,9 +46,22 @@ | |||
| #include "strutil.h" | ||||
| #include "configuration.h" | ||||
| 
 | ||||
| #include "irrXML.h" | ||||
| 
 | ||||
| #include "timeops.h" | ||||
| 
 | ||||
| #include "irrXML.h" | ||||
| /** Some platforms have problems with condition variables apparently.
 | ||||
|  * When cancelling a thread which waits in pthread_cond_timedwait, | ||||
|  * the thread is stuck. | ||||
|  * We replace it by an unconditional wait, and a test on a boolean | ||||
|  * which indicates if data was saved in the internal buffers. | ||||
|  * The consequence is that data are not immediately saved in KML files, | ||||
|  * and the user has to wait until the end of the delay. | ||||
|  */ | ||||
| 
 | ||||
| #if !defined(__APPLE__) | ||||
| #	define FLDIGI_KML_CONDITION_VARIABLE 1 | ||||
| #endif | ||||
| 
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
| 
 | ||||
|  | @ -85,7 +98,10 @@ static time_t KmlFromTimestamp( const char * ts ) { | |||
| 
 | ||||
| 	if( 0 == strcmp( ts, KmlSrvUnique ) ) return KmlServer::UniqueEvent ; | ||||
| 
 | ||||
| 	tm objTm ; | ||||
| 	/// So all fields are initialised with correct default values.
 | ||||
| 	time_t timNow = time(NULL); | ||||
| 	tm objTm = *gmtime( &timNow );  | ||||
| 
 | ||||
| 	int r = sscanf( ts, "%4d-%02d-%02dT%02d:%02dZ", | ||||
| 			&objTm.tm_year, | ||||
| 			&objTm.tm_mon, | ||||
|  | @ -96,6 +112,7 @@ static time_t KmlFromTimestamp( const char * ts ) { | |||
| 	objTm.tm_year -= 1900; | ||||
| 	objTm.tm_mon -= 1; | ||||
| 	objTm.tm_sec = 0; | ||||
| 
 | ||||
| 	time_t res = mktime( &objTm ); | ||||
| 	if( res < 0 ) throw std::runtime_error("Cannot make timestamp from " + std::string(ts) ); | ||||
| 	return res; | ||||
|  | @ -185,12 +202,12 @@ static void KmlHeader( std::ostream & ostrm, const std::string & title ) { | |||
| 		"<name>" << title << "</name>\n" ; | ||||
| } | ||||
| 
 | ||||
| // Appended at the end of each KML document.
 | ||||
| /// Appended at the end of each KML document.
 | ||||
| static const char KmlFooter[] =  | ||||
| 	"</Document>\n" | ||||
| 	"</kml>\n" ; | ||||
| 
 | ||||
| // Contains for example GIF images, and all the styles. Can be customised by the user.
 | ||||
| /// Contains for example GIF images, and all the styles. Can be customised by the user.
 | ||||
| static const std::string namStyles = "styles.kml"; | ||||
| 
 | ||||
| /** Used to code the data for reloading. The description tag is too complicated
 | ||||
|  | @ -789,7 +806,6 @@ class  KmlSrvImpl : public KmlServer { | |||
| 				{ | ||||
| 					PlacesMapItrSetT::const_iterator itNamNxt = itNamLast; | ||||
| 					++itNamNxt ; | ||||
| 					assert( (*itNamBeg)->first != (*itNamLast)->first ); | ||||
| 					if( ( itNamNxt == itStylNext ) || ( (*itNamNxt)->first != (*itNamLast)->first ) ) { | ||||
| 						// No point tracing a line with one point only.
 | ||||
| 						if( *itNamBeg != *itNamLast ) { | ||||
|  | @ -852,15 +868,17 @@ class  KmlSrvImpl : public KmlServer { | |||
| 
 | ||||
| 	/// This file copy does not need to be atomic because it happens once only.
 | ||||
| 	void CopyStyleFileIfNotExists(void) { | ||||
| 		// Where the installed file is stored. Used as default.
 | ||||
| 		/// Where the installed file is stored and never moved from. Used as default.
 | ||||
| 		std::string namSrc = PKGDATADIR "/kml/" + namStyles ; | ||||
| 
 | ||||
| 		/// The use might customize its styles file: It will not be altered.
 | ||||
| 		std::string namDst = m_kml_dir + namStyles ; | ||||
| 
 | ||||
| 		/// Used to copy the master file to the user copy if needed.
 | ||||
| 		FILE * filSrc = NULL; | ||||
| 		FILE * filDst = fopen( namDst.c_str(), "r" ); | ||||
| 		// If the file is there, leave as it is because it is maybe customize.
 | ||||
| 
 | ||||
| 		/// If the file is there, leave as it is because it is maybe customize.
 | ||||
| 		if( filDst ) { | ||||
| 			LOG_INFO("Style file %s not altered", namDst.c_str() ); | ||||
| 			goto close_and_quit ; | ||||
|  | @ -875,6 +893,8 @@ class  KmlSrvImpl : public KmlServer { | |||
| 			LOG_INFO("Cannot open source style file %s", namSrc.c_str() ); | ||||
| 			goto close_and_quit ; | ||||
| 		} | ||||
| 
 | ||||
| 		/// Transient buffer to copy the file.
 | ||||
|     		char buffer[BUFSIZ]; | ||||
|     		size_t n; | ||||
| 
 | ||||
|  | @ -898,7 +918,7 @@ class  KmlSrvImpl : public KmlServer { | |||
| 
 | ||||
| 		LOG_INFO("Creating baseFil=%s", baseFil.c_str() ); | ||||
| 
 | ||||
| 		// We do not need to make this file aomtic because it is read once only.
 | ||||
| 		/// We do not need to make this file atomic because it is read once only.
 | ||||
| 		AtomicRenamer ar( baseFil ); | ||||
| 
 | ||||
| 		KmlHeader( ar, "Fldigi"); | ||||
|  | @ -918,7 +938,7 @@ class  KmlSrvImpl : public KmlServer { | |||
| 		PlacesMapT::const_iterator beg, | ||||
| 		PlacesMapT::const_iterator last ) { | ||||
| 
 | ||||
| 		// The polyline gets an id based on the beginning of the path, which will never change.
 | ||||
| 		/// The polyline gets an id based on the beginning of the path, which will never change.
 | ||||
| 		ostrm | ||||
| 			<< "<Placemark id=\"" << beg->second.KmlId() << ":Path\">" | ||||
| 			"<name>" << beg->second.KmlId() << "</name>" | ||||
|  | @ -1102,7 +1122,7 @@ class  KmlSrvImpl : public KmlServer { | |||
| 				if( ! avoidNode.empty() ) break ; | ||||
| 
 | ||||
| 				const char * msgTxt = xml->getNodeData(); | ||||
| 				// LOG_INFO( "getNodeData=%s currState=%s", msgTxt, KmlRdToStr(currState) );
 | ||||
| 				LOG_DEBUG( "getNodeData=%s currState=%s", msgTxt, KmlRdToStr(currState) ); | ||||
| 				switch(currState) { | ||||
| 					case KMLRD_FOLDER_NAME :  | ||||
| 					       currFolderName = msgTxt ? msgTxt : "NullFolder"; | ||||
|  | @ -1135,9 +1155,15 @@ class  KmlSrvImpl : public KmlServer { | |||
| 						if (!strcmp("Folder", nodeName)) { | ||||
| 							currState = KMLRD_FOLDER ; | ||||
| 						} else { | ||||
| 							/// These tags are not meaningful for us.
 | ||||
| 							if(	strcmp( "kml", nodeName ) && | ||||
| 								strcmp( "Document", nodeName ) && | ||||
| 								strcmp( "name", nodeName ) ) | ||||
| 							{ | ||||
| 							LOG_INFO("Unexpected %s in document %s. currState=%s", | ||||
| 								nodeName, category.c_str(), KmlRdToStr(currState) ); | ||||
| 							} | ||||
| 						} | ||||
| 						break; | ||||
| 					case KMLRD_FOLDER :  | ||||
| 						if (!strcmp("name", nodeName)) { | ||||
|  | @ -1331,7 +1357,16 @@ class  KmlSrvImpl : public KmlServer { | |||
| 		return wasSaved ; | ||||
| 	} // KmlSrvImpl::RewriteKmlFileFull
 | ||||
| 
 | ||||
| #ifdef FLDIGI_KML_CONDITION_VARIABLE | ||||
| 	/// This is signaled when geographic data is broadcasted.
 | ||||
| 	pthread_cond_t  m_cond_queue ; | ||||
| #else | ||||
| 	/// This is set to true when geographic data is broadcasted.
 | ||||
| 	bool            m_bool_queue ; | ||||
| 
 | ||||
| 	/// This tells that the subthread must leave at the first opportunity.
 | ||||
| 	bool            m_kml_must_leave; | ||||
| #endif | ||||
| 	pthread_mutex_t m_mutex_write ; | ||||
| 
 | ||||
| 	typedef std::list< PlacemarkT > PlacemarkListT ; | ||||
|  | @ -1359,6 +1394,7 @@ class  KmlSrvImpl : public KmlServer { | |||
| 		// Endless loop until end of program, which cancels this subthread.
 | ||||
| 		for(;;) | ||||
| 		{ | ||||
| #ifdef FLDIGI_KML_CONDITION_VARIABLE | ||||
| 			struct timespec tmp_tim; | ||||
| 			{ | ||||
| 				guard_lock myGuard( &m_mutex_write ); | ||||
|  | @ -1373,6 +1409,23 @@ class  KmlSrvImpl : public KmlServer { | |||
| 					LOG_ERROR("pthread_cond_timedwait %s d=%d", strerror(errno), m_refresh_interval ); | ||||
| 					return (void *)"Error in pthread_cond_timed_wait"; | ||||
| 				} | ||||
| #else | ||||
| 			/// On the platforms where pthread_cond_timedwait has problems, everything behaves
 | ||||
| 			// as if there was a timeout when data is saved. refresh_delay is never changed.
 | ||||
| 			for( int i = 0; i < refresh_delay; ++i ) | ||||
| 			{ | ||||
| 				MilliSleep( 1000 ); | ||||
| 				if( m_kml_must_leave ) | ||||
| 				{ | ||||
| 					LOG_INFO("Exit flag detected. Leaving"); | ||||
| 					return (void *)"Exit flag detected"; | ||||
| 				} | ||||
| 			} | ||||
| 			{ | ||||
| 				guard_lock myGuard( &m_mutex_write ); | ||||
| 				r = m_bool_queue ? ETIMEDOUT : 0 ; | ||||
| 				m_bool_queue = false; | ||||
| #endif | ||||
| 
 | ||||
| 				// Except if extremely slow init, the object should be ready now: Files loaded etc...
 | ||||
| 				if( ! m_loaded ) { | ||||
|  | @ -1414,10 +1467,12 @@ class  KmlSrvImpl : public KmlServer { | |||
| 
 | ||||
| 				// Reset the interval to the initial value.
 | ||||
| 				refresh_delay = m_refresh_interval ; | ||||
| #ifdef FLDIGI_KML_CONDITION_VARIABLE | ||||
| 			} else { | ||||
| 				refresh_delay = tmp_tim.tv_sec - time(NULL); | ||||
| 				if( refresh_delay <= 0 ) refresh_delay = 1 ; | ||||
| 				// LOG_INFO("Interrupted when waiting. Restart with wait=%d", refresh );
 | ||||
| #endif | ||||
| 			} | ||||
| 		} // Endless loop.
 | ||||
| 		return NULL ; | ||||
|  | @ -1494,7 +1549,7 @@ public: | |||
| 		} | ||||
| 
 | ||||
| 		// Now the object is usable. Theoretically should be protected by a mutex.
 | ||||
| 		LOG_INFO("Object ready"); | ||||
| 		LOG_DEBUG("Object ready"); | ||||
| 
 | ||||
| 		/// Even if an exception was thrown when loading the previous file, it does not 
 | ||||
| 		/// prevent to overwrite the old files with new and clean ones.
 | ||||
|  | @ -1510,8 +1565,13 @@ public: | |||
| 	, m_refresh_interval(-1) | ||||
| 	, m_balloon_style(0) | ||||
| 	{ | ||||
| 		LOG_INFO("Creation"); | ||||
| 		LOG_DEBUG("Creation"); | ||||
| #ifdef FLDIGI_KML_CONDITION_VARIABLE | ||||
| 		pthread_cond_init( &m_cond_queue, NULL ); | ||||
| #else | ||||
| 		m_bool_queue = false; | ||||
| 		m_kml_must_leave = false; | ||||
| #endif | ||||
| 		pthread_mutex_init( &m_mutex_write, NULL ); | ||||
| 
 | ||||
| 		/// TODO: Add this thread to the other fldigi threads stored in cbq[].
 | ||||
|  | @ -1553,7 +1613,11 @@ public: | |||
| 			LOG_ERROR("Category %s undefined", category.c_str()); | ||||
| 		} | ||||
| 		ptrMap->Enqueue( tmpKmlNam, currPM ); | ||||
| #ifdef FLDIGI_KML_CONDITION_VARIABLE | ||||
| 		pthread_cond_signal( &m_cond_queue ); | ||||
| #else | ||||
| 		m_bool_queue = true; | ||||
| #endif | ||||
| 		LOG_INFO("'%s' sz=%d time=%s nb_broad=%d m_merge_dist=%lf", | ||||
| 			descrTxt.c_str(), (int)ptrMap->size(), | ||||
| 			KmlTimestamp(evtTim).c_str(), | ||||
|  | @ -1567,12 +1631,17 @@ public: | |||
| 			LOG_INFO("Cancelling writer thread"); | ||||
| 			guard_lock myGuard( &m_mutex_write ); | ||||
| 
 | ||||
| #ifdef FLDIGI_KML_CONDITION_VARIABLE | ||||
| 			LOG_INFO("Cancelling subthread"); | ||||
| 			int r = pthread_cancel( m_writer_thread ); | ||||
| 			if( r ) { | ||||
| 				LOG_ERROR("pthread_cancel %s", strerror(errno) ); | ||||
| 				return ; | ||||
| 			} | ||||
| #else | ||||
| 			LOG_INFO("Setting exit flag."); | ||||
| 			m_kml_must_leave = true ; | ||||
| #endif | ||||
| 		} | ||||
| 		// LOG_INFO("Joining subthread");
 | ||||
| 		void * retPtr; | ||||
|  | @ -1592,7 +1661,9 @@ public: | |||
| 		/// Here we are sure that the subthread is stopped. The subprocess is not called.
 | ||||
| 		RewriteKmlFileFull(); | ||||
| 
 | ||||
| #ifdef FLDIGI_KML_CONDITION_VARIABLE | ||||
| 		pthread_cond_destroy( &m_cond_queue ); | ||||
| #endif | ||||
| 		pthread_mutex_destroy( &m_mutex_write ); | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
		Ładowanie…
	
		Reference in New Issue
	
	 David Freese
						David Freese