Revision: 8189
          http://playerstage.svn.sourceforge.net/playerstage/?rev=8189&view=rev
Author:   rtv
Date:     2009-08-11 02:02:02 +0000 (Tue, 11 Aug 2009)

Log Message:
-----------
greatly simplified and improved timing code - API change requires move to 
version 3.2.0

Modified Paths:
--------------
    code/stage/trunk/CMakeLists.txt
    code/stage/trunk/examples/ctrl/fasr.cc
    code/stage/trunk/libstage/main.cc
    code/stage/trunk/libstage/model.cc
    code/stage/trunk/libstage/model_load.cc
    code/stage/trunk/libstage/stage.hh
    code/stage/trunk/libstage/test.cc
    code/stage/trunk/libstage/world.cc
    code/stage/trunk/libstage/worldgui.cc
    code/stage/trunk/worlds/SFU.world
    code/stage/trunk/worlds/benchmark/cave.world
    code/stage/trunk/worlds/benchmark/hospital.world
    code/stage/trunk/worlds/fasr.world
    code/stage/trunk/worlds/pioneer_flocking.world

Modified: code/stage/trunk/CMakeLists.txt
===================================================================
--- code/stage/trunk/CMakeLists.txt     2009-08-10 08:49:51 UTC (rev 8188)
+++ code/stage/trunk/CMakeLists.txt     2009-08-11 02:02:02 UTC (rev 8189)
@@ -1,7 +1,7 @@
 PROJECT(Stage)
 
 SET( V_MAJOR 3 )
-SET( V_MINOR 1 )
+SET( V_MINOR 2 )
 SET( V_BUGFIX 0 )
 
 SET( VERSION ${V_MAJOR}.${V_MINOR}.${V_BUGFIX} )

Modified: code/stage/trunk/examples/ctrl/fasr.cc
===================================================================
--- code/stage/trunk/examples/ctrl/fasr.cc      2009-08-10 08:49:51 UTC (rev 
8188)
+++ code/stage/trunk/examples/ctrl/fasr.cc      2009-08-11 02:02:02 UTC (rev 
8189)
@@ -496,15 +496,17 @@
 // Stage calls this when the model starts up
 extern "C" int Init( Model* mod )
 {  
+#if 0          
+  // example using the model rasterizer
   if( strcmp( mod->Token(), "r0" ) == 0 )
         {
                const unsigned int dw = 64, dh = 32;
-
+               
                uint8_t* data = new uint8_t[dw*dh*2];
                memset( data, 0, sizeof(uint8_t) * dw * dh );
                
                mod->GetWorld()->GetModel( "cave" )->Rasterize( data, dw, dh, 
0.25, 0.5 );
-
+               
                putchar( '\n' );
                for( unsigned int y=0; y<dh; y++ )
                  {
@@ -514,7 +516,8 @@
                  }
                delete data;
         }
-
+#endif
+  
   new Robot( (ModelPosition*)mod,
                                 mod->GetWorld()->GetModel( "source" ),
                                 mod->GetWorld()->GetModel( "sink" ) );

Modified: code/stage/trunk/libstage/main.cc
===================================================================
--- code/stage/trunk/libstage/main.cc   2009-08-10 08:49:51 UTC (rev 8188)
+++ code/stage/trunk/libstage/main.cc   2009-08-11 02:02:02 UTC (rev 8189)
@@ -11,7 +11,7 @@
 using namespace Stg;
 
 const char* USAGE = 
-  "USAGE:  stage [options] [<worldfile>]\n"
+  "USAGE:  stage [options] <worldfile1> [worldfile2 ... worldfileN]\n"
   "Available [options] are:\n"
   "  --clock        : print simulation time peridically on standard output\n"
   "  -c             : short for --clock\n"
@@ -19,8 +19,7 @@
   "  -g             : short for --gui\n"
   "  --help         : print this message\n"
   "  -h             : short for --help\n"
-  "  -?             : short for --help\n"
-  " If <worldfile> is not specified, Stage starts with a file selector dialog";
+  "  -?             : short for --help";
 
 /* options descriptor */
 static struct option longopts[] = {
@@ -77,7 +76,6 @@
   // arguments at index [optindex] and later are not options, so they
   // must be world file names
   
-  bool loaded_world_file = false;
   optindex = optind; //points to first non-option
   while( optindex < argc )
         {
@@ -86,22 +84,18 @@
                         const char* worldfilename = argv[optindex];
                         World* world = ( usegui ? 
                                                                                
new WorldGui( 400, 300, worldfilename ) : 
-                                                                               
new World( worldfilename ) );
+                                                                       new 
World( worldfilename ) );
                         world->Load( worldfilename );
                         world->ShowClock( showclock );
-                        loaded_world_file = true;
+
+                        if( ! world->paused ) 
+                               world->Start();
                  }
                optindex++;
         }
   
-  if( loaded_world_file == false ) 
-        {
-               // TODO: special window/loading dialog for this case
-               new WorldGui( 400, 300 );
-        }
-  
   if( usegui )
-        while( true ) World::UpdateAll();
+        Fl::run();      
   else
         while( ! World::UpdateAll() );
 

Modified: code/stage/trunk/libstage/model.cc
===================================================================
--- code/stage/trunk/libstage/model.cc  2009-08-10 08:49:51 UTC (rev 8188)
+++ code/stage/trunk/libstage/model.cc  2009-08-11 02:02:02 UTC (rev 8189)
@@ -210,7 +210,6 @@
         log_state(false),
     map_resolution(0.1),
     mass(0),
-    //on_velocity_list( false ),
     parent(parent),
     pose(),
         power_pack( NULL ),
