src/simulator/default-simulator-impl.cc
author Guillaume Seguin <guillaume@segu.in>
Thu Nov 12 13:19:35 2009 +0100 (2009-11-12)
changeset 5507 915abd2b907b
parent 5302 5ed72d440db4
child 5521 37c6c83d4252
permissions -rw-r--r--
Simulator::SetScheduler now takes an ObjectFactory
craigdo@3470
     1
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
craigdo@3470
     2
/*
craigdo@3470
     3
 * Copyright (c) 2005,2006 INRIA
craigdo@3470
     4
 *
craigdo@3470
     5
 * This program is free software; you can redistribute it and/or modify
craigdo@3470
     6
 * it under the terms of the GNU General Public License version 2 as
craigdo@3470
     7
 * published by the Free Software Foundation;
craigdo@3470
     8
 *
craigdo@3470
     9
 * This program is distributed in the hope that it will be useful,
craigdo@3470
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
craigdo@3470
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
craigdo@3470
    12
 * GNU General Public License for more details.
craigdo@3470
    13
 *
craigdo@3470
    14
 * You should have received a copy of the GNU General Public License
craigdo@3470
    15
 * along with this program; if not, write to the Free Software
craigdo@3470
    16
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
craigdo@3470
    17
 *
craigdo@3470
    18
 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
craigdo@3470
    19
 */
craigdo@3470
    20
craigdo@3470
    21
#include "simulator.h"
craigdo@3470
    22
#include "default-simulator-impl.h"
craigdo@3470
    23
#include "scheduler.h"
craigdo@3470
    24
#include "event-impl.h"
craigdo@3470
    25
craigdo@3470
    26
#include "ns3/ptr.h"
craigdo@3470
    27
#include "ns3/pointer.h"
craigdo@3470
    28
#include "ns3/assert.h"
craigdo@3470
    29
#include "ns3/log.h"
craigdo@3470
    30
craigdo@3470
    31
#include <math.h>
craigdo@3470
    32
craigdo@3470
    33
NS_LOG_COMPONENT_DEFINE ("DefaultSimulatorImpl");
craigdo@3470
    34
craigdo@3470
    35
