[prev in list] [next in list] [prev in thread] [next in thread] 

List:       flightgear-cvs
Subject:    [Flightgear-cvslogs] CVS: source/src/Environment
From:       "Curtis L. Olson" <curt () flightgear ! org>
Date:       2004-02-28 19:52:20
Message-ID: E1AxAVY-0003xu-00 () baron ! me ! umn ! edu
[Download RAW message or body]

Update of /var/cvs/FlightGear-0.9/source/src/Environment
In directory baron:/tmp/cvs-serv15169

Modified Files:
	environment_ctrl.cxx environment_ctrl.hxx 
Log Message:
Investigating some wierd behavior where the threaded metar fetcher would
occasionally cause a large number of valid stations to be flagged as invalid.
This *seemed* like a "race condition" type problem because there were some
assumptions in the communication between the main process and the threaded
loader which if they broke down could lead to this problem.

In the process of removing this ambiguity, I restructured the threaded
(and non-threaded) metar fetching code a bit.  Some of the top level logic
(which Erik politely left untouched) didn't make nearly as much sense in the
context of a threaded metar loader and could have contributed to some of the
wierdness I was seeing.


Index: environment_ctrl.cxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Environment/environment_ctrl.cxx,v
retrieving revision 1.21
retrieving revision 1.22
diff -C2 -r1.21 -r1.22
*** a/environment_ctrl.cxx	28 Feb 2004 12:08:01 -0000	1.21
--- b/environment_ctrl.cxx	28 Feb 2004 19:52:17 -0000	1.22
***************
*** 317,321 ****
  FGMetarEnvironmentCtrl::FGMetarEnvironmentCtrl ()
      : env( new FGInterpolateEnvironmentCtrl ),
!       _icao( fgGetString("/sim/presets/airport-id") ),
        search_interval_sec( 60.0 ),        // 1 minute
        same_station_interval_sec( 900.0 ), // 15 minutes
--- 317,321 ----
  FGMetarEnvironmentCtrl::FGMetarEnvironmentCtrl ()
      : env( new FGInterpolateEnvironmentCtrl ),
!       _icao( "" ),
        search_interval_sec( 60.0 ),        // 1 minute
        same_station_interval_sec( 900.0 ), // 15 minutes
***************
*** 397,406 ****
                        latitude->getDoubleValue(),
                        true );
!         if ( fetch_data( a.id ) ) {
!             cout << "closest station w/ metar = " << a.id << endl;
              last_apt = a;
              _icao = a.id;
              search_elapsed = 0.0;
              fetch_elapsed = 0.0;
              update_env_config();
              env->init();
--- 397,408 ----
                        latitude->getDoubleValue(),
                        true );
!         FGMetarResult result = fetch_data( a.id );
!         if ( result.m != NULL ) {
!             SG_LOG( SG_GENERAL, SG_INFO, "closest station w/ metar = " << a.id);
              last_apt = a;
              _icao = a.id;
              search_elapsed = 0.0;
              fetch_elapsed = 0.0;
+             update_metar_properties( result.m );
              update_env_config();
              env->init();
***************
*** 409,413 ****
              // mark as no metar so it doesn't show up in subsequent
              // searches.
!             cout << "no metar at metar = " << a.id << endl;
              globals->get_airports()->no_metar( a.id );
          }
--- 411,415 ----
              // mark as no metar so it doesn't show up in subsequent
              // searches.
!             SG_LOG( SG_GENERAL, SG_INFO, "no metar at metar = " << a.id );
              globals->get_airports()->no_metar( a.id );
          }