@@ -226,7 +225,7 @@
         trail_length(50),
         trail_interval(5),
     type(type),        
-        update_list_num( -1 ),
+        event_queue_num( -1 ),
     used(false),
     velocity(),
     watts(0.0),
@@ -297,6 +296,14 @@
   UnMap(); // remove any old cruft rendered during startup
   Map();
 
+  if( FindPowerPack() )
+        world->Enqueue( 0, World::Event::ENERGY, interval_energy, this );
+  
+  // find the queue for update events: zero if thread safe, else we
+  // ask the world to assign us to a queue  
+  if( event_queue_num < 1 )            
+        event_queue_num = thread_safe ? world->GetEventQueue( this ) : 0;
+  
   CallCallbacks( &hooks.init );
 }  
 
@@ -322,8 +329,7 @@
 {
   if( flag )
         {
-               flag_list.erase( remove( flag_list.begin(), flag_list.end(), 
flag ));
-
+               flag_list.erase( remove( flag_list.begin(), flag_list.end(), 
flag ));           
                CallCallbacks( &hooks.flag_decr );
         }
 }
@@ -341,12 +347,12 @@
 {
   if( flag_list.size() == 0 )
     return NULL;
-
+  
   Flag* flag = flag_list.front();
   flag_list.pop_front();
-
+  
   CallCallbacks( &hooks.flag_decr );
-
+  
   return flag;
 }
 
@@ -634,15 +640,13 @@
 
 void Model::Startup( void )
 {
-  //printf( "Startup model %s\n", this->token );
-
-//   if( update_list_num < 0 )
-//     update_list_num = world->UpdateListAdd( this );
+  //printf( "Startup model %s\n", this->token );  
+  //printf( "model %s using queue %d\n", token, event_queue_num );
   
-  // put my first update in the world's queue
-  world->Enqueue( World::Event::UPDATE, interval, this );
-  world->Enqueue( World::Event::POSE, interval_pose, this );
-
+  // put my first events in the world's queue
+  world->Enqueue( event_queue_num, World::Event::UPDATE, interval, this );
+  world->Enqueue( 0, World::Event::POSE, interval_pose, this );
+  
   CallCallbacks( &hooks.startup );
 }
 
@@ -655,50 +659,15 @@
 
 void Model::Update( void )
 { 
-  // empty - XX todo make this pure?
-}
+  CallCallbacks( &hooks.update );
 
-void Model::SynchronousPostUpdate( void )
-{  
-  CallUpdateCallbacks();
-  
-  // if we're drawing current and a power pack has been installed
-  PowerPack* pp = FindPowerPack();
-  if( pp && ( watts > 0 ))
-        {
-               // consume  energy stored in the power pack
-               stg_joules_t consumed =  watts * (interval * 1e-6); 
-               pp->Dissipate( consumed, GetGlobalPose() );      
-        }  
-  
-  if( trail_length > 0 && world->updates % trail_interval == 0 )
-        {
-               trail.push_back( TrailItem( world->sim_time, GetGlobalPose(), 
color ) ); 
-               
-               if( trail.size() > trail_length )
-                 trail.pop_front();
-        }        
-      
   last_update = world->sim_time;
-
-  if( subs > 0 )
-        // put my next update in the world's queue  
-        world->Enqueue( World::Event::UPDATE, interval, this );
-
-  //  getchar();
   
-  if( log_state )
-        world->Log( this );
+  if( subs > 0 )
+        world->Enqueue( event_queue_num, World::Event::UPDATE, interval, this 
);
 }
 
 
-void Model::CallUpdateCallbacks( void )
-{
-  // if we were updated this timestep, call the callbacks
-  //if( last_update == world->sim_time ) 
-  CallCallbacks( &hooks.update );
-}
-
 stg_meters_t Model::ModelHeight() const
 {      
   stg_meters_t m_child = 0; //max size of any child
@@ -764,50 +733,58 @@
 }  
 
 void Model::UpdateCharge()
-{
-  assert( watts_give > 0 );
-  
+{  
   PowerPack* mypp = FindPowerPack();
   assert( mypp );
   
-  // detach charger from all the packs charged last time
-  FOR_EACH( it, pps_charging )
-        (*it)->ChargeStop();
-  pps_charging.clear();
-
-  // run through and update all appropriate touchers
-  ModelPtrSet touchers;
-  AppendTouchingModels( touchers );
-
-  FOR_EACH( it, touchers )
+  if( watts > 0 ) // dissipation rate
         {
-          Model* toucher = (*it); //(Model*)touchers->data;            
-               PowerPack* hispp =toucher->FindPowerPack();             
+               // consume  energy stored in the power pack
+               stg_joules_t consumed =  watts * (interval_energy * 1e-6); 
+               mypp->Dissipate( consumed, GetGlobalPose() );      
+        }  
+  
+  if( watts_give > 0 ) // transmission to other powerpacks max rate
+        {  
+               // detach charger from all the packs charged last time
+               FOR_EACH( it, pps_charging )
+                 (*it)->ChargeStop();
+               pps_charging.clear();
                
-               if( hispp && toucher->watts_take > 0.0) 
-                 {             
-                        //printf( "   toucher %s can take up to %.2f wats\n", 
-                        //             toucher->Token(), toucher->watts_take );
+               // run through and update all appropriate touchers
+               ModelPtrSet touchers;
+               AppendTouchingModels( touchers );
+               
+               FOR_EACH( it, touchers )
+                 {
+                        Model* toucher = (*it); //(Model*)touchers->data;      
        
+                        PowerPack* hispp =toucher->FindPowerPack();            
                         
-                        stg_watts_t rate = std::min( watts_give, 
toucher->watts_take );
-                        stg_joules_t amount =  rate * interval_energy * 1e-6;
-                        
-                        //printf ( "moving %.2f joules from %s to %s\n",
-                        //              amount, token, toucher->token );
-                        
-                        // set his charging flag
-                        hispp->ChargeStart();
-                        
-                        // move some joules from me to him
-                        mypp->TransferTo( hispp, amount );
-                        
-                        // remember who we are charging so we can detatch next 
time
-                        pps_charging.push_front( hispp );
-                 }
-        }
+                        if( hispp && toucher->watts_take > 0.0) 
+                               {               
+                                 //printf( "   toucher %s can take up to %.2f 
wats\n", 
+                                 //            toucher->Token(), 
toucher->watts_take );
+                                 
+                                 stg_watts_t rate = std::min( watts_give, 
toucher->watts_take );
+                                 stg_joules_t amount =  rate * interval_energy 
* 1e-6;
+                                 
+                                 //printf ( "moving %.2f joules from %s to 
%s\n",
+                                 //             amount, token, toucher->token 
);
+                                 
+                                 // set his charging flag
+                                 hispp->ChargeStart();
+                                 
+                                 // move some joules from me to him
+                                 mypp->TransferTo( hispp, amount );
+                                 
+                                 // remember who we are charging so we can 
detatch next time
+                                 pps_charging.push_front( hispp );
+                               }
+                 }
+        }
   
   // set up the next event