namespace ns3 {
craigdo@3470
    36
craigdo@3470
    37
NS_OBJECT_ENSURE_REGISTERED (DefaultSimulatorImpl);
craigdo@3470
    38
craigdo@3470
    39
TypeId
craigdo@3470
    40
DefaultSimulatorImpl::GetTypeId (void)
craigdo@3470
    41
{
craigdo@3470
    42
  static TypeId tid = TypeId ("ns3::DefaultSimulatorImpl")
craigdo@3470
    43
    .SetParent<Object> ()
craigdo@3470
    44
    .AddConstructor<DefaultSimulatorImpl> ()
craigdo@3470
    45
    ;
craigdo@3470
    46
  return tid;
craigdo@3470
    47
}
craigdo@3470
    48
craigdo@3470
    49
DefaultSimulatorImpl::DefaultSimulatorImpl ()
craigdo@3470
    50
{
craigdo@3470
    51
  m_stop = false;
craigdo@3470
    52
  // uids are allocated from 4.
craigdo@3470
    53
  // uid 0 is "invalid" events
craigdo@3470
    54
  // uid 1 is "now" events
craigdo@3470
    55
  // uid 2 is "destroy" events
craigdo@3470
    56
  m_uid = 4; 
craigdo@3470
    57
  // before ::Run is entered, the m_currentUid will be zero
craigdo@3470
    58
  m_currentUid = 0;
craigdo@3470
    59
  m_currentTs = 0;
craigdo@3470
    60
  m_unscheduledEvents = 0;
craigdo@3470
    61
}
craigdo@3470
    62
craigdo@3470
    63
DefaultSimulatorImpl::~DefaultSimulatorImpl ()
craigdo@3470
    64
{
craigdo@3470
    65
  while (!m_events->IsEmpty ())
craigdo@3470
    66
    {
mathieu@3807
    67
      Scheduler::Event next = m_events->RemoveNext ();
mathieu@3807
    68
      next.impl->Unref ();
craigdo@3470
    69
    }
craigdo@3470
    70
  m_events = 0;
craigdo@3470
    71
}
craigdo@3470
    72
craigdo@3470
    73
void
craigdo@3470
    74
DefaultSimulatorImpl::Destroy ()
craigdo@3470
    75
{
craigdo@3470
    76
  while (!m_destroyEvents.empty ()) 
craigdo@3470
    77
    {
craigdo@3470
    78
      Ptr<EventImpl> ev = m_destroyEvents.front ().PeekEventImpl ();
craigdo@3470
    79
      m_destroyEvents.pop_front ();
craigdo@3470
    80
      NS_LOG_LOGIC ("handle destroy " << ev);
craigdo@3470
    81
      if (!ev->IsCancelled ())
craigdo@3470
    82
        {
craigdo@3470
    83
          ev->Invoke ();
craigdo@3470
    84
        }
craigdo@3470
    85
    }
craigdo@3470
    86
}
craigdo@3470
    87
craigdo@3470
    88
void
guillaume@5507
    89
DefaultSimulatorImpl::SetScheduler (ObjectFactory schedulerFactory)
craigdo@3470
    90
{
guillaume@5507
    91
  Ptr<Scheduler> scheduler = schedulerFactory.Create<Scheduler> ();
guillaume@5507
    92
craigdo@3470
    93
  if (m_events != 0)
craigdo@3470
    94
    {
craigdo@3470
    95
      while (!m_events->IsEmpty ())
craigdo@3470
    96
        {
mathieu@3807
    97
          Scheduler::Event next = m_events->RemoveNext ();
craigdo@3470
    98
          scheduler->Insert (next);
craigdo@3470
    99
        }
craigdo@3470
   100
    }
craigdo@3470
   101
  m_events = scheduler;
craigdo@3470
   102
}
craigdo@3470
   103
craigdo@3470
   104
void
craigdo@3470
   105
DefaultSimulatorImpl::ProcessOneEvent (void)
craigdo@3470
   106
{
mathieu@3807
   107
  Scheduler::Event next = m_events->RemoveNext ();
craigdo@3470
   108
mathieu@3807
   109
  NS_ASSERT (next.key.m_ts >= m_currentTs);
craigdo@3470
   110
  --m_unscheduledEvents;
craigdo@3470
   111
mathieu@3807
   112
  NS_LOG_LOGIC ("handle " << next.key.m_ts);
mathieu@3807
   113
  m_currentTs = next.key.m_ts;
mathieu@3807
   114
  m_currentUid = next.key.m_uid;
mathieu@3807
   115
  next.impl->Invoke ();
mathieu@3807
   116
  next.impl->Unref ();
craigdo@3470
   117
}
craigdo@3470
   118
craigdo@3470
   119
bool 
craigdo@3470
   120
DefaultSimulatorImpl::IsFinished (void) const
craigdo@3470
   121
{
gjc@4085
   122
  return m_events->IsEmpty () || m_stop;
craigdo@3470
   123
}
craigdo@3470
   124
craigdo@3470
   125
uint64_t
craigdo@3470
   126
DefaultSimulatorImpl::NextTs (void) const
craigdo@3470
   127
{
craigdo@3470
   128
  NS_ASSERT (!m_events->IsEmpty ());
mathieu@3807
   129
  Scheduler::Event ev = m_events->PeekNext ();
mathieu@3807
   130
  return ev.key.m_ts;
craigdo@3470
   131
}
craigdo@3470
   132
craigdo@3470
   133
Time
craigdo@3470
   134
DefaultSimulatorImpl::Next (void) const
craigdo@3470
   135
{
craigdo@3470
   136
  return TimeStep (NextTs ());
craigdo@3470
   137
}
craigdo@3470
   138
craigdo@3470
   139
void
craigdo@3470
   140
DefaultSimulatorImpl::Run (void)
craigdo@3470
   141
{
mathieu@4057
   142
  m_stop = false;
mathieu@4009
   143
  while (!m_events->IsEmpty () && !m_stop) 
craigdo@3470
   144
    {
craigdo@3470
   145
      ProcessOneEvent ();
craigdo@3470
   146
    }
craigdo@3470
   147
craigdo@3470
   148
  // If the simulator stopped naturally by lack of events, make a
craigdo@3470
   149
  // consistency test to check that we didn't lose any events along the way.
craigdo@3470
   150
  NS_ASSERT(!m_events->IsEmpty () || m_unscheduledEvents == 0);
craigdo@3470
   151
}
craigdo@3470
   152
gjc@3515
   153
void
gjc@3515
   154
DefaultSimulatorImpl::RunOneEvent (void)
gjc@3515
   155
{
gjc@3515
   156
  ProcessOneEvent ();
gjc@3515
   157
}
gjc@3515
   158
craigdo@3470
   159
void 
craigdo@3470
   160
DefaultSimulatorImpl::Stop (void)
craigdo@3470
   161
{
craigdo@3470
   162
  m_stop = true;
craigdo@3470
   163
}
craigdo@3470
   164
craigdo@3470
   165
craigdo@3796
   166
//
craigdo@3796
   167
// Schedule an event for a _relative_ time in the future.
craigdo@3796
   168
//
craigdo@3470
   169
EventId
mathieu@3808
   170
DefaultSimulatorImpl::Schedule (Time const &time, EventImpl *event)
craigdo@3470
   171
{
craigdo@3796
   172
  Time tAbsolute = time + Now();
craigdo@3796
   173
craigdo@3796
   174
  NS_ASSERT (tAbsolute.IsPositive ());
craigdo@3796
   175
  NS_ASSERT (tAbsolute >= TimeStep (m_currentTs));
mathieu@3807
   176
  Scheduler::Event ev;
mathieu@3808
   177
  ev.impl = event;
mathieu@3807
   178
  ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep ();
mathieu@3807
   179
  ev.key.m_uid = m_uid;
craigdo@3470
   180
  m_uid++;
craigdo@3470
   181
  ++m_unscheduledEvents;
mathieu@3807
   182
  m_events->Insert (ev);
mathieu@3807
   183
  return EventId (event, ev.key.m_ts, ev.key.m_uid);
craigdo@3470
   184
}
craigdo@3470
   185
craigdo@3470
   186
EventId
mathieu@3808
   187
DefaultSimulatorImpl::ScheduleNow (EventImpl *event)
craigdo@3470
   188
{
mathieu@3807
   189
  Scheduler::Event ev;
mathieu@3808
   190
  ev.impl = event;
mathieu@3807
   191
  ev.key.m_ts = m_currentTs;
mathieu@3807
   192
  ev.key.m_uid = m_uid;
craigdo@3470
   193
  m_uid++;
craigdo@3470
   194
  ++m_unscheduledEvents;
mathieu@3807
   195
  m_events->Insert (ev);
mathieu@3807
   196
  return EventId (event, ev.key.m_ts, ev.key.m_uid);
craigdo@3470
   197
}
craigdo@3470
   198
craigdo@3470
   199
EventId
mathieu@3808
   200
DefaultSimulatorImpl::ScheduleDestroy (EventImpl *event)
craigdo@3470
   201
{
mathieu@3808
   202
  EventId id (Ptr<EventImpl> (event, false), m_currentTs, 2);
craigdo@3470
   203
  m_destroyEvents.push_back (id);
craigdo@3470
   204
  m_uid++;
craigdo@3470
   205
  return id;
craigdo@3470
   206
}
craigdo@3470
   207
craigdo@3470
   208
Time
craigdo@3470
   209
DefaultSimulatorImpl::Now (void) const
craigdo@3470
   210
{
craigdo@3470
   211
  return TimeStep (m_currentTs);
craigdo@3470
   212
}
craigdo@3470
   213
craigdo@3470
   214
Time 
craigdo@3470
   215
DefaultSimulatorImpl::GetDelayLeft (const EventId &id) const
craigdo@3470
   216
{
craigdo@3470
   217
  if (IsExpired (id))
craigdo@3470
   218
    {
craigdo@3470
   219
      return TimeStep (0);
craigdo@3470
   220
    }
craigdo@3470
   221
  else
craigdo@3470
   222
    {
craigdo@3470
   223
      return TimeStep (id.GetTs () - m_currentTs);
craigdo@3470
   224
    }
craigdo@3470
   225
}
craigdo@3470
   226
craigdo@3470
   227
void
mathieu@3807
   228
DefaultSimulatorImpl::Remove (const EventId &id)
craigdo@3470
   229
{
mathieu@3807
   230
  if (id.GetUid () == 2)
craigdo@3470
   231
    {
craigdo@3470
   232
      // destroy events.
craigdo@3470
   233
      for (DestroyEvents::iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++)
craigdo@3470
   234
        {
mathieu@3807
   235
          if (*i == id)
craigdo@3470
   236
            {
craigdo@3470
   237
              m_destroyEvents.erase (i);
craigdo@3470
   238
              break;
craigdo@3470
   239
            }
craigdo@3470
   240
         }
craigdo@3470
   241
      return;
craigdo@3470
   242
    }
mathieu@3807
   243
  if (IsExpired (id))
craigdo@3470
   244
    {
craigdo@3470
   245
      return;
craigdo@3470
   246
    }
mathieu@3807
   247
  Scheduler::Event event;
mathieu@3807
   248
  event.impl = id.PeekEventImpl ();
mathieu@3807
   249
  event.key.m_ts = id.GetTs ();
mathieu@3807
   250
  event.key.m_uid = id.GetUid ();
mathieu@3807
   251
  m_events->Remove (event);
mathieu@3807
   252
  event.impl->Cancel ();
mathieu@3807
   253
  // whenever we remove an event from the event list, we have to unref it.
mathieu@3807
   254
  event.impl->Unref ();
craigdo@3470
   255
craigdo@3470
   256
  --m_unscheduledEvents;
craigdo@3470
   257
}
craigdo@3470
   258
craigdo@3470
   259
void
craigdo@3470
   260
DefaultSimulatorImpl::Cancel (const EventId &id)
craigdo@3470
   261
{
craigdo@3470
   262
  if (!IsExpired (id))
craigdo@3470
   263
    {
craigdo@3470
   264
      id.PeekEventImpl ()->Cancel ();
craigdo@3470
   265
    }
craigdo@3470
   266
}
craigdo@3470
   267
craigdo@3470
   268
bool
craigdo@3470
   269
DefaultSimulatorImpl::IsExpired (const EventId &ev) const
craigdo@3470
   270
{
craigdo@3470
   271
  if (ev.GetUid () == 2)
craigdo@3470
   272
    {
mathieu@5302
   273
      if (ev.PeekEventImpl () == 0 ||
mathieu@5302
   274
          ev.PeekEventImpl ()->IsCancelled ())
mathieu@5302
   275
        {
mathieu@5302
   276
          return true;
mathieu@5302
   277
        }
craigdo@3470
   278
      // destroy events.
craigdo@3470
   279
      for (DestroyEvents::const_iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++)
craigdo@3470
   280
        {
craigdo@3470
   281
          if (*i == ev)
craigdo@3470
   282
            {
craigdo@3470
   283
              return false;
craigdo@3470
   284
            }
craigdo@3470
   285
         }
craigdo@3470
   286
      return true;
craigdo@3470
   287
    }
craigdo@3470
   288
  if (ev.PeekEventImpl () == 0 ||
craigdo@3470
   289
      ev.GetTs () < m_currentTs ||
craigdo@3470
   290
      (ev.GetTs () == m_currentTs &&
craigdo@3470
   291
       ev.GetUid () <= m_currentUid) ||
craigdo@3470
   292
      ev.PeekEventImpl ()->IsCancelled ()) 
craigdo@3470
   293
    {
craigdo@3470
   294
      return true;
craigdo@3470
   295
    }
craigdo@3470
   296
  else
craigdo@3470
   297
    {
craigdo@3470
   298
      return false;
craigdo@3470
   299
    }
craigdo@3470
   300
}
craigdo@3470
   301
craigdo@3470
   302
Time 
craigdo@3470
   303
DefaultSimulatorImpl::GetMaximumSimulationTime (void) const
craigdo@3470
   304
{
craigdo@3470
   305
  // XXX: I am fairly certain other compilers use other non-standard
craigdo@3470
   306
  // post-fixes to indicate 64 bit constants.
craigdo@3470
   307
  return TimeStep (0x7fffffffffffffffLL);
craigdo@3470
   308
}
craigdo@3470
   309
mathieu@3807
   310
} // namespace ns3
craigdo@3470
   311
craigdo@3470
   312