***************
*** 428,431 ****
--- 430,435 ----
  FGMetarEnvironmentCtrl::update(double delta_time_sec)
  {
+     FGMetarResult result;
+ 
      static const SGPropertyNode *longitude
          = fgGetNode( "/position/longitude-deg", true );
***************
*** 434,437 ****
--- 438,444 ----
      search_elapsed += delta_time_sec;
      fetch_elapsed += delta_time_sec;
+ 
+     // if time for a new search request, push it onto the request
+     // queue
      if ( search_elapsed > search_interval_sec ) {
          FGAirport a = globals->get_airports()
***************
*** 442,463 ****
               || fetch_elapsed > same_station_interval_sec )
          {
!             if ( fetch_data( a.id ) ) {
!                 cout << "closest station w/ metar = " << a.id << endl;
!                 last_apt = a;
!                 _icao = a.id;
!                 search_elapsed = 0.0;
!                 fetch_elapsed = 0.0;
!                 update_env_config();
!                 env->reinit();
!             } else {
!                 // mark as no metar so it doesn't show up in subsequent
!                 // searches.
!                 cout << "no metar at metar = " << a.id << endl;
!                 globals->get_airports()->no_metar( a.id );
!             }
          } else {
              search_elapsed = 0.0;
!             // cout << "same station, waiting = "
!             //      << same_station_interval_sec - fetch_elapsed << endl;
          }
      }
--- 449,495 ----
               || fetch_elapsed > same_station_interval_sec )
          {
!             SG_LOG( SG_GENERAL, SG_INFO, "closest station w/ metar = " << a.id);
!             request_queue.push( a.id );
!             last_apt = a;
!             _icao = a.id;
!             search_elapsed = 0.0;
!             fetch_elapsed = 0.0;
          } else {
              search_elapsed = 0.0;
!             SG_LOG( SG_GENERAL, SG_INFO, "same station, waiting = "
!                  << same_station_interval_sec - fetch_elapsed );
!         }
!     }
! 
! #ifndef ENABLE_THREADS
!     // No loader thread running so manually fetch the data
!     string id = "";
!     while ( !request_queue.empty() ) {
!         id = request_queue.front();
!         request_queue.pop();
!     }
!     if ( !id.empty() ) {
!         SG_LOG( SG_GENERAL, SG_INFO, "inline fetching = " << id );
!         result = fetch_data( id );
!         result_queue.push( result );
!     }
! #endif // ENABLE_THREADS
! 
!     // process any results from the loader.
!     while ( !result_queue.empty() ) {
!         result = result_queue.front();
!         result_queue.pop();
!         if ( result.m != NULL ) {
!             update_metar_properties( result.m );
!             delete result.m;
!             update_env_config();
!             env->reinit();
!         } else {
!             // mark as no metar so it doesn't show up in subsequent
!             // searches, and signal an immediate re-search.
!             SG_LOG( SG_GENERAL, SG_WARN,
!                     "no metar at station = " << result.icao );
!             globals->get_airports()->no_metar( result.icao );
!             search_elapsed = 9999.0;
          }
      }
***************
*** 466,469 ****
--- 498,502 ----
  }
  
+ 
  void
  FGMetarEnvironmentCtrl::setEnvironment (FGEnvironment * environment)
***************
*** 472,644 ****
  }
  