-  world->Enqueue( World::Event::ENERGY, interval_energy, this );
+  world->Enqueue( 0, World::Event::ENERGY, interval_energy, this );
 }
 
 void Model::CommitTestedPose()
@@ -859,9 +836,17 @@
        // ConditionalMove() returns a pointer to the model we hit, or
        // NULL. We use this as a boolean for SetStall()
   SetStall( ConditionalMove( pose + p ) );
+  
+  if( trail_length > 0 && world->updates % trail_interval == 0 )
+        {
+               trail.push_back( TrailItem( world->sim_time, GetGlobalPose(), 
color ) ); 
+               
+               if( trail.size() > trail_length )
+                 trail.pop_front();
+        }                  
 
   //if( ! velocity.IsZero() )
-  world->Enqueue( World::Event::POSE, interval_pose, this );
+  world->Enqueue( 0, World::Event::POSE, interval_pose, this );
 }
 
 Model* Model::GetUnsubscribedModelOfType( stg_model_type_t type ) const

Modified: code/stage/trunk/libstage/model_load.cc
===================================================================
--- code/stage/trunk/libstage/model_load.cc     2009-08-10 08:49:51 UTC (rev 
8188)
+++ code/stage/trunk/libstage/model_load.cc     2009-08-11 02:02:02 UTC (rev 
8189)
@@ -21,6 +21,9 @@
   
   PRINT_DEBUG1( "Model \"%s\" loading...", token );
   
+  // choose the thread to run in, if thread_safe > 0 
+  event_queue_num = wf->ReadInt( wf_entity, "event_queue", event_queue_num );
+
   if( wf->PropertyExists( wf_entity, "joules" ) )
         {
                if( !power_pack )
@@ -55,10 +58,6 @@
   if( (watts_give > 0.0) && !pp)
         PRINT_WARN1( "Model %s: Setting \"watts_give\" has no effect unless 
\"joules\" is specified for this model or a parent", token );
   
-  if( watts_give ) // need to get the world to test this model for charging 
others
-        //world->ChargeListAdd( this );
-        world->Enqueue( World::Event::ENERGY, interval_energy, this );
-
   watts_take = wf->ReadFloat( wf_entity, "take_watts", watts_take );
   if( (watts_take > 0.0) & !pp )
         PRINT_WARN1( "Model %s: Setting \"watts_take\" has no effect unless 
\"joules\" is specified for this model or a parent", token );    

Modified: code/stage/trunk/libstage/stage.hh
===================================================================
--- code/stage/trunk/libstage/stage.hh  2009-08-10 08:49:51 UTC (rev 8188)
+++ code/stage/trunk/libstage/stage.hh  2009-08-11 02:02:02 UTC (rev 8189)
@@ -1003,8 +1003,21 @@
         };
         
         std::vector<std::priority_queue<Event> > event_queues;
-        void Enqueue( Event::type_t type, stg_usec_t delay, Model* mod );
+        void Enqueue( unsigned int queue_num, Event::type_t type, stg_usec_t 
delay, Model* mod );
         
+        /** The sim time of the next event in the queue. */
+        //stg_usec_t time_of_next_event;
+        uint32_t event_pending_count;
+        
+        stg_usec_t sim_interval;
+        
+        /** consume events from the queue up to and including the current 
sim_time */
+        void ConsumeQueue( unsigned int queue_num );
+
+        /** returns an event queue index number for a model to use for
+                 updates */
+        unsigned int GetEventQueue( Model* mod );
+
   public:
     /** returns true when time to quit, false otherwise */
     static bool UpdateAll(); 
@@ -1403,8 +1416,6 @@
     std::vector<Option*> drawOptions;
     FileManager* fileMan; ///< Used to load and save worldfiles
         std::vector<stg_usec_t> interval_log;
-
-    stg_usec_t interval_real;   ///< real-time interval between updates - set 
this to zero for 'as fast as possible
         
         /** Stage attempts to run this many times faster than real
                  time. If -1, Stage runs as fast as possible. */
@@ -1416,6 +1427,8 @@
     stg_usec_t real_time_of_last_update;
        
     // static callback functions
