00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifdef HAVE_CONFIG_H
00018 # include <dtn-config.h>
00019 #endif
00020
00021 #include <oasys/tclcmd/TclCommand.h>
00022
00023 #include "Simulator.h"
00024 #include "Node.h"
00025 #include "Topology.h"
00026 #include "SimLog.h"
00027 #include "bundling/BundleTimestamp.h"
00028
00029 using namespace dtn;
00030
00031 namespace dtnsim {
00032
00033 template<>
00034 Simulator* oasys::Singleton<Simulator, false>::instance_ = NULL;
00035
00036
00037
00038 double Simulator::time_ = 0;
00039 bool Simulator::interrupted_ = false;
00040 double Simulator::runtill_ = -1;
00041
00042
00043 Simulator::Simulator()
00044 : Logger("Simulator", "/dtnsim"),
00045 eventq_(),
00046 exit_event_(NULL)
00047 {
00048 }
00049
00050
00051 void
00052 Simulator::post(SimEvent* e)
00053 {
00054 instance_->eventq_.push(e);
00055 }
00056
00057
00058 void
00059 Simulator::exit()
00060 {
00061 ::exit(0);
00062 }
00063
00064
00065 int
00066 Simulator::run_node_events()
00067 {
00068 bool done;
00069 int next_timer;
00070 do {
00071 done = true;
00072 next_timer = -1;
00073
00074 Topology::NodeTable::iterator iter;
00075 for (iter = Topology::node_table()->begin();
00076 iter != Topology::node_table()->end();
00077 ++iter)
00078 {
00079 check_interrupt();
00080
00081 Node* node = iter->second;
00082 node->set_active();
00083
00084 int next = oasys::TimerSystem::instance()->run_expired_timers();
00085 if (next != -1) {
00086 if (next_timer == -1) {
00087 next_timer = next;
00088 } else {
00089 next_timer = std::min(next_timer, next);
00090 }
00091 }
00092
00093 log_debug("processing all bundle events for node %s", node->name());
00094 if (node->process_one_bundle_event()) {
00095 done = false;
00096 while (node->process_one_bundle_event()) {
00097 check_interrupt();
00098 }
00099 }
00100 }
00101 } while (!done);
00102
00103 return next_timer;
00104 }
00105
00106
00107 void
00108 Simulator::log_inqueue_stats()
00109 {
00110 Topology::NodeTable::iterator node_iter;
00111 for (node_iter = Topology::node_table()->begin();
00112 node_iter != Topology::node_table()->end();
00113 ++node_iter)
00114 {
00115 Node* node = node_iter->second;
00116
00117 oasys::ScopeLock l(node->pending_bundles()->lock(), "log_inqueue_stats");
00118 BundleList::iterator bundle_iter;
00119 for (bundle_iter = node->pending_bundles()->begin();
00120 bundle_iter != node->pending_bundles()->end();
00121 ++bundle_iter)
00122 {
00123 Bundle* bundle = *bundle_iter;
00124 SimLog::instance()->log_inqueue(node, bundle);
00125 }
00126 }
00127 }
00128
00129
00130 void
00131 Simulator::run()
00132 {
00133 oasys::Log* log = oasys::Log::instance();
00134 log->set_prefix("--");
00135
00136 log_debug("Configuring all nodes");
00137 Topology::NodeTable::iterator iter;
00138 for (iter = Topology::node_table()->begin();
00139 iter != Topology::node_table()->end();
00140 ++iter)
00141 {
00142 iter->second->configure();
00143 }
00144
00145 log_debug("Setting up interrupt handler");
00146 signal(SIGINT, handle_interrupt);
00147
00148 log_debug("Starting Simulator event loop...");
00149
00150 while (1) {
00151 check_interrupt();
00152
00153 int next_timer_ms = run_node_events();
00154 double next_timer = (next_timer_ms == -1) ? INT_MAX :
00155 time_ + (((double)next_timer_ms) / 1000);
00156 double next_event = INT_MAX;
00157 log->set_prefix("--");
00158
00159 SimEvent* e = NULL;
00160 if (! eventq_.empty()) {
00161 e = eventq_.top();
00162 next_event = e->time();
00163 }
00164
00165 if ((next_timer_ms == -1) && (e == NULL)) {
00166 break;
00167 }
00168 else if (next_timer < next_event) {
00169 time_ = next_timer;
00170 log_debug("advancing time by %u ms to %f for next timer",
00171 next_timer_ms, time_);
00172 }
00173 else {
00174 ASSERT(e != NULL);
00175 eventq_.pop();
00176 time_ = e->time();
00177
00178 if (e->is_valid()) {
00179 ASSERT(e->handler() != NULL);
00180
00181 log_debug("Event:%p type %s at time %f",
00182 e, e->type_str(), time_);
00183 e->handler()->process(e);
00184 }
00185 }
00186
00187 if ((Simulator::runtill_ != -1) &&
00188 (time_ > Simulator::runtill_)) {
00189 log_info("Exiting simulation. "
00190 "Current time (%f) > Max time (%f)",
00191 time_, Simulator::runtill_);
00192 goto done;
00193 }
00194 }
00195
00196 log_info("Simulator loop done -- no pending events or timers (time is %f)",
00197 time_);
00198
00199 if (exit_event_) {
00200 run_at_event(exit_event_);
00201 }
00202
00203 done:
00204 log_inqueue_stats();
00205 SimLog::instance()->flush();
00206 }
00207
00208
00209 void
00210 Simulator::pause()
00211 {
00212 oasys::StaticStringBuffer<128> cmd;
00213 cmd.appendf("puts \"Simulator paused at time %f...\"", time_);
00214 oasys::TclCommandInterp::instance()->exec_command(cmd.c_str());
00215
00216 run_console(false);
00217 }
00218
00219
00220 void
00221 Simulator::run_console(bool complete)
00222 {
00223 Node* cur_active = Node::active_node();
00224 interrupted_ = true;
00225
00226 if (complete) {
00227 oasys::TclCommandInterp::instance()->command_loop("dtnsim% ");
00228 } else {
00229
00230
00231 oasys::TclCommandInterp::instance()->exec_command(
00232 "simple_command_loop \"dtnsim% \"");
00233 }
00234
00235 interrupted_ = false;
00236 cur_active->set_active();
00237 }
00238
00239
00240 void
00241 Simulator::handle_interrupt(int sig)
00242 {
00243 (void)sig;
00244
00245 if (interrupted_) {
00246 instance()->exit();
00247 } else {
00248 interrupted_ = true;
00249 }
00250 }
00251
00252
00253 void
00254 Simulator::check_interrupt()
00255 {
00256 if (interrupted_) {
00257 oasys::StaticStringBuffer<128> cmd;
00258 cmd.appendf("puts \"Simulator interrupted at time %f...\"", time_);
00259 oasys::TclCommandInterp::instance()->exec_command(cmd.c_str());
00260 run_console(false);
00261 }
00262 }
00263
00264
00268 extern "C" int
00269 gettimeofday(struct timeval *tv, struct timezone *tz)
00270 {
00271 (void)tz;
00272 double now = Simulator::time();
00273 DOUBLE_TO_TIMEVAL(now, *tv);
00274
00275
00276
00277
00278 if ((tv->tv_usec % 1000) == 999) {
00279 tv->tv_usec += 1;
00280 }
00281 return 0;
00282 }
00283
00284
00285 void
00286 Simulator::process(SimEvent *e)
00287 {
00288 switch (e->type()) {
00289 case SIM_AT_EVENT: {
00290 run_at_event((SimAtEvent*)e);
00291 break;
00292 }
00293 default:
00294 NOTREACHED;
00295 }
00296 }
00297
00298
00299 void
00300 Simulator::set_exit_event(SimAtEvent* evt)
00301 {
00302 ASSERTF(exit_event_ == NULL, "cannot set multiple exit events");
00303 exit_event_ = evt;
00304 }
00305
00306
00307 void
00308 Simulator::run_at_event(SimAtEvent* evt)
00309 {
00310 int err = oasys::TclCommandInterp::instance()->
00311 exec_command(evt->objc_, evt->objv_);
00312 if (err != 0) {
00313 oasys::StringBuffer cmd;
00314 cmd.appendf("puts \"ERROR in at command, pausing simulation\"");
00315 oasys::TclCommandInterp::instance()->exec_command(cmd.c_str());
00316 pause();
00317 }
00318 }
00319
00320 }