]> git.mxchange.org Git - flightgear.git/commitdiff
Avoid crash and/or long delay on shutdown in METAR loader.
authorThorstenB <brehmt@gmail.com>
Sun, 13 Feb 2011 15:50:23 +0000 (16:50 +0100)
committerThorstenB <brehmt@gmail.com>
Sun, 13 Feb 2011 17:44:56 +0000 (18:44 +0100)
Catching loader thread on subsystem destruction is too late, since it
depends on other subsystems (which are destroyed earlier).
=> Need to stop & join thread during subsystem shutdown.
Also changed loader sleep logic - to avoid excessive delays (up to
30 seconds) on shutdown.
(Issues mostly happened when running offline with realwx enabled.)

src/Environment/realwx_ctrl.cxx

index a547ef7e5b769656e26cbd4a14228950a1b6a7bb..71f52d7bad0820950f1d17d301c1989929a70ac7 100644 (file)
@@ -191,6 +191,7 @@ public:
     NoaaMetarRealWxController( SGPropertyNode_ptr rootNode );
     virtual ~NoaaMetarRealWxController();
     virtual void update (bool first, double delta_time_sec);
+    virtual void shutdown ();
 
     class MetarLoadRequest {
     public:
@@ -234,14 +235,17 @@ private:
      class MetarLoadThread : public OpenThreads::Thread {
      public:
         MetarLoadThread( long maxAge );
+        virtual ~MetarLoadThread( ) { stop(); } 
         void requestMetar( const MetarLoadRequest & metarRequest, bool background = true );
         bool hasMetar() { return _responseQueue.size() > 0; }
         MetarLoadResponse getMetar() { return _responseQueue.pop(); }
         virtual void run();
+        void stop();
      private:
         void fetch( const MetarLoadRequest & );
         long _maxAge;
         long _minRequestInterval;
+        volatile bool _stop;
         SGBlockingQueue <MetarLoadRequest> _requestQueue;
         SGBlockingQueue <MetarLoadResponse> _responseQueue;
      };
@@ -261,18 +265,20 @@ NoaaMetarRealWxController::NoaaMetarRealWxController( SGPropertyNode_ptr rootNod
 #endif
 }
 
-NoaaMetarRealWxController::~NoaaMetarRealWxController()
+void NoaaMetarRealWxController::shutdown()
 {
 #if defined(ENABLE_THREADS)
     if( _metarLoadThread ) {
-        MetarLoadRequest request("");
-        _metarLoadThread->requestMetar(request);
-        _metarLoadThread->join();
         delete _metarLoadThread;
+        _metarLoadThread = NULL;
     }
 #endif // ENABLE_THREADS
 }
 
+NoaaMetarRealWxController::~NoaaMetarRealWxController()
+{
+}
+
 void NoaaMetarRealWxController::update( bool first, double dt )
 {
     _positionTimeToLive -= dt;
@@ -319,7 +325,7 @@ void NoaaMetarRealWxController::update( bool first, double dt )
                     "NoaaMetarRealWxController::update(): spawning load request for station-id '" << stationId << "'" );
             
                 MetarLoadRequest request( stationId );
-                // load the metar for the neares airport in the foreground if the fdm is uninitialized
+                // load the metar for the nearest airport in the foreground if the fdm is uninitialized
                 // to make sure a metar is received
                 // before the automatic runway selection code runs. All subsequent calls
                 // run in the background
@@ -348,7 +354,8 @@ void NoaaMetarRealWxController::update( bool first, double dt )
 #if defined(ENABLE_THREADS)
 NoaaMetarRealWxController::MetarLoadThread::MetarLoadThread( long maxAge ) :
   _maxAge(maxAge),
-  _minRequestInterval(2000)
+  _minRequestInterval(2000),
+  _stop(false)
 {
 }
 
@@ -368,24 +375,41 @@ void NoaaMetarRealWxController::MetarLoadThread::requestMetar( const MetarLoadRe
     }
 }
 
+void NoaaMetarRealWxController::MetarLoadThread::stop()
+{
+    // set stop flag and wake up the thread with an empty request
+    _stop = true;
+    MetarLoadRequest request("");
+    requestMetar(request);
+    join();
+}
+
 void NoaaMetarRealWxController::MetarLoadThread::run()
 {
     SGTimeStamp lastRun = SGTimeStamp::fromSec(0);
     for( ;; ) {
         SGTimeStamp dt = SGTimeStamp::now() - lastRun;
 
-        if( dt.getSeconds() * 1000 < _minRequestInterval )
-            microSleep( (_minRequestInterval - dt.getSeconds() * 1000 ) * 1000 );
-        
-        lastRun = SGTimeStamp::now();
+        long delayMs = _minRequestInterval - dt.getSeconds() * 1000;
+        while (( delayMs > 0 ) && !_stop)
+        {
+            // sleep no more than 3 seconds at a time, otherwise shutdown response is too slow
+            long sleepMs = (delayMs>3000) ? 3000 : delayMs; 
+            microSleep( sleepMs * 1000 );
+            delayMs -= sleepMs;
+        }
 
+        if (_stop)
+            break;
+
+        lastRun = SGTimeStamp::now();
         const MetarLoadRequest request = _requestQueue.pop();
 
-        if( request._stationId.size() == 0 )
+        if (( request._stationId.size() == 0 ) || _stop)
             break;
 
         fetch( request );
-
     }
 }