From ae320ca46c78cdb34c0cd730733dfb8ef3c737df Mon Sep 17 00:00:00 2001 From: ThorstenB Date: Sun, 13 Feb 2011 16:50:23 +0100 Subject: [PATCH] Avoid crash and/or long delay on shutdown in METAR loader. 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 | 48 ++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/src/Environment/realwx_ctrl.cxx b/src/Environment/realwx_ctrl.cxx index 197f4cf52..087040486 100644 --- a/src/Environment/realwx_ctrl.cxx +++ b/src/Environment/realwx_ctrl.cxx @@ -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 _requestQueue; SGBlockingQueue _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 ); - } } -- 2.39.5