+               static void UpdateCallback( WorldGui* world );
+
     static void windowCb( Fl_Widget* w, void* p );     
     static void fileLoadCb( Fl_Widget* w, void* p );
     static void fileSaveCb( Fl_Widget* w, void* p );
@@ -1472,13 +1485,7 @@
     void Show(); 
 
     /** Get human readable string that describes the current global energy 
state. */
-    std::string EnergyString( void );
-       
-    /** Set the minimum real time interval between world updates, in
-                 microeconds. */
-    void SetRealTimeInterval( stg_usec_t usec )
-    { interval_real = usec; }
-
+    std::string EnergyString( void );  
     virtual void RemoveChild( Model* mod );     
   };
 
@@ -1807,15 +1814,15 @@
                bool rebuild_displaylist; ///< iff true, regenerate block 
display list before redraw
                char* say_string;   ///< if non-null, this string is displayed 
in the GUI 
                
-               stg_bool_t stall;
-               /** Thread safety flag. Iff true, Update() may be called in
-                               parallel with other models. Defaults to false 
for safety */
-               int subs;    ///< the number of subscriptions to this model
-               bool thread_safe;
-               
-               /** Cache of recent poses, used to draw the trail. */
-               std::list<TrailItem> trail;
-
+        stg_bool_t stall;
+        int subs;    ///< the number of subscriptions to this model
+        /** Thread safety flag. Iff true, Update() may be called in
+                 parallel with other models. Defaults to false for safety */
+        bool thread_safe;
+        
+        /** Cache of recent poses, used to draw the trail. */
+        std::list<TrailItem> trail;
+        
                /** The maxiumum length of the trail drawn. Default is 20, but 
can
                                be set in the world file using the tail_length 
model
                                property. */
@@ -1825,13 +1832,13 @@
                long unsigned int trail_interval;
 
                stg_model_type_t type;  
-               /** The index into the world's vector of update lists. Initially
-                               -1, to indicate that it is not on a list yet. */
-       int update_list_num; 
-       bool used;   ///< TRUE iff this model has been returned by 
GetUnusedModelOfType()  
-       Velocity velocity;
-       stg_watts_t watts;///< power consumed by this model
-       
+        /** The index into the world's vector of event queues. Initially
+                 -1, to indicate that it is not on a list yet. */
+        int event_queue_num; 
+        bool used;   ///< TRUE iff this model has been returned by 
GetUnusedModelOfType()  
+        Velocity velocity;
+        stg_watts_t watts;///< power consumed by this model
+        
        /** If >0, this model can transfer energy to models that have
                watts_take >0 */
        stg_watts_t watts_give;
@@ -1938,7 +1945,6 @@
         virtual void Startup();
         virtual void Shutdown();
         virtual void Update();
-        virtual void SynchronousPostUpdate();
         virtual void UpdatePose();
         virtual void UpdateCharge();
 
@@ -1946,10 +1952,6 @@
 
         stg_meters_t ModelHeight() const;
 
-        //bool UpdateDue( void );
-        //void UpdateIfDue();
-        void CallUpdateCallbacks( void );
-
         void DrawBlocksTree();
         virtual void DrawBlocks();
         void DrawBoundingBox();

Modified: code/stage/trunk/libstage/test.cc
===================================================================
--- code/stage/trunk/libstage/test.cc   2009-08-10 08:49:51 UTC (rev 8188)
+++ code/stage/trunk/libstage/test.cc   2009-08-11 02:02:02 UTC (rev 8189)
@@ -37,12 +37,8 @@
   Init( &argc, &argv);
 
   WorldGui world( 400,400, "Test" );
-
-  world.SetRealTimeInterval( 10000 );
-
   world.Start();
 
-
   Geom geom;
   bzero( &geom, sizeof(geom) );
 

Modified: code/stage/trunk/libstage/world.cc
===================================================================
--- code/stage/trunk/libstage/world.cc  2009-08-10 08:49:51 UTC (rev 8188)
+++ code/stage/trunk/libstage/world.cc  2009-08-11 02:02:02 UTC (rev 8189)
@@ -99,7 +99,9 @@
   wf( NULL ),
   paused( false ),
   steps(0),
-  event_queues(1)
+  event_queues(1),
+  //  time_of_next_event(0)
+  sim_interval( 1e5 ) // 100 msec
 {
   if( ! Stg::InitDone() )
     {
@@ -149,57 +151,41 @@
   return quit;
 }
 
-// void* World::update_thread_entry( std::pair<World*,int> *thread_info )
-// {
-//   World* world = thread_info->first;
-//   int thread_instance = thread_info->second;
+void* World::update_thread_entry( std::pair<World*,int> *thread_info )
+{
+  World* world = thread_info->first;
+  int thread_instance = thread_info->second;
 
-//   //g_mutex_lock( world->thread_mutex );
-//   pthread_mutex_lock( &world->thread_mutex );
+  pthread_mutex_lock( &world->thread_mutex );
   
-//   while( 1 )
-//     {
-//       // wait until the main thread signals us
-//       //puts( "worker waiting for start signal" );
+  while( 1 )
+       {
+         // wait until the main thread signals us
+         //puts( "worker waiting for start signal" );
 
-//       //g_cond_wait( world->threads_start_cond, world->thread_mutex );
-//       //g_mutex_unlock( world->thread_mutex );
-//       pthread_cond_wait( &world->threads_start_cond, &world->thread_mutex );
-//       pthread_mutex_unlock( &world->thread_mutex );
+         pthread_cond_wait( &world->threads_start_cond, &world->thread_mutex );
+         pthread_mutex_unlock( &world->thread_mutex );
 
+         //puts( "worker thread awakes" );
 
-
-//       //puts( "worker thread awakes" );
+         // consume events on the queue up to the current sim time
+         world->ConsumeQueue( thread_instance );
+                 
+         // done working, so increment the counter. If this was the last
+         // thread to finish working, signal the main thread, which is
+         // blocked waiting for this to happen
          
-//       // loop over the list of rentrant models for this thread
-//       FOR_EACH( it, world->update_lists[thread_instance] )
-//              {
-//                     Model* mod = *it;
-//                     //printf( "thread %d updating model %s (%p)\n", 
thread_instance, mod->Token(), mod );
-                       
-//                     // TODO - some of this (Model::Update()) is not thread 
safe!
-//                     //if( mod->UpdateDue() )
-//                       mod->Update();
-//              }
-         
-//       // done working, so increment the counter. If this was the last
-//       // thread to finish working, signal the main thread, which is
-//       // blocked waiting for this to happen
-
-//       //g_mutex_lock( world->thread_mutex );          
-//       pthread_mutex_lock( &world->thread_mutex );     
-
-//       if( --world->threads_working == 0 )
-//              {
-//                     //puts( "last worker signalling main thread" );
-//                     //g_cond_signal( world->threads_done_cond );
-//                     pthread_cond_signal( &world->threads_done_cond );
-//              }
-//       // keep lock going round the loop
-//     }
+         pthread_mutex_lock( &world->thread_mutex );     
+         if( --world->threads_working == 0 )
+                {
+                       //puts( "last worker signalling main thread" );
+                       pthread_cond_signal( &world->threads_done_cond );
+                }
+         // keep lock going round the loop
+       }
   
-//   return NULL;
-// }
+  return NULL;
+}
 
 
 void World::RemoveModel( Model* mod )
@@ -315,27 +301,27 @@
   if( worker_threads > 0 )
         {
                PRINT_WARN( "\nmulti-thread support is experimental and may not 
work properly, if at all." );
-//             update_lists.resize( worker_threads + 1 );
                
-//             // kick off count threads.
-//             for( unsigned int t=0; t<worker_threads; t++ )
-//               {
-//                      std::pair<World*,int> *p = new std::pair<World*,int>( 
this, t+1 );
+               event_queues.resize( worker_threads + 1 );
+               
+               // kick off the threads
+               for( unsigned int t=0; t<worker_threads; t++ )
+                 {
+                        std::pair<World*,int> *p = new std::pair<World*,int>( 
this, t+1 );
                         
-//                      //normal posix pthread C function pointer
-//                      typedef void* (*func_ptr) (void*);
+                        //normal posix pthread C function pointer
+                        typedef void* (*func_ptr) (void*);
                         
-//                      pthread_t pt;
-//                      pthread_create( &pt,
-//                                                               NULL,
-//                                                               
(func_ptr)World::update_thread_entry, 
-//                                                               p );
-//               }
+                        pthread_t pt;
+                        pthread_create( &pt,
+                                                                 NULL,
+                                                                 
(func_ptr)World::update_thread_entry, 
+                                                                 p );
+                 }
                
                printf( "[threads %u]", worker_threads );       
         }
 
-
   // Iterate through entitys and create objects of the appropriate type
   for( int entity = 1; entity < wf->GetEntityCount(); entity++ )
     {
@@ -486,132 +472,121 @@
        }      
 }
 
-bool World::Update()
-{
-  PRINT_DEBUG( "World::Update()" );
-  
-  // if we've run long enough, exit
-  if( PastQuitTime() ) {
-    if( IsGUI() == false )
-      return true;             
-  }
-  
-  if( paused )
-       {
-         if( steps < 1 )        
-               return true;
-         else
-               {
-                 --steps;
-                 //printf( "world::update (steps remaining %d)\n", steps );    
          
-               }
-       }
+void World::ConsumeQueue( unsigned int queue_num )
+{  
+  std::priority_queue<Event>& queue = event_queues[queue_num];
 
-  dirty = true; // need redraw 
-  
-  stg_usec_t next_time = 0;
-    
-  // TESTING
-  static unsigned int last_queue_len = 0;  
-  unsigned int queue_len = event_queues[0].size();
-  if( last_queue_len != 0 && last_queue_len != queue_len )
-        {
-               printf( "queue length changed from %u to %u\n", last_queue_len, 
queue_len );
-               getchar();
-        }
-  // END TESTING
+  if( queue.empty() )
+        return;
 
-  last_queue_len = queue_len;
-
   // update everything on the event queue that happens at this time or earlier
-  if( ! event_queues[0].empty() )
+  Event ev( queue.top() );    
+  while( ev.time <= sim_time ) 
         {
-               Event ev( event_queues[0].top() );  
-               while( ev.time <= sim_time ) 
+               //                       printf( "@ %llu next event <%s %llu 
%s>\n", 
+               //                                              sim_time,
+               //                                              ev.TypeStr( 
ev.type ),
+               //                                              ev.time, 
+               //                                              ev.mod->Token() 
);
+               
+               queue.pop();
+               
+               // only update events are allowed in queues other than zero
+               if( queue_num > 0 && ev.type != Event::UPDATE )
+                 PRINT_WARN1( "event type %d in async queue", queue_num );
+               
+               switch( ev.type )
                  {
-//                      printf( "@ %llu next event <%s %llu %s>\n", 
-//                                             sim_time,
-//                                             ev.TypeStr( ev.type ),
-//                                             ev.time, 
-//                                             ev.mod->Token() );
-                
-                        event_queues[0].pop();
+                 case Event::UPDATE:                             
+                        ev.mod->Update();
+                        break;
                         
-                        switch( ev.type )
-                               {
-                               case Event::UPDATE:                             
  
-                                 ev.mod->Update();
-                                 ev.mod->SynchronousPostUpdate();
-                                 break;
-
-                               case Event::POSE:                               
  
-                                 ev.mod->UpdatePose();
-                                 break;
-
-                               case Event::ENERGY:                             
  
-                                 ev.mod->UpdateCharge();
-                                 break;
-                                 
-                               default:
-                                 PRINT_WARN1( "unknown event type %d", ev.type 
);
-                               }
+                 case Event::POSE:                               
+                        ev.mod->UpdatePose();
+                        break;
                         
-                        ev = event_queues[0].top();
+                 case Event::ENERGY:                             
+                        ev.mod->UpdateCharge();
+                        break;
+                        
+                 default:
+                        PRINT_WARN1( "unknown event type %d", ev.type );
                  }
-
-               next_time = ev.time;            
                
-               stg_usec_t step = next_time - sim_time;
-               // smoothed interval tracking
-               interval_track = 0.1 * step + 0.9 * interval_track;
-
-               // printf( "@ %llu done. (next event at %llu)\n\n", sim_time, 
next_time );
+               ev = queue.top();
         }