! bool
! FGMetarEnvironmentCtrl::fetch_data (const string &icao)
  {
!     char s[128];
!     double d, dt;
!     int i;
! 
!     if ((icao == "") && (_icao == "")) {
!         _icao = fgGetString("/sim/presets/airport-id");
! 
!     } else if (icao != "") {
!         _icao = icao;
!     }
  
      // fetch station elevation if exists
!     FGAirport a = globals->get_airports()->search( _icao );
      station_elevation_ft = a.elevation;
  
      // fetch current metar data
-     SGMetar *m = NULL;
- #ifdef ENABLE_THREADS
- 
-     // We are only interested in the latest metar report
-     // FIXME: Do we want to keep the latest valid report instead?
-     while (!metar_queue.empty()) {
-  
-         if (m != NULL)
-             delete m;
- 
-         m = metar_queue.pop();
-     }
- 
-     if ( m != NULL ) {
- 
- #else
      try {
          string host = proxy_host->getStringValue();
          string auth = proxy_auth->getStringValue();
          string port = proxy_port->getStringValue();
!         m = new SGMetar( _icao, host, port, auth);
! 
! #endif // ENABLE_THREADS
  
!         d = m->getMinVisibility().getVisibility_m();
!         d = (d != SGMetarNaN) ? d : 10000;
!         fgSetDouble("/environment/metar/min-visibility-m", d);
  
-         dt =  m->getMaxVisibility().getVisibility_m();
-         d = (dt != SGMetarNaN) ? dt : d;
-         fgSetDouble("/environment/metar/max-visibility-m", d);
- 
-         SGMetarVisibility *dirvis = m->getDirVisibility();
-         for (i = 0; i < 8; i++, dirvis++) {
-             const char *min = "/environment/metar/visibility[%d]/min-m";
-             const char *max = "/environment/metar/visibility[%d]/max-m";
-             char s[128];
- 
-             d = dirvis->getVisibility_m();
-             d = (d != SGMetarNaN) ? d : 10000;
- 
-             snprintf(s, 128, min, i);
-             fgSetDouble(s, d);
-             snprintf(s, 128, max, i);
-             fgSetDouble(s, d);
-         }
  
!         i = m->getWindDir();
!         if ( i == -1 ) {
!             fgSetInt("/environment/metar/base-wind-range-from",
!                         m->getWindRangeFrom() );
!             fgSetInt("/environment/metar/base-wind-range-to",
!                         m->getWindRangeTo() );
!         } else {
!             fgSetInt("/environment/metar/base-wind-range-from", i);
!             fgSetInt("/environment/metar/base-wind-range-to", i);
!         }
!         fgSetDouble("/environment/metar/base-wind-speed-kt",
!                     m->getWindSpeed_kt() );
  
!         d = m->getGustSpeed_kt();
!         d = (d != SGMetarNaN) ? d : 0.0;
!         fgSetDouble("/environment/metar/gust-wind-speed-kt", d);
! 
!         d = m->getTemperature_C();
!         if (d != SGMetarNaN) {
!             dt = m->getDewpoint_C();
!             dt = (dt != SGMetarNaN) ? dt : 0.0;
!             fgSetDouble("/environment/metar/dewpoint-degc", dt);
!             fgSetDouble("/environment/metar/rel-humidity-norm",
!                         m->getRelHumidity() );
!         }   
!         d = (d != SGMetarNaN) ? d : 15.0;
!         fgSetDouble("/environment/metar/temperature-degc", d);
! 
!         d = m->getPressure_inHg();
!         d = (d != SGMetarNaN) ? d : 30.0;
!         fgSetDouble("/environment/metar/pressure-inhg", d);
! 
!         vector<SGMetarCloud> cv = m->getClouds();
!         vector<SGMetarCloud>::iterator cloud;
! 
!         const char *cl = "/environment/clouds/layer[%i]";
!         for (i = 0, cloud = cv.begin(); cloud != cv.end(); cloud++, i++) {
!             const char *coverage_string[5] = 
!                           { "clear", "few", "scattered", "broken", "overcast" };
!             const double thickness[5] = { 0, 65, 600,750, 1000};
!             int q;
! 
!             snprintf(s, 128, cl, i);
!             strncat(s, "/coverage", 128);
!             q = cloud->getCoverage();
!             q = (q != -1 ) ? q : 0;
!             fgSetString(s, coverage_string[q] );
! 
!             snprintf(s, 128, cl, i);
!             strncat(s, "/elevation-ft", 128);
!             d = cloud->getAltitude_ft();
!             d = (d != SGMetarNaN) ? d : -9999;
!             fgSetDouble(s, d + station_elevation_ft);
! 
!             snprintf(s, 128, cl, i);
!             strncat(s, "/thickness-ft", 128);
!             fgSetDouble(s, thickness[q]);
! 
!             snprintf(s, 128, cl, i);
!             strncat(s, "/span-m", 128);
!             fgSetDouble(s, 40000.0);
!         }
!         for (; i < FGEnvironmentMgr::MAX_CLOUD_LAYERS; i++) {
!             snprintf(s, 128, cl, i);
!             strncat(s, "/coverage", 128);
!             fgSetString(s, "clear");
! 
!             snprintf(s, 128, cl, i);
!             strncat(s, "/elevation-ft", 128);
!             fgSetDouble(s, -9999);
! 
!             snprintf(s, 128, cl, i);
!             strncat(s, "/thickness-ft", 128);
!             fgSetDouble(s, 0);
! 
!             snprintf(s, 128, cl, i);
!             strncat(s, "/span-m", 128);
!             fgSetDouble(s, 40000.0);
!         }
  
!         delete m;
  
      }
- #ifdef ENABLE_THREADS
  
!     mutex.lock();
!     metar_cond.signal();
!     mutex.unlock();
  
!     if (m == NULL)
!         return false;
  
! #else
!     catch (const sg_io_exception& e) {
!         SG_LOG( SG_GENERAL, SG_WARN, "Error fetching live weather data: "
!                                       << e.getFormattedMessage().c_str() );
!         return false;
      }
- #endif // ENABLE_THREADS
  
!     return true;
  }
  
  #ifdef ENABLE_THREADS
  /**
--- 505,647 ----
  }
  
! FGMetarResult
! FGMetarEnvironmentCtrl::fetch_data( const string &icao )
  {
!     FGMetarResult result;
!     result.icao = icao;
  
      // fetch station elevation if exists
!     FGAirport a = globals->get_airports()->search( icao );
      station_elevation_ft = a.elevation;
  
      // fetch current metar data
      try {
          string host = proxy_host->getStringValue();
          string auth = proxy_auth->getStringValue();
          string port = proxy_port->getStringValue();
!         result.m = new SGMetar( icao, host, port, auth);
!     } catch (const sg_io_exception& e) {
!         SG_LOG( SG_GENERAL, SG_WARN, "Error fetching live weather data: "
!                 << e.getFormattedMessage().c_str() );
!         result.m = NULL;
!     }
  
!     return result;
! }
  
  
! void
! FGMetarEnvironmentCtrl::update_metar_properties( SGMetar *m )
! {
!     int i;
!     double d, dt;
!     char s[128];
  
!     d = m->getMinVisibility().getVisibility_m();
!     d = (d != SGMetarNaN) ? d : 10000;
!     fgSetDouble("/environment/metar/min-visibility-m", d);
! 
!     dt =  m->getMaxVisibility().getVisibility_m();
!     d = (dt != SGMetarNaN) ? dt : d;
!     fgSetDouble("/environment/metar/max-visibility-m", d);
! 
!     SGMetarVisibility *dirvis = m->getDirVisibility();
!     for (i = 0; i < 8; i++, dirvis++) {
!         const char *min = "/environment/metar/visibility[%d]/min-m";
!         const char *max = "/environment/metar/visibility[%d]/max-m";
!         char s[128];
  
!         d = dirvis->getVisibility_m();
!         d = (d != SGMetarNaN) ? d : 10000;
  
+         snprintf(s, 128, min, i);
+         fgSetDouble(s, d);
+         snprintf(s, 128, max, i);
+         fgSetDouble(s, d);
      }
  
!     i = m->getWindDir();
!     if ( i == -1 ) {
!         fgSetInt("/environment/metar/base-wind-range-from",
!                  m->getWindRangeFrom() );
!         fgSetInt("/environment/metar/base-wind-range-to",
!                  m->getWindRangeTo() );
!     } else {
!         fgSetInt("/environment/metar/base-wind-range-from", i);
!         fgSetInt("/environment/metar/base-wind-range-to", i);
!     }
!     fgSetDouble("/environment/metar/base-wind-speed-kt",
!                 m->getWindSpeed_kt() );
  
!     d = m->getGustSpeed_kt();
!     d = (d != SGMetarNaN) ? d : 0.0;
!     fgSetDouble("/environment/metar/gust-wind-speed-kt", d);
! 
!     d = m->getTemperature_C();
!     if (d != SGMetarNaN) {
!         dt = m->getDewpoint_C();
!         dt = (dt != SGMetarNaN) ? dt : 0.0;
!         fgSetDouble("/environment/metar/dewpoint-degc", dt);
!         fgSetDouble("/environment/metar/rel-humidity-norm",
!                     m->getRelHumidity() );
!     }
!     d = (d != SGMetarNaN) ? d : 15.0;
!     fgSetDouble("/environment/metar/temperature-degc", d);
  
!     d = m->getPressure_inHg();
!     d = (d != SGMetarNaN) ? d : 30.0;
!     fgSetDouble("/environment/metar/pressure-inhg", d);
! 
!     vector<SGMetarCloud> cv = m->getClouds();
!     vector<SGMetarCloud>::iterator cloud;
! 
!     const char *cl = "/environment/clouds/layer[%i]";
!     for (i = 0, cloud = cv.begin(); cloud != cv.end(); cloud++, i++) {
!         const char *coverage_string[5] = 
!             { "clear", "few", "scattered", "broken", "overcast" };
!         const double thickness[5] = { 0, 65, 600,750, 1000};
!         int q;
! 
!         snprintf(s, 128, cl, i);
!         strncat(s, "/coverage", 128);
!         q = cloud->getCoverage();
!         q = (q != -1 ) ? q : 0;
!         fgSetString(s, coverage_string[q] );
! 
!         snprintf(s, 128, cl, i);
!         strncat(s, "/elevation-ft", 128);
!         d = cloud->getAltitude_ft();
!         d = (d != SGMetarNaN) ? d : -9999;
!         fgSetDouble(s, d + station_elevation_ft);
! 
!         snprintf(s, 128, cl, i);
!         strncat(s, "/thickness-ft", 128);
!         fgSetDouble(s, thickness[q]);
! 
!         snprintf(s, 128, cl, i);
!         strncat(s, "/span-m", 128);
!         fgSetDouble(s, 40000.0);
      }
  
!     for (; i < FGEnvironmentMgr::MAX_CLOUD_LAYERS; i++) {
!         snprintf(s, 128, cl, i);
!         strncat(s, "/coverage", 128);
!         fgSetString(s, "clear");
! 
!         snprintf(s, 128, cl, i);
!         strncat(s, "/elevation-ft", 128);
!         fgSetDouble(s, -9999);
! 
!         snprintf(s, 128, cl, i);
!         strncat(s, "/thickness-ft", 128);
!         fgSetDouble(s, 0);
! 
!         snprintf(s, 128, cl, i);
!         strncat(s, "/span-m", 128);
!         fgSetDouble(s, 40000.0);
!     }
  }
  
+ 
  #ifdef ENABLE_THREADS
  /**
***************
*** 648,679 ****
  FGMetarEnvironmentCtrl::MetarThread::run()
  {
-     SGMetar *m = NULL;
- 
      // pthread_cleanup_push( metar_cleanup_handler, fetcher );
      while ( true )
      {
          set_cancel( SGThread::CANCEL_DISABLE );
-         try
-         {
-             cout << "Fetching ..." << endl;
-             // if (m != NULL)  m = NULL;
-             string host = fetcher->proxy_host->getStringValue();
-             string auth = fetcher->proxy_auth->getStringValue();
-             string port = fetcher->proxy_port->getStringValue();
-             m = new SGMetar( fetcher->_icao, host, port, auth );
- 
-         } catch (const sg_io_exception& e) {
-             // SG_LOG( SG_GENERAL, SG_WARN, "Error fetching live weather data: "
-             //                             << e.getFormattedMessage().c_str() );
-             m = NULL;
-         }
-         set_cancel( SGThread::CANCEL_DEFERRED );
  
!         fetcher->metar_queue.push( m );
  
!         // Wait for the next frame signal before we fetch the next metar data
!         fetcher->mutex.lock();
!         fetcher->metar_cond.wait( fetcher->mutex );
!         fetcher->mutex.unlock();
      }
      // pthread_cleanup_pop(1);
--- 651,666 ----
  FGMetarEnvironmentCtrl::MetarThread::run()
  {
      // pthread_cleanup_push( metar_cleanup_handler, fetcher );
      while ( true )
      {
          set_cancel( SGThread::CANCEL_DISABLE );
  
!         string icao = fetcher->request_queue.pop();
!         SG_LOG( SG_GENERAL, SG_INFO, "Thread: fetch metar data = " << icao );
!         FGMetarResult result = fetcher->fetch_data( icao );
! 
!         set_cancel( SGThread::CANCEL_DEFERRED );
  
!         fetcher->result_queue.push( result );
      }
      // pthread_cleanup_pop(1);

Index: environment_ctrl.hxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Environment/environment_ctrl.hxx,v
retrieving revision 1.10
retrieving revision 1.11
diff -C2 -r1.10 -r1.11
*** a/environment_ctrl.hxx	26 Feb 2004 18:21:11 -0000	1.10
--- b/environment_ctrl.hxx	28 Feb 2004 19:52:17 -0000	1.11
***************
*** 39,44 ****
--- 39,46 ----
  #endif
  
+ #include <queue>
  #include <vector>
  
+ SG_USING_STD(queue);
  SG_USING_STD(vector);
  
***************
*** 140,143 ****
--- 142,152 ----
  
  
+ // A convenience wrapper around SGMetar
+ struct FGMetarResult {
+     string icao;
+     SGMetar *m;
+ };
+ 
+ 
  
  /**
***************
*** 153,157 ****
      virtual void reinit ();
      virtual void update (double delta_time_sec);
- 
      virtual void setEnvironment (FGEnvironment * environment);
  
--- 162,165 ----
***************
*** 170,177 ****
      SGPropertyNode *proxy_auth;
  
!     bool fetch_data (const string &icao);
      void update_env_config();
  
- 
  private:
  
--- 178,185 ----
      SGPropertyNode *proxy_auth;
  
!     FGMetarResult fetch_data( const string &icao );
!     virtual void update_metar_properties( SGMetar *m );
      void update_env_config();
  
  private:
  
***************
*** 180,186 ****
       * FIFO queue which holds a pointer to the fetched metar data.
       */
!     SGBlockingQueue< SGMetar * > metar_queue;
  
      /**
       * This class represents the thread of execution responsible for
       * fetching the metar data.
--- 188,211 ----
       * FIFO queue which holds a pointer to the fetched metar data.
       */
!     SGBlockingQueue < string > request_queue;
  
      /**
+      * FIFO queue which holds a pointer to the fetched metar data.
+      */
+     SGBlockingQueue < FGMetarResult > result_queue;
+ #else
+     /**
+      * FIFO queue which holds a pointer to the fetched metar data.
+      */
+     queue < string > request_queue;
+ 
+     /**
+      * FIFO queue which holds a pointer to the fetched metar data.
+      */
+     queue < FGMetarResult > result_queue;
+ #endif
+ 
+ #ifdef ENABLE_THREADS
+     /**
       * This class represents the thread of execution responsible for
       * fetching the metar data.
***************
*** 193,197 ****
  
          /**
!          * Reads the tile from disk.
           */
          void run();
--- 218,222 ----
  
          /**
!          * Fetched the metar data from the NOAA.
           */
          void run();


_______________________________________________
Flightgear-cvslogs mailing list
Flightgear-cvslogs@flightgear.org
http://mail.flightgear.org/mailman/listinfo/flightgear-cvslogs
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic