sim/Simulator.cc
changeset 0 2b3e5ec03512
equal deleted inserted replaced
-1:000000000000 0:2b3e5ec03512
       
     1 /*
       
     2  *    Copyright 2004-2006 Intel Corporation
       
     3  * 
       
     4  *    Licensed under the Apache License, Version 2.0 (the "License");
       
     5  *    you may not use this file except in compliance with the License.
       
     6  *    You may obtain a copy of the License at
       
     7  * 
       
     8  *        http://www.apache.org/licenses/LICENSE-2.0
       
     9  * 
       
    10  *    Unless required by applicable law or agreed to in writing, software
       
    11  *    distributed under the License is distributed on an "AS IS" BASIS,
       
    12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       
    13  *    See the License for the specific language governing permissions and
       
    14  *    limitations under the License.
       
    15  */
       
    16 
       
    17 #ifdef HAVE_CONFIG_H
       
    18 #  include <dtn-config.h>
       
    19 #endif
       
    20 
       
    21 #include <oasys/tclcmd/TclCommand.h>
       
    22 
       
    23 #include "Simulator.h"
       
    24 #include "Node.h"
       
    25 #include "Topology.h"
       
    26 #include "SimLog.h"
       
    27 #include "bundling/BundleTimestamp.h"
       
    28 
       
    29 using namespace dtn;
       
    30 
       
    31 namespace dtnsim {
       
    32 
       
    33 template<>
       
    34 Simulator* oasys::Singleton<Simulator, false>::instance_ = NULL;
       
    35 
       
    36 //----------------------------------------------------------------------
       
    37 
       
    38 double Simulator::time_ = 0;
       
    39 bool   Simulator::interrupted_ = false;
       
    40 double Simulator::runtill_ = -1;
       
    41 
       
    42 //----------------------------------------------------------------------
       
    43 Simulator::Simulator()
       
    44     : Logger("Simulator", "/dtnsim"),
       
    45       eventq_(),
       
    46       exit_event_(NULL)
       
    47 {
       
    48 }
       
    49 
       
    50 //----------------------------------------------------------------------
       
    51 void
       
    52 Simulator::post(SimEvent* e)
       
    53 {	
       
    54     instance_->eventq_.push(e);
       
    55 }
       
    56 
       
    57 //----------------------------------------------------------------------
       
    58 void
       
    59 Simulator::exit() 
       
    60 {
       
    61     ::exit(0);
       
    62 }
       
    63 
       
    64 //----------------------------------------------------------------------
       
    65 int
       
    66 Simulator::run_node_events()
       
    67 {
       
    68     bool done;
       
    69     int next_timer;
       
    70     do {
       
    71         done = true;
       
    72         next_timer = -1;
       
    73         
       
    74         Topology::NodeTable::iterator iter;
       
    75         for (iter =  Topology::node_table()->begin();
       
    76              iter != Topology::node_table()->end();
       
    77              ++iter)
       
    78         {
       
    79             check_interrupt();
       
    80         
       
    81             Node* node = iter->second;
       
    82             node->set_active();
       
    83         
       
    84             int next = oasys::TimerSystem::instance()->run_expired_timers();
       
    85             if (next != -1) {
       
    86                 if (next_timer == -1) {
       
    87                     next_timer = next;
       
    88                 } else {
       
    89                     next_timer = std::min(next_timer, next);
       
    90                 }
       
    91             }
       
    92         
       
    93             log_debug("processing all bundle events for node %s", node->name());
       
    94             if (node->process_one_bundle_event()) {
       
    95                 done = false;
       
    96                 while (node->process_one_bundle_event()) {
       
    97                     check_interrupt();
       
    98                 }
       
    99             }
       
   100         }
       
   101     } while (!done);
       
   102 
       
   103     return next_timer;
       
   104 }
       
   105 
       
   106 //----------------------------------------------------------------------
       
   107 void
       
   108 Simulator::log_inqueue_stats()
       
   109 {
       
   110     Topology::NodeTable::iterator node_iter;
       
   111     for (node_iter =  Topology::node_table()->begin();
       
   112          node_iter != Topology::node_table()->end();
       
   113          ++node_iter)
       
   114     {
       
   115         Node* node = node_iter->second;
       
   116 
       
   117         oasys::ScopeLock l(node->pending_bundles()->lock(), "log_inqueue_stats");
       
   118         BundleList::iterator bundle_iter;
       
   119         for (bundle_iter = node->pending_bundles()->begin();
       
   120              bundle_iter != node->pending_bundles()->end();
       
   121              ++bundle_iter)
       
   122         {
       
   123             Bundle* bundle = *bundle_iter;
       
   124             SimLog::instance()->log_inqueue(node, bundle);
       
   125         }
       
   126     }
       
   127 }
       
   128 
       
   129 //----------------------------------------------------------------------
       
   130 void
       
   131 Simulator::run()
       
   132 {
       
   133     oasys::Log* log = oasys::Log::instance();
       
   134     log->set_prefix("--");
       
   135 
       
   136     log_debug("Configuring all nodes");
       
   137     Topology::NodeTable::iterator iter;
       
   138     for (iter = Topology::node_table()->begin();
       
   139          iter != Topology::node_table()->end();
       
   140          ++iter)
       
   141     {
       
   142         iter->second->configure();
       
   143     }
       
   144 
       
   145     log_debug("Setting up interrupt handler");
       
   146     signal(SIGINT, handle_interrupt);
       
   147     
       
   148     log_debug("Starting Simulator event loop...");
       
   149 
       
   150     while (1) {
       
   151         check_interrupt();
       
   152 
       
   153         int next_timer_ms = run_node_events();
       
   154         double next_timer = (next_timer_ms == -1) ? INT_MAX :
       
   155                             time_ + (((double)next_timer_ms) / 1000);
       
   156         double next_event = INT_MAX;
       
   157         log->set_prefix("--");
       
   158         
       
   159         SimEvent* e = NULL;
       
   160         if (! eventq_.empty()) {
       
   161             e = eventq_.top();
       
   162             next_event = e->time();
       
   163         }
       
   164         
       
   165         if ((next_timer_ms == -1) && (e == NULL)) {
       
   166             break;
       
   167         }
       
   168         else if (next_timer < next_event) {
       
   169             time_ = next_timer;
       
   170             log_debug("advancing time by %u ms to %f for next timer",
       
   171                       next_timer_ms, time_);
       
   172         }
       
   173         else {
       
   174             ASSERT(e != NULL);
       
   175             eventq_.pop();
       
   176             time_ = e->time();
       
   177 
       
   178             if (e->is_valid()) {
       
   179                 ASSERT(e->handler() != NULL);
       
   180                 /* Process the event */
       
   181                 log_debug("Event:%p type %s at time %f",
       
   182                           e, e->type_str(), time_);
       
   183                 e->handler()->process(e);
       
   184             }
       
   185         }
       
   186         
       
   187         if ((Simulator::runtill_ != -1) &&
       
   188             (time_ > Simulator::runtill_)) {
       
   189             log_info("Exiting simulation. "
       
   190                      "Current time (%f) > Max time (%f)",
       
   191                      time_, Simulator::runtill_);
       
   192             goto done;
       
   193         }
       
   194     }
       
   195 
       
   196     log_info("Simulator loop done -- no pending events or timers (time is %f)",
       
   197              time_);
       
   198 
       
   199     if (exit_event_) {
       
   200         run_at_event(exit_event_);
       
   201     }
       
   202     
       
   203 done:
       
   204     log_inqueue_stats();
       
   205     SimLog::instance()->flush();
       
   206 }
       
   207 
       
   208 //----------------------------------------------------------------------
       
   209 void
       
   210 Simulator::pause()
       
   211 {
       
   212     oasys::StaticStringBuffer<128> cmd;
       
   213     cmd.appendf("puts \"Simulator paused at time %f...\"", time_);
       
   214     oasys::TclCommandInterp::instance()->exec_command(cmd.c_str());
       
   215 
       
   216     run_console(false);
       
   217 }
       
   218 
       
   219 //----------------------------------------------------------------------
       
   220 void
       
   221 Simulator::run_console(bool complete)
       
   222 {
       
   223     Node* cur_active = Node::active_node();
       
   224     interrupted_ = true;
       
   225     
       
   226     if (complete) {
       
   227         oasys::TclCommandInterp::instance()->command_loop("dtnsim% ");
       
   228     } else {
       
   229         // we can't re-enter tclreadline more than once so if it's not
       
   230         // complete we need to use the simple command loop
       
   231         oasys::TclCommandInterp::instance()->exec_command(
       
   232             "simple_command_loop \"dtnsim% \"");
       
   233     }
       
   234     
       
   235     interrupted_ = false;
       
   236     cur_active->set_active();
       
   237 }
       
   238 
       
   239 //----------------------------------------------------------------------
       
   240 void
       
   241 Simulator::handle_interrupt(int sig)
       
   242 {
       
   243     (void)sig;
       
   244     
       
   245     if (interrupted_) {
       
   246         instance()->exit();
       
   247     } else {
       
   248         interrupted_ = true;
       
   249     }
       
   250 }
       
   251 
       
   252 //----------------------------------------------------------------------
       
   253 void
       
   254 Simulator::check_interrupt()
       
   255 {
       
   256     if (interrupted_) {
       
   257         oasys::StaticStringBuffer<128> cmd;
       
   258         cmd.appendf("puts \"Simulator interrupted at time %f...\"", time_);
       
   259         oasys::TclCommandInterp::instance()->exec_command(cmd.c_str());
       
   260         run_console(false);
       
   261     }
       
   262 }
       
   263 
       
   264 //----------------------------------------------------------------------
       
   265 /**
       
   266  * Override gettimeofday to return the simulator time.
       
   267  */
       
   268 extern "C" int
       
   269 gettimeofday(struct timeval *tv, struct timezone *tz)
       
   270 {
       
   271     (void)tz;
       
   272     double now = Simulator::time();
       
   273     DOUBLE_TO_TIMEVAL(now, *tv);
       
   274 
       
   275     // Sometimes converting a double like 100.2 into an timeval
       
   276     // results in a value like of 100.199999 so we fudge it a bit here
       
   277     // to make the output look prettier
       
   278     if ((tv->tv_usec % 1000) == 999) {
       
   279         tv->tv_usec += 1;
       
   280     }
       
   281     return 0;
       
   282 }
       
   283 
       
   284 //----------------------------------------------------------------------
       
   285 void
       
   286 Simulator::process(SimEvent *e)
       
   287 {
       
   288     switch (e->type()) {
       
   289     case SIM_AT_EVENT: {
       
   290         run_at_event((SimAtEvent*)e);
       
   291         break;
       
   292     }    
       
   293     default:
       
   294         NOTREACHED;
       
   295     }
       
   296 }
       
   297 
       
   298 //----------------------------------------------------------------------
       
   299 void
       
   300 Simulator::set_exit_event(SimAtEvent* evt)
       
   301 {
       
   302     ASSERTF(exit_event_ == NULL, "cannot set multiple exit events");
       
   303     exit_event_ = evt;
       
   304 }
       
   305 
       
   306 //----------------------------------------------------------------------
       
   307 void
       
   308 Simulator::run_at_event(SimAtEvent* evt)
       
   309 {
       
   310     int err = oasys::TclCommandInterp::instance()->
       
   311               exec_command(evt->objc_, evt->objv_);
       
   312     if (err != 0) {
       
   313         oasys::StringBuffer cmd;
       
   314         cmd.appendf("puts \"ERROR in at command, pausing simulation\"");
       
   315         oasys::TclCommandInterp::instance()->exec_command(cmd.c_str());
       
   316         pause();
       
   317     }
       
   318 }
       
   319 
       
   320 } // namespace dtnsim