-  
+}
 
-  // world callbacks
-  CallUpdateCallbacks();
 
-  // move the clock on to the next event
-  sim_time = next_time;
-  this->updates++;  
-       
-    
-//   // then update all models on the update lists
-//   FOR_EACH( it, update_lists[0] )
+bool World::Update()
+{
+  PRINT_DEBUG( "World::Update()" );
+  
+  // if we've run long enough, exit
+//   if( PastQuitTime() ) 
 //      {
-//             //printf( "thread MAIN updating model %s\n", (*it)->Token() );
-//             (*it)->UpdateIfDue();
+//             if( IsGUI() == false )
+//               return true;          
 //      }
   
-//   if( worker_threads > 0 )
-//     {
-//       pthread_mutex_lock( &thread_mutex );
-//       threads_working = worker_threads; 
-//       // unblock the workers - they are waiting on this condition var
-//       //puts( "main thread signalling workers" );
-//       pthread_cond_broadcast( &threads_start_cond );
-
-//       // wait for all the last update job to complete - it will
-//       // signal the worker_threads_done condition var
-//       while( threads_working > 0  )
-//             {
-//               //puts( "main thread waiting for workers to finish" );
-//               pthread_cond_wait( &threads_done_cond, &thread_mutex );
-//             }
-//       pthread_mutex_unlock( &thread_mutex );                 
-//       //puts( "main thread awakes" );
-
-//             // TODO: allow threadsafe callbacks to be called in worker
-//             // threads
-         
-//     }
-
-//   // do any sychronous updates we need to do
-//   for( unsigned int i=1; i<update_lists.size(); i++ )
-//      FOR_EACH( it, update_lists[i] )
-//             (*it)->SynchronousPostUpdate();
+  if( event_pending_count < 1 )
+        {
+               PRINT_WARN( "event queue(s) empty." );
+               return false;
+    }
     
+  //   if( paused )
+  //   {
+  //     if( steps < 1 )        
+  //           return true;
+  //     else
+  //           {
+  //             --steps;
+  //             //printf( "world::update (steps remaining %d)\n", steps );    
          
+  //           }
+  //   }
+  
+  sim_time += sim_interval; 
+
+  // handle the zeroth queue synchronously in the main thread
+  ConsumeQueue( 0 );
+  
+  // handle all the remaining queues asynchronously in worker threads
+  if( worker_threads > 0 )
+    {
+               pthread_mutex_lock( &thread_mutex );
+               threads_working = worker_threads; 
+               // unblock the workers - they are waiting on this condition var
+               //puts( "main thread signalling workers" );
+               pthread_cond_broadcast( &threads_start_cond );
+       
+               // todo - take the 1th thread work here?
+       
+      // wait for all the last update job to complete - it will
+      // signal the worker_threads_done condition var
+      while( threads_working > 0  )
+                 {
+                        //puts( "main thread waiting for workers to finish" );
+                        pthread_cond_wait( &threads_done_cond, &thread_mutex );
+                 }
+      pthread_mutex_unlock( &thread_mutex );            
+               //puts( "main thread awakes" );
+               
+               // TODO: allow threadsafe callbacks to be called in worker
+               // threads              
+    }
+                                               
+  //stg_usec_t step = time_of_next_event - sim_time;    
+  // smoothed interval tracking
+  //interval_track = 0.1 * step + 0.9 * interval_track;
+  dirty = true; // need redraw 
+  // printf( "@ %llu done. (next event at %llu)\n\n", sim_time, next_time );
+  
+  // world callbacks
+  CallUpdateCallbacks();
+  
+  ++updates;  
+  
   if( show_clock && ((this->updates % show_clock_interval) == 0) )
        {
          printf( "\r[Stage: %s]", ClockString().c_str() );
@@ -626,6 +601,13 @@
   models_by_name[mod->token] = mod;
 }
 
+unsigned int World::GetEventQueue( Model* mod )
+{
+  if( worker_threads < 1 )
+        return 0;
+  return( (random() % worker_threads) + 1);
+}
+
 Model* World::GetModel( const char* name ) const
 {
   PRINT_DEBUG1( "looking up model name %s in models_by_name", name );
@@ -1114,11 +1096,12 @@
   //LogEntry::Print();
 }
 
-void World::Enqueue( Event::type_t type, stg_usec_t delay, Model* mod )
+void World::Enqueue( unsigned int queue_num, Event::type_t type, stg_usec_t 
delay, Model* mod )
 {
   //printf( "enqueue at %llu %p %s\n", sim_time + delay, mod, mod->Token() );
-
-  event_queues[0].push( Event( type, sim_time + delay, mod ) );
+  
+  event_queues[queue_num].push( Event( type, sim_time + delay, mod ) );
+  ++event_pending_count;
 }
 
 bool World::Event::operator<( const Event& other ) const 

Modified: code/stage/trunk/libstage/worldgui.cc
===================================================================
--- code/stage/trunk/libstage/worldgui.cc       2009-08-10 08:49:51 UTC (rev 
8188)
+++ code/stage/trunk/libstage/worldgui.cc       2009-08-11 02:02:02 UTC (rev 
8189)
@@ -190,7 +190,6 @@
   drawOptions(),
   fileMan( new FileManager() ),
   interval_log(),
-  interval_real( (stg_usec_t)1e5 ),
   speedup(1.0), // real time
   mbar( new Fl_Menu_Bar(0,0, W, 30)),
   oDlg( NULL ),
@@ -199,7 +198,7 @@
 {
   interval_log.resize(16);
   for( unsigned int i=0; i<interval_log.size(); i++ )
-        interval_log[i] = interval_real;
+        interval_log[i] = sim_interval;
   
   Fl::scheme( "gtk+" );
   resizable(canvas);
@@ -270,23 +269,12 @@
   fileMan->newWorld( filename );
 
   World::Load( filename );
-       
-  int world_section = 0; // use the top-level section for some parms
-  // that traditionally live there
-
-  // todo - remove this and use speedup instead
-  this->interval_real = (stg_usec_t)thousand *  
-        wf->ReadInt( world_section, "interval_real", 
(int)(this->interval_real/thousand) );
   
-  this->speedup = wf->ReadFloat( world_section, "speedup", this->speedup );
+  // worldgui exclusive properties live in the top-level section
+  int world_section = 0; 
+  speedup = wf->ReadFloat( world_section, "speedup", speedup );    
+  paused = wf->ReadInt( world_section, "paused", paused );
   
-  if( sgn(speedup) < 0 )
-        interval_real = 0;
-
-  // this is a world property that's only load()ed in worldgui
-  this->paused = 
-    wf->ReadInt( world_section, "paused", this->paused );
-
   // use the window section for the rest
   int window_section = wf->LookupEntity( "window" );
   
@@ -315,13 +303,17 @@
 void WorldGui::UnLoad() 
 {
   World::UnLoad();
-  //   canvas->camera.setPose( 0, 0 );
 }
 
 bool WorldGui::Save( const char* filename )
 {
   PRINT_DEBUG1( "%s.Save()", token );
-       
+  
+  // worldgui exclusive properties live in the top-level section
+  int world_section = 0; 
+  wf->WriteFloat( world_section, "speedup", speedup );    
+  wf->WriteInt( world_section, "paused", paused );
+
   // use the window section for the rest
   int window_section = wf->LookupEntity( "window" );
        
@@ -341,54 +333,25 @@
   return true;
 }
 
+void WorldGui::UpdateCallback( WorldGui* world )
+{      
+  world->Update();
+}
+
 bool WorldGui::Update()
-{
-  //pause the simulation if quit time is set
-  if( PastQuitTime() && pause_time == false ) {
-         TogglePause();
-         pause_time = true;
-  }
-  
-  // if we're paused and counting down, we need to redraw the window
-  // because it's not drawn on a timer when paused.
-  bool need_redraw = paused && (steps > 0);
-  
-  bool val = World::Update(); 
-  
-  if( need_redraw )
-        canvas->redraw();
-  
-  stg_usec_t timenow;
-  stg_usec_t interval;
+{  
+  double timeout = speedup > 0 ? (sim_interval/1e6) / speedup : 0;
+  Fl::repeat_timeout( timeout, (Fl_Timeout_Handler)UpdateCallback, this );
 
-  const double sleeptime_max = 1e4;
-  double sleeptime = sleeptime_max;
-
-  do { // we loop over updating the GUI, sleeping if there's any spare
-    // time
-    Fl::check();
-
-    timenow = RealTimeNow();
-        
-        // do
-        {              
-               interval = timenow - real_time_of_last_update; // guaranteed to 
be >= 0
-
-               if( ! paused ) 
-                 sleeptime = (double)interval_real - (double)interval;
-               
-               if( sleeptime > 0)  
-                 usleep( (stg_usec_t)std::min(sleeptime,sleeptime_max) ); // 
check the GUI at 10Hz min         
-        }
-  } while( interval < interval_real );
+  //printf( "speedup %.2f timeout %.6f\n", speedup, timeout );
   
-  
-  interval_log[updates%interval_log.size()] =  interval;
-  
-real_time_of_last_update = timenow;
-  
-  //puts( "FINSHED UPDATE" );
-  return val;
+  stg_usec_t timenow = RealTimeNow();   
+  stg_usec_t interval = timenow - real_time_of_last_update; 
+  interval_log[updates%interval_log.size()] =  interval;  
+  real_time_of_last_update = timenow;
+   
+  // inherit
+  return World::Update();
 }
 
 std::string WorldGui::ClockString()
@@ -450,23 +413,17 @@
 
 void WorldGui::DrawTree( bool drawall )
 {  
-       FOR_EACH( it, superregions )
-//   for( std::map<stg_point_int_t,SuperRegion*>::iterator it = 
superregions.begin();
-//              it != superregions.end();
-//              it++ )
+  FOR_EACH( it, superregions )
         (*it).second->Draw( drawall );
 }
 
 void WorldGui::DrawFloor()
 {
   PushColor( 1,1,1,1 );
-
-       FOR_EACH( it, superregions )
-//   for( std::map<stg_point_int_t,SuperRegion*>::iterator it = 
superregions.begin();
-//              it != superregions.end();
-//              it++ )
+  
+  FOR_EACH( it, superregions )
         (*it).second->Floor();
-
+  
   PopColor();
 }
 
@@ -570,34 +527,25 @@
 
 void WorldGui::slowerCb( Fl_Widget* w, WorldGui* wg )
 {
-  if( wg->interval_real == 0 )
-        wg->interval_real = 10;
-  else
-        {
-               wg->interval_real *= 1.2;
-        }
+  wg->speedup *= 0.8;  
 }
 
 void WorldGui::fasterCb( Fl_Widget* w, WorldGui* wg )
 {
-  if( wg->interval_real == 0 )
-        putchar( 7 ); // bell!
+  if( wg->speedup <= 0 )
+        putchar( 7 ); // bell - can go no faster
   else
-        {
-               wg->interval_real *= 0.8;
-               if( wg->interval_real < 10 )
-                 wg->interval_real = 0;
-        }
+        wg->speedup *= 1.2;
 }
 
 void WorldGui::realtimeCb( Fl_Widget* w, WorldGui* wg )
 {
-  wg->interval_real = wg->interval_track;
+  wg->speedup = 1.0;
 }
 
 void WorldGui::fasttimeCb( Fl_Widget* w, WorldGui* wg )
 {
-  wg->interval_real = 0;
+  wg->speedup = -1;
 }
 
 void WorldGui::Start()
@@ -608,14 +556,16 @@
   Fl::add_timeout( ((double)canvas->interval/1000), 
                                                 
(Fl_Timeout_Handler)Canvas::TimerCallback, 
                                                 canvas );
+
+       Fl::add_timeout( 0.01, (Fl_Timeout_Handler)UpdateCallback, this );
 }
 
 void WorldGui::Stop()
 {
   World::Stop();
   
-  // remove the redraw timeout
   Fl::remove_timeout( (Fl_Timeout_Handler)Canvas::TimerCallback );     
+  Fl::remove_timeout( (Fl_Timeout_Handler)WorldGui::UpdateCallback );  
 
   // drawn 'cos we cancelled the timeout
   canvas->redraw(); // in case something happened that will never be

Modified: code/stage/trunk/worlds/SFU.world
===================================================================
--- code/stage/trunk/worlds/SFU.world   2009-08-10 08:49:51 UTC (rev 8188)
+++ code/stage/trunk/worlds/SFU.world   2009-08-11 02:02:02 UTC (rev 8189)
@@ -6,8 +6,7 @@
 include "map.inc"
 include "sick.inc"
 
-interval_sim 100  # simulation timestep in milliseconds
-interval_real 0  # real-time interval between simulation updates in 
milliseconds 
+speedup -1 # as fast as possible
 
 paused 0
 resolution 0.1

Modified: code/stage/trunk/worlds/benchmark/cave.world
===================================================================
--- code/stage/trunk/worlds/benchmark/cave.world        2009-08-10 08:49:51 UTC 
(rev 8188)
+++ code/stage/trunk/worlds/benchmark/cave.world        2009-08-11 02:02:02 UTC 
(rev 8189)
@@ -7,8 +7,9 @@
 include "../sick.inc"
 
 resolution 0.02    # resolution of the underlying raytrace mode
-interval_sim 100  # simulation timestep in milliseconds
-interval_real 0 # real-time interval between simulation updates in 
milliseconds 
+
+speedup -1 # as fast as possible
+
 paused 1
 
 # configure the GUI window

Modified: code/stage/trunk/worlds/benchmark/hospital.world
===================================================================
--- code/stage/trunk/worlds/benchmark/hospital.world    2009-08-10 08:49:51 UTC 
(rev 8188)
+++ code/stage/trunk/worlds/benchmark/hospital.world    2009-08-11 02:02:02 UTC 
(rev 8189)
@@ -8,8 +8,7 @@
 # set the resolution of the underlying raytrace model in meters
 resolution 0.02
 
-interval_sim 100  # simulation timestep in milliseconds
-interval_real 0  # real-time interval between simulation updates in 
milliseconds 
+speedup -1 # as fast as possible
 
 paused 1
 

Modified: code/stage/trunk/worlds/fasr.world
===================================================================
--- code/stage/trunk/worlds/fasr.world  2009-08-10 08:49:51 UTC (rev 8188)
+++ code/stage/trunk/worlds/fasr.world  2009-08-11 02:02:02 UTC (rev 8189)
@@ -6,8 +6,7 @@
 include "map.inc"
 include "sick.inc"
 
-interval_real 0 # real-time interval between simulation updates in 
milliseconds 
-speedup 1
+speedup -1 # fast mode
 paused 1
 
 # time to pause (in GUI mode) or quit (in headless mode) the simulation
@@ -15,7 +14,7 @@
 
 resolution 0.02
 
-threads 2
+threads 0
 
 # configure the GUI window
 window

Modified: code/stage/trunk/worlds/pioneer_flocking.world
===================================================================
--- code/stage/trunk/worlds/pioneer_flocking.world      2009-08-10 08:49:51 UTC 
(rev 8188)
+++ code/stage/trunk/worlds/pioneer_flocking.world      2009-08-11 02:02:02 UTC 
(rev 8189)
@@ -5,8 +5,7 @@
 include "pioneer.inc"
 include "map.inc"
 
-interval_sim 100  # simulation timestep in milliseconds
-interval_real 0  # real-time interval between simulation updates in 
milliseconds 
+speedup 100
 
 paused 1
 


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with 
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Playerstage-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/playerstage-commit

Reply via email to