View | Details | Raw Unified | Return to bug 376
Collapse All | Expand All

(-)011897c60e9c (+131 lines)
Added Link Here 
1
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2
3
#include "ns3/simulator.h"
4
#include "ns3/nstime.h"
5
#include "ns3/log.h"
6
#include "ns3/wall-clock-synchronizer.h"
7
#include "ns3/system-thread.h"
8
#include "ns3/string.h"
9
#include "ns3/config.h"
10
#include "ns3/global-value.h"
11
12
#include <unistd.h>
13
#include <sys/time.h>
14
15
using namespace ns3;
16
17
NS_LOG_COMPONENT_DEFINE ("TestSync");
18
19
bool gFirstRun = false;
20
21
  void 
22
inserted_function (void)
23
{
24
  NS_ASSERT (gFirstRun);
25
  NS_LOG_UNCOND ("inserted_function() called at " << 
26
    Simulator::Now ().GetSeconds () << " s");
27
}
28
29
  void 
30
background_function (void)
31
{
32
  NS_ASSERT (gFirstRun);
33
  NS_LOG_UNCOND ("background_function() called at " << 
34
    Simulator::Now ().GetSeconds () << " s");
35
}
36
37
  void 
38
first_function (void)
39
{
40
  NS_LOG_UNCOND ("first_function() called at " << 
41
    Simulator::Now ().GetSeconds () << " s");
42
  gFirstRun = true;
43
}
44
45
class FakeNetDevice
46
{
47
public:
48
  FakeNetDevice ();
49
  void Doit1 (void);
50
  void Doit2 (void);
51
};
52
53
FakeNetDevice::FakeNetDevice ()
54
{
55
  NS_LOG_FUNCTION_NOARGS ();
56
}
57
58
  void
59
FakeNetDevice::Doit2 (void)
60
{
61
  NS_LOG_FUNCTION_NOARGS ();
62
  sleep (1);
63
  for (uint32_t i = 0.001; i < 10000; ++i)
64
    {
65
      //
66
      // Exercise the relative schedule path
67
      //
68
      Simulator::Schedule (Seconds (0), &inserted_function);
69
      usleep (1000);
70
    }
71
}
72
73
  void
74
FakeNetDevice::Doit1 (void)
75
{
76
  NS_LOG_FUNCTION_NOARGS ();
77
  sleep (1);
78
  for (uint32_t i = 0.001; i < 10000; ++i)
79
    {
80
      // 
81
      // Exercise the ScheduleNow path
82
      //
83
      Simulator::ScheduleNow (&inserted_function);
84
      usleep (1000);
85
    }
86
}
87
88
  void 
89
test (void)
90
{
91
  GlobalValue::Bind ("SimulatorImplementationType", 
92
    StringValue ("ns3::RealtimeSimulatorImpl"));
93
94
  FakeNetDevice fnd;
95
96
  // 
97
  // Make sure ScheduleNow works when the system isn't running
98
  //
99
  Simulator::ScheduleNow(&first_function);
100
101
  // 
102
  // drive the progression of m_currentTs at a ten millisecond rate
103
  //
104
  for (double d = 0.; d < 14.999; d += 0.01)
105
    {
106
      Simulator::Schedule (Seconds (d), &background_function);
107
    }
108
109
  Ptr<SystemThread> st1 = Create<SystemThread> (
110
    MakeCallback (&FakeNetDevice::Doit1, &fnd));
111
  st1->Start ();
112
  Ptr<SystemThread> st2 = Create<SystemThread> (
113
    MakeCallback (&FakeNetDevice::Doit2, &fnd));
114
  st2->Start ();
115
116
  Simulator::Stop (Seconds (15.0));
117
  Simulator::Run ();
118
  st1->Join ();
119
  st2->Join ();
120
  Simulator::Destroy ();
121
}
122
123
  int
124
main (int argc, char *argv[])
125
{
126
  for (;;)
127
    {
128
      test ();
129
    }
130
}
131
(-)a/samples/wscript (+3 lines)
 Lines 19-24   def build(bld): Link Here 
19
    obj = bld.create_ns3_program('main-test')
19
    obj = bld.create_ns3_program('main-test')
20
    obj.source = 'main-test.cc'
20
    obj.source = 'main-test.cc'
21
21
22
    obj = bld.create_ns3_program('main-test-sync')
23
    obj.source = 'main-test-sync.cc'
24
22
    obj = bld.create_ns3_program('main-simple',
25
    obj = bld.create_ns3_program('main-simple',
23
                                 ['node', 'internet-stack', 'onoff'])
26
                                 ['node', 'internet-stack', 'onoff'])
24
    obj.source = 'main-simple.cc'
27
    obj.source = 'main-simple.cc'
(-)a/src/simulator/default-simulator-impl.cc (-3 / +8 lines)
 Lines 180-191   DefaultSimulatorImpl::Stop (Time const & Link Here 
180
  m_stopAt = absolute.GetTimeStep ();
180
  m_stopAt = absolute.GetTimeStep ();
181
}
181
}
182
182
183
//
184
// Schedule an event for a _relative_ time in the future.
185
//
183
EventId
186
EventId
184
DefaultSimulatorImpl::Schedule (Time const &time, const Ptr<EventImpl> &event)
187
DefaultSimulatorImpl::Schedule (Time const &time, const Ptr<EventImpl> &event)
185
{
188
{
186
  NS_ASSERT (time.IsPositive ());
189
  Time tAbsolute = time + Now();
187
  NS_ASSERT (time >= TimeStep (m_currentTs));
190
188
  uint64_t ts = (uint64_t) time.GetTimeStep ();
191
  NS_ASSERT (tAbsolute.IsPositive ());
192
  NS_ASSERT (tAbsolute >= TimeStep (m_currentTs));
193
  uint64_t ts = (uint64_t) tAbsolute.GetTimeStep ();
189
  EventId id (event, ts, m_uid);
194
  EventId id (event, ts, m_uid);
190
  m_uid++;
195
  m_uid++;
191
  ++m_unscheduledEvents;
196
  ++m_unscheduledEvents;
(-)a/src/simulator/realtime-simulator-impl.cc (-164 / +171 lines)
 Lines 169-215   RealtimeSimulatorImpl::ProcessOneEvent ( Link Here 
169
  NS_LOG_FUNCTION_NOARGS ();
169
  NS_LOG_FUNCTION_NOARGS ();
170
  //
170
  //
171
  // The idea here is to wait until the next event comes due.  In the case of
171
  // The idea here is to wait until the next event comes due.  In the case of
172
  // a simulation not locked to realtime, the next event is due immediately and
172
  // a realtime simulation, we want real time to be consumed between events.  
173
  // we jump time forward -- there is no real time consumed between events.  In
173
  // It is the realtime synchronizer that causes real time to be consumed by
174
  // the case of a realtime simulation, we do want real time to be consumed 
174
  // doing some kind of a wait.
175
  // between events.  It is the synchronizer that causes real time to be 
176
  // consumed.
177
  //
175
  //
178
  // Now, there is a possibility that a wait down in the call to the synchronizer
176
  // We need to be able to have external events (such as a packet reception event)
179
  // will be interrupted.  In this case, we need to re-evaluate how long to wait 
177
  // cause us to re-evaluate our state.  The way this works is that the synchronizer
180
  // until the next event since the interruption may have been caused by an
178
  // gets interrupted and returs.  So, there is a possibility that things may change
181
  // event inserted before the one that was on the head of the list when we 
179
  // out from under us dynamically.  In this case, we need to re-evaluate how long to 
182
  // started.
180
  // wait in a for-loop until we have waited sucessfully (until a timeout) for the 
181
  // event at the head of the event list.
183
  //
182
  //
184
  // m_synchronizer->Synchronize will return true if the wait was completed
183
  // m_synchronizer->Synchronize will return true if the wait was completed without 
185
  // without interruption, otherwise it will return false.  So our goal is to
184
  // interruption, otherwise it will return false indicating that something has changed
186
  // sit in a for loop trying to synchronize until it returns true.  If this 
185
  // out from under us.  If we sit in the for-loop trying to synchronize until 
187
  // happens we will have successfully synchronized the execution time of the
186
  // Synchronize() returns true, we will have successfully synchronized the execution 
188
  // next event with the wall clock time of the synchronizer.
187
  // time of the next event with the wall clock time of the synchronizer.
189
  //
188
  //
190
189
191
  for (;;) 
190
  for (;;) 
192
    {
191
    {
193
      uint64_t tsDelay = 0;
192
      uint64_t tsDelay = 0;
194
      uint64_t tsNow = m_currentTs;
195
      uint64_t tsNext = 0;
193
      uint64_t tsNext = 0;
194
196
      //
195
      //
197
      // NextTs peeks into the event list and returns the time stamp of the first 
196
      // It is important to understand that m_currentTs is interpreted only as the 
198
      // event in the list.  We need to protect this kind of access with a critical
197
      // timestamp  of the last event we executed.  Current time can a bit of a 
199
      // section.
198
      // slippery concept in realtime mode.  What we have here is a discrete event 
200
      // 
199
      // simulator, so the last event is, by defintion, executed entirely at a single
200
      //  discrete time.  This is the definition of m_currentTs.  It really has 
201
      // nothing to do with the current real time, except that we are trying to arrange
202
      // that at the instant of the beginning of event execution, the current real time
203
      // and m_currentTs coincide.
204
      //
205
      // We use tsNow as the indication of the current real time.
206
      //
207
      uint64_t tsNow;
208
201
      { 
209
      { 
202
        CriticalSection cs (m_mutex);
210
        CriticalSection cs (m_mutex);
203
204
        NS_ASSERT_MSG (NextTs () >= m_currentTs, 
205
          "RealtimeSimulatorImpl::ProcessOneEvent (): "
206
          "Next event time earlier than m_currentTs (list order error)");
207
        //
211
        //
208
        // Since we are in realtime mode, the time to delay has got to be the 
212
        // Since we are in realtime mode, the time to delay has got to be the 
209
        // difference between the current realtime and the timestamp of the next 
213
        // difference between the current realtime and the timestamp of the next 
210
        // event.  Since m_currentTs is actually the timestamp of the last event we 
214
        // event.  Since m_currentTs is actually the timestamp of the last event we 
211
        // executed, it's not particularly meaningful for us here since real time has
215
        // executed, it's not particularly meaningful for us here since real time has
212
        // since elapsed.  
216
        // certainly elapsed since it was last updated.
213
        //
217
        //
214
        // It is possible that the current realtime has drifted past the next event
218
        // It is possible that the current realtime has drifted past the next event
215
        // time so we need to be careful about that and not delay in that case.
219
        // time so we need to be careful about that and not delay in that case.
 Lines 217-225   RealtimeSimulatorImpl::ProcessOneEvent ( Link Here 
217
        NS_ASSERT_MSG (m_synchronizer->Realtime (), 
221
        NS_ASSERT_MSG (m_synchronizer->Realtime (), 
218
          "RealtimeSimulatorImpl::ProcessOneEvent (): Synchronizer reports not Realtime ()");
222
          "RealtimeSimulatorImpl::ProcessOneEvent (): Synchronizer reports not Realtime ()");
219
223
224
        //
225
        // tsNow is set to the normalized current real time.  When the simulation was
226
        // started, the current real time was effectively set to zero; so tsNow is
227
        // the current "real" simulation time.
228
        //
229
        // tsNext is the simulation time of the next event we want to execute.
230
        //
220
        tsNow = m_synchronizer->GetCurrentRealtime ();
231
        tsNow = m_synchronizer->GetCurrentRealtime ();
221
        tsNext = NextTs ();
232
        tsNext = NextTs ();
222
233
234
        //
235
        // tsDelay is therefore the real time we need to delay in order to bring the
236
        // real time in sync with the simulation time.  If we wait for this amount of
237
        // real time, we will accomplish moving the simulation time at the same rate
238
        // as the real time.  This is typically called "pacing" the simulation time.
239
        //
240
        // We do have to be careful if we are falling behind.  If so, tsDelay must be
241
        // zero.  If we're late, don't dawdle.
242
        //
223
        if (tsNext <= tsNow)
243
        if (tsNext <= tsNow)
224
          {
244
          {
225
            tsDelay = 0;
245
            tsDelay = 0;
 Lines 229-241   RealtimeSimulatorImpl::ProcessOneEvent ( Link Here 
229
            tsDelay = tsNext - tsNow;
249
            tsDelay = tsNext - tsNow;
230
          }
250
          }
231
      
251
      
252
        //
253
        // We've figured out how long we need to delay in order to pace the 
254
        // simulation time with the real time.  We're going to sleep, but need
255
        // to work with the synchronizer to make sure we're awakened if something 
256
        // external happens (like a packet is received).  This next line resets
257
        // the synchronizer so that any future event will cause it to interrupt.
258
        //
232
        m_synchronizer->SetCondition (false);
259
        m_synchronizer->SetCondition (false);
233
      }
260
      }
234
261
235
      //
262
      //
236
      // So, we have a time to delay.  This time may actually not be valid anymore
263
      // We have a time to delay.  This time may actually not be valid anymore
237
      // since we released the critical section and a Schedule may have snuck in just
264
      // since we released the critical section immediately above, and a real-time
238
      // after the closing brace above.
265
      // ScheduleReal or ScheduleRealNow may have snuck in, well, between the 
266
      // closing brace above and this comment so to speak.  If this is the case, 
267
      // that schedule operation will have done a synchronizer Signal() that 
268
      // will set the condition variable to true and cause the Synchronize call 
269
      // below to return immediately.
239
      //
270
      //
240
      // It's easiest to understand if you just consider a short tsDelay that only
271
      // It's easiest to understand if you just consider a short tsDelay that only
241
      // requires a SpinWait down in the synchronizer.  What will happen is that 
272
      // requires a SpinWait down in the synchronizer.  What will happen is that 
 Lines 247-351   RealtimeSimulatorImpl::ProcessOneEvent ( Link Here 
247
      // until the condition variable becomes true.  A true condition indicates that
278
      // until the condition variable becomes true.  A true condition indicates that
248
      // the wait should stop.  The condition is set to true by one of the Schedule
279
      // the wait should stop.  The condition is set to true by one of the Schedule
249
      // methods of the simulator; so if we are in a wait down in Synchronize, and
280
      // methods of the simulator; so if we are in a wait down in Synchronize, and
250
      // a Simulator::Schedule is done, the wait down in Synchronize will exit and
281
      // a Simulator::ScheduleReal is done, the wait down in Synchronize will exit and
251
      // Synchronize will return (false).
282
      // Synchronize will return false.  This means we have not actually synchronized
283
      // to the event expiration time.  If no real-time schedule operation is done
284
      // while down in Synchronize, the wait will time out and Synchronize will return 
285
      // true.  This indicates that we have synchronized to the event time.
252
      //
286
      //
253
      // So, we set this condition to false in a critical section.  The code that
287
      // So we need to stay in this for loop, looking for the next event timestamp and 
254
      // sets the condition (Simulator::Schedule) also runs protected by the same
288
      // attempting to sleep until its due.  If we've slept until the timestamp is due, 
255
      // critical section mutex -- there is no race.  We call Synchronize -- if no
289
      // Synchronize returns true and we break out of the sync loop.  If an external
256
      // Simulator::Schedule is done, the waits (sleep- and spin-wait) will complete
290
      // event happens that requires a re-schedule, Synchronize returns false and
257
      // and Synchronize will return true.  If a Schedule is done before we get to 
291
      // we re-evaluate our timing by continuing in the loop.  
258
      // Synchronize, the Synchronize code will check the condition before going to
259
      // sleep.  If a Schedule happens while we are sleeping, we let the kernel wake
260
      // us up.
261
      //
292
      //
262
      // So the bottom line is that we just stay in this for loop, looking for the
293
      // It is expected that tsDelay become shorter as external events interrupt our
263
      // next timestamp and attempting to sleep until its due.  If we've slept until
294
      // waits.
264
      // the timestamp is due, Synchronize() returns true and we break out of the 
265
      //sync loop.  If we're interrupted we continue in the loop.  We may find that
266
      // the next timestamp is actually earlier than we thought, but we continue 
267
      // around the loop and reevaluate and wait for that one correctly.
268
      //
295
      //
269
      if (m_synchronizer->Synchronize (tsNow, tsDelay))
296
      if (m_synchronizer->Synchronize (tsNow, tsDelay))
270
        {
297
        {
271
          NS_LOG_LOGIC ("Interrupted ...");
298
          NS_LOG_LOGIC ("Interrupted ...");
272
          break;
299
          break;
273
        }
300
        }
301
 
302
      //
303
      // If we get to this point, we have been interrupted during a wait by a real-time
304
      // schedule operation.  This means all bets are off regarding tsDelay and we need
305
      // to re-evaluate what it is we want to do.  We'll loop back around in the 
306
      // for-loop and start again from scratch.
307
      //
274
    }
308
    }
275
309
276
  //
310
  //
277
  // Okay, now more words.  We have slept without interruption until the 
311
  // If we break out of the for-loop above, we have waited until the time specified
278
  // timestamp we found at the head of the event list when we started the sleep.
312
  // by the event that was at the head of the event list when we started the process.
279
  // We are now outside a critical section, so another schedule operation can
313
  // Since there is a bunch of code that was executed outside a critical section (the
280
  // sneak in.  What does this mean?  The only thing that can "go wrong" is if
314
  // Synchronize call) we cannot be sure that the event at the head of the event list
281
  // the new event was moved in ahead of the timestamp for which we waited.
315
  // is the one we think it is.  What we can be sure of is that it is time to execute
282
  //
316
  // whatever event is at the head of this list if the list is in time order.
283
  // If you think about it, this is not a problem, since the best we can 
284
  // possibly do is to execute the event as soon as we can execute it.  We'll
285
  // be a little late, but we were late anyway.
286
  //
287
  // So we just go ahead and pull the first event off of the list, even though
288
  // it may be the case that it's not actually the one we waited for.
289
  //
290
  // One final tidbit is, "what the heck time is it anyway"?  The simulator is
291
  // going to want to get a timestamp from the next event and wait until the
292
  // wall clock time is equal to the timestamp.  At the point when those times
293
  // are the same (roughly) we get to this point and set the m_currentTs below.
294
  // That's straightforward here, but you might ask, how does the next event get
295
  // the time when it is inserted from an external source?
296
  //
297
  // The method RealtimeSimulatorImpl::ScheduleNow takes makes an event and 
298
  // needs to schedule that event for immediate execution.  If the simulator is 
299
  // not locked to a realtime source, the current time is m_currentTs.  If it is
300
  // locked to a realtime source, we need to use the real current real time.
301
  // This real time is then used to set the event execution time and will be 
302
  // read by the next.GetTs below and will set the current simulation time.
303
  //
317
  //
304
  EventId next;
318
  EventId next;
305
319
306
  { 
320
  { 
307
    CriticalSection cs (m_mutex);
321
    CriticalSection cs (m_mutex);
308
322
323
    // 
324
    // We do know we're waiting for an event, so there had better be an event on the 
325
    // event queue.  Let's pull it off.  When we release the critical section, the
326
    // event we're working on won't be on the list and so subsequent operations won't
327
    // mess with us.
328
    //
309
    NS_ASSERT_MSG (m_events->IsEmpty () == false, 
329
    NS_ASSERT_MSG (m_events->IsEmpty () == false, 
310
      "RealtimeSimulatorImpl::ProcessOneEvent(): event queue is empty");
330
      "RealtimeSimulatorImpl::ProcessOneEvent(): event queue is empty");
311
312
    next = m_events->RemoveNext ();
331
    next = m_events->RemoveNext ();
313
    --m_unscheduledEvents;
332
    --m_unscheduledEvents;
333
334
    //
335
    // We cannot make any assumption that "next" is the same event we originally waited 
336
    // for.  We can only assume that only that it must be due and cannot cause time 
337
    // to move backward.
338
    //
339
    NS_ASSERT_MSG (next.GetTs () >= m_currentTs,
340
                   "RealtimeSimulatorImpl::ProcessOneEvent(): "
341
                   "next.GetTs() earlier than m_currentTs (list order error)");
342
    NS_LOG_LOGIC ("handle " << next.GetTs ());
343
344
    // 
345
    // Update the current simulation time to be the timestamp of the event we're 
346
    // executing.  From the rest of the simulation's point of view, simulation time
347
    // is frozen until the next event is executed.
348
    //
349
    m_currentTs = next.GetTs ();
350
    m_currentUid = next.GetUid ();
351
352
    // 
353
    // We're about to run the event and we've done our best to synchronize this
354
    // event execution time to real time.  Now, if we're in SYNC_HARD_LIMIT mode
355
    // we have to decide if we've done a good enough job and if we haven't, we've
356
    // been asked to commit ritual suicide.
357
    //
358
    // We check the simulation time against the current real time to make this
359
    // judgement.
360
    //
361
    if (m_synchronizationMode == SYNC_HARD_LIMIT)
362
      {
363
        uint64_t tsFinal = m_synchronizer->GetCurrentRealtime ();
364
        uint64_t tsJitter;
365
366
        if (tsFinal >= m_currentTs)
367
          {
368
            tsJitter = tsFinal - m_currentTs;
369
          }
370
        else
371
          {
372
            tsJitter = m_currentTs - tsFinal;
373
          }
374
375
        if (tsJitter > static_cast<uint64_t>(m_hardLimit.GetTimeStep ()))
376
          {
377
            NS_FATAL_ERROR ("RealtimeSimulatorImpl::ProcessOneEvent (): "
378
                            "Hard real-time limit exceeded (jitter = " << tsJitter << ")");
379
          }
380
      }
314
  }
381
  }
315
382
316
  NS_ASSERT_MSG (next.GetTs () >= m_currentTs,
317
    "RealtimeSimulatorImpl::ProcessOneEvent(): "
318
    "next.GetTs() earlier than m_currentTs (list order error)");
319
  NS_LOG_LOGIC ("handle " << next.GetTs ());
320
  m_currentTs = next.GetTs ();
321
  m_currentUid = next.GetUid ();
322
323
  // 
324
  // We're about to run the event and we've done our best to synchronize this
325
  // event execution time to real time.  Now, if we're in SYNC_HARD_LIMIT mode
326
  // we have to decide if we've done a good enough job and if we haven't, we've
327
  // been asked to commit ritual suicide.
328
  //
383
  //
329
  if (m_synchronizationMode == SYNC_HARD_LIMIT)
384
  // We have got the event we're about to execute completely disentangled from the 
330
    {
385
  // event list so we can execute it outside a critical section without fear of someone
331
      uint64_t tsFinal = m_synchronizer->GetCurrentRealtime ();
386
  // changing things out from under us.
332
      uint64_t tsJitter;
333
334
      if (tsFinal >= m_currentTs)
335
        {
336
          tsJitter = tsFinal - m_currentTs;
337
        }
338
      else
339
        {
340
          tsJitter = m_currentTs - tsFinal;
341
        }
342
343
      if (tsJitter > static_cast<uint64_t>(m_hardLimit.GetTimeStep ()))
344
        {
345
          NS_FATAL_ERROR ("RealtimeSimulatorImpl::ProcessOneEvent (): "
346
                          "Hard real-time limit exceeded (jitter = " << tsJitter << ")");
347
        }
348
    }
349
387
350
  EventImpl *event = next.PeekEventImpl ();
388
  EventImpl *event = next.PeekEventImpl ();
351
  m_synchronizer->EventStart ();
389
  m_synchronizer->EventStart ();
 Lines 479-493   RealtimeSimulatorImpl::Stop (void) Link Here 
479
517
480
static void Placeholder (void) {}
518
static void Placeholder (void) {}
481
519
520
//
521
// Schedule a stop for a _relative_ time in the future.  If the simulation
522
// hasn't started yet, this will effectively be an absolute time.
523
//
482
void 
524
void 
483
RealtimeSimulatorImpl::Stop (Time const &time)
525
RealtimeSimulatorImpl::Stop (Time const &time)
484
{
526
{
485
  NS_LOG_FUNCTION (time);
527
  NS_LOG_FUNCTION (time);
486
  NS_ASSERT_MSG (time.IsPositive (),
487
    "RealtimeSimulatorImpl::Stop(): Negative time");
488
528
489
  Time absolute = Simulator::Now () + time;
529
  Time tAbsolute = Simulator::Now () + time;
490
  m_stopAt = absolute.GetTimeStep ();
530
  NS_ASSERT (tAbsolute.IsPositive ());
531
  NS_ASSERT (tAbsolute >= TimeStep (m_currentTs));
532
  m_stopAt = tAbsolute.GetTimeStep ();
491
  //
533
  //
492
  // For the realtime case, we need a real event sitting out at the end of time
534
  // For the realtime case, we need a real event sitting out at the end of time
493
  // to keep the simulator running (sleeping) while there are no other events 
535
  // to keep the simulator running (sleeping) while there are no other events 
 Lines 497-507   RealtimeSimulatorImpl::Stop (Time const Link Here 
497
  //
539
  //
498
  // The easiest thing to do is to call back up into the simulator to take 
540
  // The easiest thing to do is to call back up into the simulator to take 
499
  // advantage of all of the nice event wrappers.  This will call back down into
541
  // advantage of all of the nice event wrappers.  This will call back down into
500
  // RealtimeSimulatorImpl::Schedule to do the work.
542
  // RealtimeSimulatorImpl::Schedule to do the work.  This path interprets the 
543
  // time as relative, so pass the relative time.
501
  //
544
  //
502
  Simulator::Schedule (absolute, &Placeholder);
545
  Simulator::Schedule (time, &Placeholder);
503
}
546
}
504
547
548
//
549
// Schedule an event for a _relative_ time in the future.
550
//
505
EventId
551
EventId
506
RealtimeSimulatorImpl::Schedule (Time const &time, const Ptr<EventImpl> &event)
552
RealtimeSimulatorImpl::Schedule (Time const &time, const Ptr<EventImpl> &event)
507
{
553
{
 Lines 511-560   RealtimeSimulatorImpl::Schedule (Time co Link Here 
511
  // This is a little tricky.  We get a Ptr<EventImpl> passed down to us in some
557
  // This is a little tricky.  We get a Ptr<EventImpl> passed down to us in some
512
  // thread context.  This Ptr<EventImpl> is not yet shared in any way.  It is 
558
  // thread context.  This Ptr<EventImpl> is not yet shared in any way.  It is 
513
  // possible however that the calling context is not the context of the main 
559
  // possible however that the calling context is not the context of the main 
514
  // scheduler thread (eg. it is in the context of a separate device thread).  
560
  // scheduler thread (e.g. it is in the context of a separate device thread).  
515
  // It would be bad (TM) if we naively wrapped the EventImpl up in an EventId 
561
  // It would be bad (TM) if we naively wrapped the EventImpl up in an EventId 
516
  // that would be accessible from multiple threads without considering thread 
562
  // that would be accessible from multiple threads without considering thread 
517
  // safety.
563
  // safety.
518
  //
519
  // Having multiple EventId containing Ptr<EventImpl> in different thread
520
  // contexts creates a situation where atomic reference count decrements
521
  // would be required (think about an event being scheduled with the calling
522
  // yielding immediately afterward.  The scheduler could become ready and 
523
  // fire the event which would eventually want to release the EventImpl.  If
524
  // the calling thread were readied and executed in mid-release, it would also
525
  // want to release the EventImpl "at the same time."  If we are careless about
526
  // this, multiple deletes are sure to eventually happen as the threads 
527
  // separately play with the EventImpl reference counts.
528
  // 
529
  // The way this all works is that we created an EventImpl in the template 
530
  // function that called us, which may be in the context of a thread separate
531
  // from the simulator thread.  We are managing the lifetime of the EventImpl
532
  // with an intrusive reference count.  The count was initialized to one when
533
  // it was created and is still one right now.  We're going to "wrap" this
534
  // EventImpl in an EventId in this method.  There's an assignment of our 
535
  // Ptr<EventImpl> into another Ptr<EventImpl> inside the EventId which will 
536
  // bump the ref count to two.  We're going to return this EventId to the 
537
  // caller so the calling thread will hold a reference to the underlying 
538
  // EventImpl.  This is what causes the first half of the multithreading issue.
539
  //
540
  // We are going to call Insert() on the EventId to put the event into the 
541
  // scheduler.  Down there, it will do a PeekEventImpl to get the pointer to
542
  // the EventImpl and manually increment the reference count (to three).  From 
543
  // there, the sheduler works with the EventImpl pointer.  When the EventId 
544
  // below goes out of scope, the Ptr<EventImpl> destructor is run and the ref
545
  // count is decremented to two.  When this function returns to the calling
546
  // template function, the Ptr<EventImpl> there will go out of scope and we'll
547
  // decrement the EventImpl ref count leaving it to be the one held by our
548
  // scheduler directly.
549
  //
550
  // The scheduler removes the EventImpl in Remove() or RemoveNext().  In the
551
  // case of Remove(), the scheduler is provided an Event reference and locates
552
  // the corresponding EventImpl in the event list.  It gets the raw pointer to
553
  // the EventImpl, erases the pointer in the list, and manually calls Unref()
554
  // on the pointer.  In RemoveNext(), it gets the raw pointer from the list and
555
  // assigns it to a Ptr<EventImpl> without bumping the reference count, thereby
556
  // transferring ownership to a containing EventId.  This is the second half of
557
  // the multithreading issue.
558
  //
564
  //
559
  // It's clear that we cannot have a situation where the EventImpl is "owned" by
565
  // It's clear that we cannot have a situation where the EventImpl is "owned" by
560
  // multiple threads.  The calling thread is free to hold the EventId as long as
566
  // multiple threads.  The calling thread is free to hold the EventId as long as
 Lines 562-587   RealtimeSimulatorImpl::Schedule (Time co Link Here 
562
  // wants.  The scheduler is free to do the same; and will eventually release
568
  // wants.  The scheduler is free to do the same; and will eventually release
563
  // the reference in the context of thread running ProcessOneEvent().  It is 
569
  // the reference in the context of thread running ProcessOneEvent().  It is 
564
  // "a bad thing" (TM) if these two threads decide to release the underlying
570
  // "a bad thing" (TM) if these two threads decide to release the underlying
565
  // EventImpl "at the same time."
571
  // EventImpl "at the same time" since the result is sure to be multiple frees,
572
  // memory leaks or bus errors.
566
  //
573
  //
567
  // The answer is to make the reference counting of the EventImpl thread safe; 
574
  // The answer is to make the reference counting of the EventImpl thread safe; 
568
  // which we do.  We don't want to force the event implementation to carry around
575
  // which we do.  We don't want to force the event implementation to carry around
569
  // a mutex, so we "lend" it one using a RealtimeEventLock object (m_eventLock)
576
  // a mutex, so we "lend" it one using a RealtimeEventLock object (m_eventLock)
570
  // in the constructor and take it back in the destructor.
577
  // in the constructor of the event and take it back in the destructor.  See the
578
  // event code for details.
571
  //
579
  //
572
  EventId id;
580
  EventId id;
573
574
  {
581
  {
575
    CriticalSection cs (m_mutex);
582
    CriticalSection cs (m_mutex);
576
583
    //
577
    NS_ASSERT_MSG (time.IsPositive (),
584
    // This is the reason we had to bring the absolute time calcualtion in from the
578
      "RealtimeSimulatorImpl::Schedule(): Negative time");
585
    // simulator.h into the implementation.  Since the implementations may be 
579
    NS_ASSERT_MSG (
586
    // multi-threaded, we need this calculation to be atomic.  You can see it is
580
      time >= TimeStep (m_currentTs),
587
    // here since we are running in a CriticalSection.
581
      "RealtimeSimulatorImpl::Schedule(): time < m_currentTs");
588
    //
582
589
    Time tAbsolute = Simulator::Now () + time;
583
    uint64_t ts = (uint64_t) time.GetTimeStep ();
590
    NS_ASSERT_MSG (tAbsolute.IsPositive (), "RealtimeSimulatorImpl::Schedule(): Negative time");
584
591
    NS_ASSERT_MSG (tAbsolute >= TimeStep (m_currentTs), "RealtimeSimulatorImpl::Schedule(): time < m_currentTs");
592
    uint64_t ts = (uint64_t) tAbsolute.GetTimeStep ();
585
    id = EventId (event, ts, m_uid);
593
    id = EventId (event, ts, m_uid);
586
    m_uid++;
594
    m_uid++;
587
    ++m_unscheduledEvents;
595
    ++m_unscheduledEvents;
 Lines 600-607   RealtimeSimulatorImpl::ScheduleNow (cons Link Here 
600
  {
608
  {
601
    CriticalSection cs (m_mutex);
609
    CriticalSection cs (m_mutex);
602
610
603
    id = EventId (event, m_synchronizer->GetCurrentRealtime (), m_uid);
611
    id = EventId (event, m_currentTs, m_uid);
604
    
605
    m_uid++;
612
    m_uid++;
606
    ++m_unscheduledEvents;
613
    ++m_unscheduledEvents;
607
    m_events->Insert (id);
614
    m_events->Insert (id);
(-)a/src/simulator/simulator.cc (-1 / +1 lines)
 Lines 210-216   Simulator::Schedule (Time const &time, c Link Here 
210
Simulator::Schedule (Time const &time, const Ptr<EventImpl> &ev)
210
Simulator::Schedule (Time const &time, const Ptr<EventImpl> &ev)
211
{
211
{
212
  NS_LOG_FUNCTION (time << ev);
212
  NS_LOG_FUNCTION (time << ev);
213
  return GetImpl ()->Schedule (Now () + time, ev);
213
  return GetImpl ()->Schedule (time, ev);
214
}
214
}
215
215
216
EventId
216
EventId
(-)a/src/simulator/simulator.h (-3 / +7 lines)
 Lines 138-146   public: Link Here 
138
  static void Stop (Time const &time);
138
  static void Stop (Time const &time);
139
139
140
  /**
140
  /**
141
   * Schedule an event to expire when the time "now + time" 
141
   * Schedule an event to expire at the relative time "time"
142
   * is reached. When the event expires, the input method 
142
   * is reached.  This can be thought of as scheduling an event
143
   * will be invoked on the input object.
143
   * for the current simulation time plus the Time passed as a
144
   * parameter
145
   *
146
   * When the event expires (when it becomes due to be run), the 
147
   * input method will be invoked on the input object.  
144
   *
148
   *
145
   * @param time the relative expiration time of the event.
149
   * @param time the relative expiration time of the event.
146
   * @param mem_ptr member method pointer to invoke
150
   * @param mem_ptr member method pointer to invoke
(-)a/src/simulator/realtime-simulator-impl.cc (-6 / +35 lines)
 Lines 618-623   RealtimeSimulatorImpl::ScheduleNow (cons Link Here 
618
  return id;
618
  return id;
619
}
619
}
620
620
621
Time
622
RealtimeSimulatorImpl::Now (void) const
623
{
624
  return TimeStep (m_currentTs);
625
}
626
627
//
628
// Schedule an event for a _relative_ time in the future.
629
//
630
EventId
631
RealtimeSimulatorImpl::ScheduleReal (Time const &time, const Ptr<EventImpl> &event)
632
{
633
  NS_LOG_FUNCTION (time << event);
634
  NS_ASSERT (false);
635
  EventId id;
636
  return id;
637
}
638
639
EventId
640
RealtimeSimulatorImpl::ScheduleRealNow (const Ptr<EventImpl> &event)
641
{
642
  NS_LOG_FUNCTION (event);
643
  NS_ASSERT (false);
644
  EventId id;
645
  return id;
646
}
647
648
Time
649
RealtimeSimulatorImpl::RealNow (void) const
650
{
651
  NS_ASSERT (false);
652
  return TimeStep (m_currentTs);
653
}
654
655
621
EventId
656
EventId
622
RealtimeSimulatorImpl::ScheduleDestroy (const Ptr<EventImpl> &event)
657
RealtimeSimulatorImpl::ScheduleDestroy (const Ptr<EventImpl> &event)
623
{
658
{
 Lines 638-649   RealtimeSimulatorImpl::ScheduleDestroy ( Link Here 
638
  }
673
  }
639
674
640
  return id;
675
  return id;
641
}
642
643
Time
644
RealtimeSimulatorImpl::Now (void) const
645
{
646
  return TimeStep (m_currentTs);
647
}
676
}
648
677
649
Time 
678
Time 
(-)a/src/simulator/realtime-simulator-impl.h (-1 / +4 lines)
 Lines 69-81   public: Link Here 
69
  void Stop (Time const &time);
69
  void Stop (Time const &time);
70
  EventId Schedule (Time const &time, const Ptr<EventImpl> &event);
70
  EventId Schedule (Time const &time, const Ptr<EventImpl> &event);
71
  EventId ScheduleNow (const Ptr<EventImpl> &event);
71
  EventId ScheduleNow (const Ptr<EventImpl> &event);
72
  EventId ScheduleReal (Time const &time, const Ptr<EventImpl> &event);
73
  EventId ScheduleRealNow (const Ptr<EventImpl> &event);
72
  EventId ScheduleDestroy (const Ptr<EventImpl> &event);
74
  EventId ScheduleDestroy (const Ptr<EventImpl> &event);
75
  Time Now (void) const;
76
  Time RealNow (void) const;
73
  void Remove (const EventId &ev);
77
  void Remove (const EventId &ev);
74
  void Cancel (const EventId &ev);
78
  void Cancel (const EventId &ev);
75
  bool IsExpired (const EventId &ev) const;
79
  bool IsExpired (const EventId &ev) const;
76
  virtual void RunOneEvent (void);
80
  virtual void RunOneEvent (void);
77
  void Run (void);
81
  void Run (void);
78
  Time Now (void) const;
79
  Time GetDelayLeft (const EventId &id) const;
82
  Time GetDelayLeft (const EventId &id) const;
80
  Time GetMaximumSimulationTime (void) const;
83
  Time GetMaximumSimulationTime (void) const;
81
84
(-)9f03fc6f7296 (+74 lines)
Added Link Here 
1
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2
/*
3
 * Copyright (c) 2008 University of Washington
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License version 2 as
7
 * published by the Free Software Foundation;
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software
16
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
 */
18
19
#include "simulator.h"
20
#include "realtime-simulator.h"
21
#include "realtime-simulator-impl.h"
22
#include "event-impl.h"
23
24
#include "ns3/assert.h"
25
#include "ns3/log.h"
26
27
NS_LOG_COMPONENT_DEFINE ("RealtimeSimulatorExtension");
28
29
namespace ns3 {
30
31
RealtimeSimulatorImpl *
32
RealtimeSimulatorExtension::GetRealtimeImpl (void)
33
{
34
  RealtimeSimulatorImpl *impl = dynamic_cast<RealtimeSimulatorImpl *>(Simulator::GetImpl ());
35
  NS_ASSERT_MSG (impl, 
36
                 "RealtimeSimulatorExtension::GetImpl (): Underlying simulator implementation not realtime");
37
  return impl;
38
}
39
40
Time
41
RealtimeSimulatorExtension::RealNow (void)
42
{
43
  return GetRealtimeImpl ()->RealNow ();
44
}
45
46
EventId
47
RealtimeSimulatorExtension::ScheduleReal (Time const &time, const Ptr<EventImpl> &ev)
48
{
49
  NS_LOG_FUNCTION (time << ev);
50
  return GetRealtimeImpl ()->ScheduleReal (time, ev);
51
}
52
53
EventId
54
RealtimeSimulatorExtension::ScheduleRealNow (const Ptr<EventImpl> &ev)
55
{
56
  NS_LOG_FUNCTION (ev);
57
  return GetRealtimeImpl ()->ScheduleRealNow (ev);
58
}
59
60
EventId
61
RealtimeSimulatorExtension::ScheduleReal (Time const &time, void (*f) (void))
62
{
63
  NS_LOG_FUNCTION (time << f);
64
  return ScheduleReal (time, Simulator::MakeEvent (f));
65
}
66
67
EventId
68
RealtimeSimulatorExtension::ScheduleRealNow (void (*f) (void))
69
{
70
  NS_LOG_FUNCTION (f);
71
  return ScheduleRealNow (Simulator::MakeEvent (f));
72
}
73
74
} // namespace ns3
(-)9f03fc6f7296 (+498 lines)
Added Link Here 
1
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2
/*
3
 * Copyright (c) 2008 University of Washington
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License version 2 as
7
 * published by the Free Software Foundation;
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software
16
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
 */
18
19
#ifndef REALTIME_SIMULATOR_H
20
#define REALTIME_SIMULATOR_H
21
22
#include "simulator.h"
23
#include "realtime-simulator-impl.h"
24
25
namespace ns3 {
26
27
/**
28
 * \ingroup simulator
29
 *
30
 * \brief Extension class to control the scheduling of real-time simulation 
31
 * events.  Intended to be used by threads driven by "external" system
32
 * events and will schedule events using the current real-time instead of 
33
 * the current simulation time.
34
 */
35
class RealtimeSimulatorExtension 
36
{
37
public:
38
  /**
39
   * Schedule an event to expire at the relative real-time "time"
40
   * is reached.  This can be thought of as scheduling an event
41
   * for the current real-time plus the Time passed as a parameter
42
   *
43
   * When the event expires (when it becomes due to be run), the 
44
   * input method will be invoked on the input object.  
45
   *
46
   * @param time the relative expiration time of the event.
47
   * @param mem_ptr member method pointer to invoke
48
   * @param obj the object on which to invoke the member method
49
   * @returns an id for the scheduled event.
50
   */
51
  template <typename MEM, typename OBJ>
52
  static EventId ScheduleReal (Time const &time, MEM mem_ptr, OBJ obj);
53
54
  /**
55
   * @param time the relative expiration time of the event.
56
   * @param mem_ptr member method pointer to invoke
57
   * @param obj the object on which to invoke the member method
58
   * @param a1 the first argument to pass to the invoked method
59
   * @returns an id for the scheduled event.
60
   */
61
  template <typename MEM, typename OBJ, typename T1>
62
  static EventId ScheduleReal (Time const &time, MEM mem_ptr, OBJ obj, T1 a1);
63
64
  /**
65
   * @param time the relative expiration time of the event.
66
   * @param mem_ptr member method pointer to invoke
67
   * @param obj the object on which to invoke the member method
68
   * @param a1 the first argument to pass to the invoked method
69
   * @param a2 the second argument to pass to the invoked method
70
   * @returns an id for the scheduled event.
71
   */
72
  template <typename MEM, typename OBJ, typename T1, typename T2>
73
  static EventId ScheduleReal (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2);
74
75
  /**
76
   * @param time the relative expiration time of the event.
77
   * @param mem_ptr member method pointer to invoke
78
   * @param obj the object on which to invoke the member method
79
   * @param a1 the first argument to pass to the invoked method
80
   * @param a2 the second argument to pass to the invoked method
81
   * @param a3 the third argument to pass to the invoked method
82
   * @returns an id for the scheduled event.
83
   */
84
  template <typename MEM, typename OBJ, 
85
            typename T1, typename T2, typename T3>
86
  static EventId ScheduleReal (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3);
87
88
  /**
89
   * @param time the relative expiration time of the event.
90
   * @param mem_ptr member method pointer to invoke
91
   * @param obj the object on which to invoke the member method
92
   * @param a1 the first argument to pass to the invoked method
93
   * @param a2 the second argument to pass to the invoked method
94
   * @param a3 the third argument to pass to the invoked method
95
   * @param a4 the fourth argument to pass to the invoked method
96
   * @returns an id for the scheduled event.
97
   */
98
  template <typename MEM, typename OBJ, 
99
            typename T1, typename T2, typename T3, typename T4>
100
  static EventId ScheduleReal (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4);
101
102
  /**
103
   * @param time the relative expiration time of the event.
104
   * @param mem_ptr member method pointer to invoke
105
   * @param obj the object on which to invoke the member method
106
   * @param a1 the first argument to pass to the invoked method
107
   * @param a2 the second argument to pass to the invoked method
108
   * @param a3 the third argument to pass to the invoked method
109
   * @param a4 the fourth argument to pass to the invoked method
110
   * @param a5 the fifth argument to pass to the invoked method
111
   * @returns an id for the scheduled event.
112
   */
113
  template <typename MEM, typename OBJ, 
114
            typename T1, typename T2, typename T3, typename T4, typename T5>
115
  static EventId ScheduleReal (Time const &time, MEM mem_ptr, OBJ obj, 
116
                           T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
117
  /**
118
   * @param time the relative expiration time of the event.
119
   * @param f the function to invoke
120
   * @returns an id for the scheduled event.
121
   */
122
  static EventId ScheduleReal (Time const &time, void (*f) (void));
123
124
  /**
125
   * @param time the relative expiration time of the event.
126
   * @param f the function to invoke
127
   * @param a1 the first argument to pass to the function to invoke
128
   * @returns an id for the scheduled event.
129
   */
130
  template <typename U1, typename T1>
131
  static EventId ScheduleReal (Time const &time, void (*f) (U1), T1 a1);
132
133
  /**
134
   * @param time the relative expiration time of the event.
135
   * @param f the function to invoke
136
   * @param a1 the first argument to pass to the function to invoke
137
   * @param a2 the second argument to pass to the function to invoke
138
   * @returns an id for the scheduled event.
139
   */
140
  template <typename U1, typename U2, typename T1, typename T2>
141
  static EventId ScheduleReal (Time const &time, void (*f) (U1,U2), T1 a1, T2 a2);
142
143
  /**
144
   * @param time the relative expiration time of the event.
145
   * @param f the function to invoke
146
   * @param a1 the first argument to pass to the function to invoke
147
   * @param a2 the second argument to pass to the function to invoke
148
   * @param a3 the third argument to pass to the function to invoke
149
   * @returns an id for the scheduled event.
150
   */
151
  template <typename U1, typename U2, typename U3, typename T1, typename T2, typename T3>
152
  static EventId ScheduleReal (Time const &time, void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3);
153
154
  /**
155
   * @param time the relative expiration time of the event.
156
   * @param f the function to invoke
157
   * @param a1 the first argument to pass to the function to invoke
158
   * @param a2 the second argument to pass to the function to invoke
159
   * @param a3 the third argument to pass to the function to invoke
160
   * @param a4 the fourth argument to pass to the function to invoke
161
   * @returns an id for the scheduled event.
162
   */
163
  template <typename U1, typename U2, typename U3, typename U4, 
164
            typename T1, typename T2, typename T3, typename T4>
165
  static EventId ScheduleReal (Time const &time, void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4);
166
167
  /**
168
   * @param time the relative expiration time of the event.
169
   * @param f the function to invoke
170
   * @param a1 the first argument to pass to the function to invoke
171
   * @param a2 the second argument to pass to the function to invoke
172
   * @param a3 the third argument to pass to the function to invoke
173
   * @param a4 the fourth argument to pass to the function to invoke
174
   * @param a5 the fifth argument to pass to the function to invoke
175
   * @returns an id for the scheduled event.
176
   */
177
  template <typename U1, typename U2, typename U3, typename U4, typename U5,
178
            typename T1, typename T2, typename T3, typename T4, typename T5>
179
  static EventId ScheduleReal (Time const &time, void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
180
181
  /**
182
   * Schedule an event to expire Now. All events scheduled to
183
   * to expire "Now" are scheduled FIFO, after all normal events
184
   * have expired. 
185
   *
186
   * @param mem_ptr member method pointer to invoke
187
   * @param obj the object on which to invoke the member method
188
   */
189
  template <typename MEM, typename OBJ>
190
  static EventId ScheduleRealNow (MEM mem_ptr, OBJ obj);
191
192
  /**
193
   * @param mem_ptr member method pointer to invoke
194
   * @param obj the object on which to invoke the member method
195
   * @param a1 the first argument to pass to the invoked method
196
   */
197
  template <typename MEM, typename OBJ, 
198
            typename T1>
199
  static EventId ScheduleRealNow (MEM mem_ptr, OBJ obj, T1 a1);
200
201
  /**
202
   * @param mem_ptr member method pointer to invoke
203
   * @param obj the object on which to invoke the member method
204
   * @param a1 the first argument to pass to the invoked method
205
   * @param a2 the second argument to pass to the invoked method
206
   */
207
  template <typename MEM, typename OBJ, 
208
            typename T1, typename T2>
209
  static EventId ScheduleRealNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2);
210
211
  /**
212
   * @param mem_ptr member method pointer to invoke
213
   * @param obj the object on which to invoke the member method
214
   * @param a1 the first argument to pass to the invoked method
215
   * @param a2 the second argument to pass to the invoked method
216
   * @param a3 the third argument to pass to the invoked method
217
   */
218
  template <typename MEM, typename OBJ, 
219
            typename T1, typename T2, typename T3>
220
  static EventId ScheduleRealNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3);
221
222
  /**
223
   * @param mem_ptr member method pointer to invoke
224
   * @param obj the object on which to invoke the member method
225
   * @param a1 the first argument to pass to the invoked method
226
   * @param a2 the second argument to pass to the invoked method
227
   * @param a3 the third argument to pass to the invoked method
228
   * @param a4 the fourth argument to pass to the invoked method
229
   */
230
  template <typename MEM, typename OBJ, 
231
            typename T1, typename T2, typename T3, typename T4>
232
  static EventId ScheduleRealNow (MEM mem_ptr, OBJ obj, 
233
                              T1 a1, T2 a2, T3 a3, T4 a4);
234
  /**
235
   * @param mem_ptr member method pointer to invoke
236
   * @param obj the object on which to invoke the member method
237
   * @param a1 the first argument to pass to the invoked method
238
   * @param a2 the second argument to pass to the invoked method
239
   * @param a3 the third argument to pass to the invoked method
240
   * @param a4 the fourth argument to pass to the invoked method
241
   * @param a5 the fifth argument to pass to the invoked method
242
   */
243
  template <typename MEM, typename OBJ, 
244
            typename T1, typename T2, typename T3, typename T4, typename T5>
245
  static EventId ScheduleRealNow (MEM mem_ptr, OBJ obj, 
246
                              T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
247
  /**
248
   * @param f the function to invoke
249
   */
250
  static EventId ScheduleRealNow (void (*f) (void));
251
252
  /**
253
   * @param f the function to invoke
254
   * @param a1 the first argument to pass to the function to invoke
255
   */
256
  template <typename U1,
257
            typename T1>
258
  static EventId ScheduleRealNow (void (*f) (U1), T1 a1);
259
260
  /**
261
   * @param f the function to invoke
262
   * @param a1 the first argument to pass to the function to invoke
263
   * @param a2 the second argument to pass to the function to invoke
264
   */
265
  template <typename U1, typename U2,
266
            typename T1, typename T2>
267
  static EventId ScheduleRealNow (void (*f) (U1,U2), T1 a1, T2 a2);
268
269
  /**
270
   * @param f the function to invoke
271
   * @param a1 the first argument to pass to the function to invoke
272
   * @param a2 the second argument to pass to the function to invoke
273
   * @param a3 the third argument to pass to the function to invoke
274
   */
275
  template <typename U1, typename U2, typename U3,
276
            typename T1, typename T2, typename T3>
277
  static EventId ScheduleRealNow (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3);
278
279
  /**
280
   * @param f the function to invoke
281
   * @param a1 the first argument to pass to the function to invoke
282
   * @param a2 the second argument to pass to the function to invoke
283
   * @param a3 the third argument to pass to the function to invoke
284
   * @param a4 the fourth argument to pass to the function to invoke
285
   */
286
  template <typename U1, typename U2, typename U3, typename U4,
287
            typename T1, typename T2, typename T3, typename T4>
288
  static EventId ScheduleRealNow (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4);
289
290
  /**
291
   * @param f the function to invoke
292
   * @param a1 the first argument to pass to the function to invoke
293
   * @param a2 the second argument to pass to the function to invoke
294
   * @param a3 the third argument to pass to the function to invoke
295
   * @param a4 the fourth argument to pass to the function to invoke
296
   * @param a5 the fifth argument to pass to the function to invoke
297
   */
298
  template <typename U1, typename U2, typename U3, typename U4, typename U5,
299
            typename T1, typename T2, typename T3, typename T4, typename T5>
300
  static EventId ScheduleRealNow (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
301
302
  /**
303
   * Return the "current normalized real-time".
304
   */
305
  static Time RealNow (void);
306
307
  /**
308
   * \param time delay until the event expires
309
   * \param event the event to schedule
310
   * \returns a unique identifier for the newly-scheduled event.
311
   *
312
   * This method will be typically used by language bindings
313
   * to delegate events to their own subclass of the EventImpl base class.
314
   */
315
  static EventId ScheduleReal (Time const &time, const Ptr<EventImpl> &event);  
316
317
  /**
318
   * \param event the event to schedule
319
   * \returns a unique identifier for the newly-scheduled event.
320
   *
321
   * This method will be typically used by language bindings
322
   * to delegate events to their own subclass of the EventImpl base class.
323
   */
324
  static EventId ScheduleRealNow (const Ptr<EventImpl> &event);
325
private:
326
  RealtimeSimulatorExtension ();
327
  ~RealtimeSimulatorExtension ();
328
329
  static RealtimeSimulatorImpl *GetRealtimeImpl (void);
330
};
331
332
template <typename MEM, typename OBJ>
333
EventId RealtimeSimulatorExtension::ScheduleReal (Time const &time, MEM mem_ptr, OBJ obj) 
334
{
335
  return ScheduleReal (time, Simulator::MakeEvent (mem_ptr, obj));
336
}
337
338
template <typename MEM, typename OBJ,
339
          typename T1>
340
EventId RealtimeSimulatorExtension::ScheduleReal (Time const &time, MEM mem_ptr, OBJ obj, T1 a1) 
341
{
342
  return ScheduleReal (time, Simulator::MakeEvent (mem_ptr, obj, a1));
343
}
344
345
template <typename MEM, typename OBJ, 
346
          typename T1, typename T2>
347
EventId RealtimeSimulatorExtension::ScheduleReal (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2)
348
{
349
  return ScheduleReal (time, Simulator::MakeEvent (mem_ptr, obj, a1, a2));
350
}
351
352
template <typename MEM, typename OBJ,
353
          typename T1, typename T2, typename T3>
354
EventId RealtimeSimulatorExtension::ScheduleReal (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3) 
355
{
356
  return ScheduleReal (time, Simulator::MakeEvent (mem_ptr, obj, a1, a2, a3));
357
}
358
359
template <typename MEM, typename OBJ, 
360
          typename T1, typename T2, typename T3, typename T4>
361
EventId RealtimeSimulatorExtension::ScheduleReal (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) 
362
{
363
  return ScheduleReal (time, Simulator::MakeEvent (mem_ptr, obj, a1, a2, a3, a4));
364
}
365
366
template <typename MEM, typename OBJ, 
367
          typename T1, typename T2, typename T3, typename T4, typename T5>
368
EventId RealtimeSimulatorExtension::ScheduleReal (Time const &time, MEM mem_ptr, OBJ obj, 
369
                             T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
370
{
371
  return ScheduleReal (time, Simulator::MakeEvent (mem_ptr, obj, a1, a2, a3, a4, a5));
372
}
373
374
template <typename U1, typename T1>
375
EventId RealtimeSimulatorExtension::ScheduleReal (Time const &time, void (*f) (U1), T1 a1) 
376
{
377
  return ScheduleReal (time, Simulator::MakeEvent (f, a1));
378
}
379
380
template <typename U1, typename U2, 
381
          typename T1, typename T2>
382
EventId RealtimeSimulatorExtension::ScheduleReal (Time const &time, void (*f) (U1,U2), T1 a1, T2 a2) 
383
{
384
  return ScheduleReal (time, Simulator::MakeEvent (f, a1, a2));
385
}
386
387
template <typename U1, typename U2, typename U3,
388
          typename T1, typename T2, typename T3>
389
EventId RealtimeSimulatorExtension::ScheduleReal (Time const &time, void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3)
390
{
391
  return ScheduleReal (time, Simulator::MakeEvent (f, a1, a2, a3));
392
}
393
394
template <typename U1, typename U2, typename U3, typename U4,
395
          typename T1, typename T2, typename T3, typename T4>
396
EventId RealtimeSimulatorExtension::ScheduleReal (Time const &time, void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4) 
397
{
398
  return ScheduleReal (time, Simulator::MakeEvent (f, a1, a2, a3, a4));
399
}
400
401
template <typename U1, typename U2, typename U3, typename U4, typename U5,
402
          typename T1, typename T2, typename T3, typename T4, typename T5>
403
EventId RealtimeSimulatorExtension::ScheduleReal (Time const &time, void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
404
{
405
  return ScheduleReal (time, Simulator::MakeEvent (f, a1, a2, a3, a4, a5));
406
}
407
408
template <typename MEM, typename OBJ>
409
EventId
410
RealtimeSimulatorExtension::ScheduleRealNow (MEM mem_ptr, OBJ obj) 
411
{
412
  return ScheduleRealNow (Simulator::MakeEvent (mem_ptr, obj));
413
}
414
415
template <typename MEM, typename OBJ, 
416
          typename T1>
417
EventId
418
RealtimeSimulatorExtension::ScheduleRealNow (MEM mem_ptr, OBJ obj, T1 a1) 
419
{
420
  return ScheduleRealNow (Simulator::MakeEvent (mem_ptr, obj, a1));
421
}
422
423
template <typename MEM, typename OBJ, 
424
          typename T1, typename T2>
425
EventId
426
RealtimeSimulatorExtension::ScheduleRealNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2) 
427
{
428
  return ScheduleRealNow (Simulator::MakeEvent (mem_ptr, obj, a1, a2));
429
}
430
431
template <typename MEM, typename OBJ, 
432
          typename T1, typename T2, typename T3>
433
EventId
434
RealtimeSimulatorExtension::ScheduleRealNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3) 
435
{
436
  return ScheduleRealNow (Simulator::MakeEvent (mem_ptr, obj, a1, a2, a3));
437
}
438
439
template <typename MEM, typename OBJ, 
440
          typename T1, typename T2, typename T3, typename T4>
441
EventId
442
RealtimeSimulatorExtension::ScheduleRealNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) 
443
{
444
  return ScheduleRealNow (Simulator::MakeEvent (mem_ptr, obj, a1, a2, a3, a4));
445
}
446
447
template <typename MEM, typename OBJ, 
448
          typename T1, typename T2, typename T3, typename T4, typename T5>
449
EventId
450
RealtimeSimulatorExtension::ScheduleRealNow (MEM mem_ptr, OBJ obj, 
451
                        T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
452
{
453
  return ScheduleRealNow (Simulator::MakeEvent (mem_ptr, obj, a1, a2, a3, a4, a5));
454
}
455
456
template <typename U1,
457
          typename T1>
458
EventId
459
RealtimeSimulatorExtension::ScheduleRealNow (void (*f) (U1), T1 a1) 
460
{
461
  return ScheduleRealNow (Simulator::MakeEvent (f, a1));
462
}
463
464
template <typename U1, typename U2,
465
          typename T1, typename T2>
466
EventId
467
RealtimeSimulatorExtension::ScheduleRealNow (void (*f) (U1,U2), T1 a1, T2 a2) 
468
{
469
  return ScheduleRealNow (Simulator::MakeEvent (f, a1, a2));
470
}
471
472
template <typename U1, typename U2, typename U3,
473
          typename T1, typename T2, typename T3>
474
EventId
475
RealtimeSimulatorExtension::ScheduleRealNow (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3)
476
{
477
  return ScheduleRealNow (Simulator::MakeEvent (f, a1, a2, a3));
478
}
479
480
template <typename U1, typename U2, typename U3, typename U4,
481
          typename T1, typename T2, typename T3, typename T4>
482
EventId
483
RealtimeSimulatorExtension::ScheduleRealNow (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4) 
484
{
485
  return ScheduleRealNow (Simulator::MakeEvent (f, a1, a2, a3, a4));
486
}
487
488
template <typename U1, typename U2, typename U3, typename U4, typename U5,
489
          typename T1, typename T2, typename T3, typename T4, typename T5>
490
EventId
491
RealtimeSimulatorExtension::ScheduleRealNow (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
492
{
493
  return ScheduleRealNow (Simulator::MakeEvent (f, a1, a2, a3, a4, a5));
494
}
495
496
}; // namespace ns3
497
498
#endif /* REALTIME_SIMULATOR_H */
(-)a/src/simulator/simulator.h (+2 lines)
 Lines 56-61   class SimulatorImpl; Link Here 
56
 */
56
 */
57
class Simulator 
57
class Simulator 
58
{
58
{
59
  friend class RealtimeSimulatorExtension;
60
59
public:
61
public:
60
  /**
62
  /**
61
   * \param impl a new simulator implementation
63
   * \param impl a new simulator implementation
(-)a/src/simulator/wscript (+2 lines)
 Lines 61-66   def build(bld): Link Here 
61
        'heap-scheduler.cc',
61
        'heap-scheduler.cc',
62
        'event-impl.cc',
62
        'event-impl.cc',
63
        'simulator.cc',
63
        'simulator.cc',
64
        'realtime-simulator.cc',
64
        'default-simulator-impl.cc',
65
        'default-simulator-impl.cc',
65
        'timer.cc',
66
        'timer.cc',
66
        'watchdog.cc',
67
        'watchdog.cc',
 Lines 75-80   def build(bld): Link Here 
75
        'event-id.h',
76
        'event-id.h',
76
        'event-impl.h',
77
        'event-impl.h',
77
        'simulator.h',
78
        'simulator.h',
79
        'realtime-simulator.h',
78
        'simulator-impl.h',
80
        'simulator-impl.h',
79
        'default-simulator-impl.h',
81
        'default-simulator-impl.h',
80
        'scheduler.h',
82
        'scheduler.h',
(-)a/samples/main-test-sync.cc (-5 / +48 lines)
 Lines 1-9    Link Here 
1
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
1
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2
2
3
#include "ns3/simulator.h"
3
#include "ns3/simulator.h"
4
#include "ns3/realtime-simulator.h"
4
#include "ns3/nstime.h"
5
#include "ns3/nstime.h"
5
#include "ns3/log.h"
6
#include "ns3/log.h"
6
#include "ns3/wall-clock-synchronizer.h"
7
#include "ns3/system-thread.h"
7
#include "ns3/system-thread.h"
8
#include "ns3/string.h"
8
#include "ns3/string.h"
9
#include "ns3/config.h"
9
#include "ns3/config.h"
 Lines 48-58   public: Link Here 
48
  FakeNetDevice ();
48
  FakeNetDevice ();
49
  void Doit1 (void);
49
  void Doit1 (void);
50
  void Doit2 (void);
50
  void Doit2 (void);
51
  void Doit3 (void);
52
  void Doit4 (void);
51
};
53
};
52
54
53
FakeNetDevice::FakeNetDevice ()
55
FakeNetDevice::FakeNetDevice ()
54
{
56
{
55
  NS_LOG_FUNCTION_NOARGS ();
57
  NS_LOG_FUNCTION_NOARGS ();
58
}
59
60
  void
61
FakeNetDevice::Doit1 (void)
62
{
63
  NS_LOG_FUNCTION_NOARGS ();
64
  sleep (1);
65
  for (uint32_t i = 0.001; i < 10000; ++i)
66
    {
67
      // 
68
      // Exercise the relative now path
69
      //
70
      Simulator::ScheduleNow (&inserted_function);
71
      usleep (1000);
72
    }
56
}
73
}
57
74
58
  void
75
  void
 Lines 71-86   FakeNetDevice::Doit2 (void) Link Here 
71
}
88
}
72
89
73
  void
90
  void
74
FakeNetDevice::Doit1 (void)
91
FakeNetDevice::Doit3 (void)
75
{
92
{
76
  NS_LOG_FUNCTION_NOARGS ();
93
  NS_LOG_FUNCTION_NOARGS ();
77
  sleep (1);
94
  sleep (1);
78
  for (uint32_t i = 0.001; i < 10000; ++i)
95
  for (uint32_t i = 0.001; i < 10000; ++i)
79
    {
96
    {
80
      // 
81
      // Exercise the ScheduleNow path
82
      //
97
      //
83
      Simulator::ScheduleNow (&inserted_function);
98
      // Exercise the realtime relative now path
99
      //
100
      RealtimeSimulatorExtension::ScheduleRealNow (&inserted_function);
101
      usleep (1000);
102
    }
103
}
104
105
  void
106
FakeNetDevice::Doit4 (void)
107
{
108
  NS_LOG_FUNCTION_NOARGS ();
109
  sleep (1);
110
  for (uint32_t i = 0.001; i < 10000; ++i)
111
    {
112
      //
113
      // Exercise the realtime relative schedule path
114
      //
115
      RealtimeSimulatorExtension::ScheduleReal (Seconds (0), &inserted_function);
84
      usleep (1000);
116
      usleep (1000);
85
    }
117
    }
86
}
118
}
 Lines 109-122   test (void) Link Here 
109
  Ptr<SystemThread> st1 = Create<SystemThread> (
141
  Ptr<SystemThread> st1 = Create<SystemThread> (
110
    MakeCallback (&FakeNetDevice::Doit1, &fnd));
142
    MakeCallback (&FakeNetDevice::Doit1, &fnd));
111
  st1->Start ();
143
  st1->Start ();
144
112
  Ptr<SystemThread> st2 = Create<SystemThread> (
145
  Ptr<SystemThread> st2 = Create<SystemThread> (
113
    MakeCallback (&FakeNetDevice::Doit2, &fnd));
146
    MakeCallback (&FakeNetDevice::Doit2, &fnd));
114
  st2->Start ();
147
  st2->Start ();
148
149
  Ptr<SystemThread> st3 = Create<SystemThread> (
150
    MakeCallback (&FakeNetDevice::Doit3, &fnd));
151
  st3->Start ();
152
153
  Ptr<SystemThread> st4 = Create<SystemThread> (
154
    MakeCallback (&FakeNetDevice::Doit4, &fnd));
155
  st4->Start ();
115
156
116
  Simulator::Stop (Seconds (15.0));
157
  Simulator::Stop (Seconds (15.0));
117
  Simulator::Run ();
158
  Simulator::Run ();
118
  st1->Join ();
159
  st1->Join ();
119
  st2->Join ();
160
  st2->Join ();
161
  st3->Join ();
162
  st4->Join ();
120
  Simulator::Destroy ();
163
  Simulator::Destroy ();
121
}
164
}
122
165
(-)a/src/simulator/realtime-simulator-impl.cc (-30 / +52 lines)
 Lines 548-582   RealtimeSimulatorImpl::Stop (Time const Link Here 
548
//
548
//
549
// Schedule an event for a _relative_ time in the future.
549
// Schedule an event for a _relative_ time in the future.
550
//
550
//
551
// A little side-note on events and multthreading:
552
//
553
// This is a little tricky.  We get a Ptr<EventImpl> passed down to us in some
554
// thread context.  This Ptr<EventImpl> is not yet shared in any way.  It is 
555
// possible however that the calling context is not the context of the main 
556
// scheduler thread (e.g. it is in the context of a separate device thread).  
557
// It would be bad (TM) if we naively wrapped the EventImpl up in an EventId 
558
// that would be accessible from multiple threads without considering thread 
559
// safety.
560
//
561
// It's clear that we cannot have a situation where the EventImpl is "owned" by
562
// multiple threads.  The calling thread is free to hold the EventId as long as
563
// it wants and manage the reference counts to the underlying EventImpl all it
564
// wants.  The scheduler is free to do the same; and will eventually release
565
// the reference in the context of thread running ProcessOneEvent().  It is 
566
// "a bad thing" (TM) if these two threads decide to release the underlying
567
// EventImpl "at the same time" since the result is sure to be multiple frees,
568
// memory leaks or bus errors.
569
//
570
// The answer is to make the reference counting of the EventImpl thread safe; 
571
// which we do.  We don't want to force the event implementation to carry around
572
// a mutex, so we "lend" it one using a RealtimeEventLock object (m_eventLock)
573
// in the constructor of the event and take it back in the destructor.  See the
574
// event code for details.
575
//
551
EventId
576
EventId
552
RealtimeSimulatorImpl::Schedule (Time const &time, const Ptr<EventImpl> &event)
577
RealtimeSimulatorImpl::Schedule (Time const &time, const Ptr<EventImpl> &event)
553
{
578
{
554
  NS_LOG_FUNCTION (time << event);
579
  NS_LOG_FUNCTION (time << event);
555
580
556
  //
557
  // This is a little tricky.  We get a Ptr<EventImpl> passed down to us in some
558
  // thread context.  This Ptr<EventImpl> is not yet shared in any way.  It is 
559
  // possible however that the calling context is not the context of the main 
560
  // scheduler thread (e.g. it is in the context of a separate device thread).  
561
  // It would be bad (TM) if we naively wrapped the EventImpl up in an EventId 
562
  // that would be accessible from multiple threads without considering thread 
563
  // safety.
564
  //
565
  // It's clear that we cannot have a situation where the EventImpl is "owned" by
566
  // multiple threads.  The calling thread is free to hold the EventId as long as
567
  // it wants and manage the reference counts to the underlying EventImpl all it
568
  // wants.  The scheduler is free to do the same; and will eventually release
569
  // the reference in the context of thread running ProcessOneEvent().  It is 
570
  // "a bad thing" (TM) if these two threads decide to release the underlying
571
  // EventImpl "at the same time" since the result is sure to be multiple frees,
572
  // memory leaks or bus errors.
573
  //
574
  // The answer is to make the reference counting of the EventImpl thread safe; 
575
  // which we do.  We don't want to force the event implementation to carry around
576
  // a mutex, so we "lend" it one using a RealtimeEventLock object (m_eventLock)
577
  // in the constructor of the event and take it back in the destructor.  See the
578
  // event code for details.
579
  //
580
  EventId id;
581
  EventId id;
581
  {
582
  {
582
    CriticalSection cs (m_mutex);
583
    CriticalSection cs (m_mutex);
 Lines 631-657   RealtimeSimulatorImpl::ScheduleReal (Tim Link Here 
631
RealtimeSimulatorImpl::ScheduleReal (Time const &time, const Ptr<EventImpl> &event)
632
RealtimeSimulatorImpl::ScheduleReal (Time const &time, const Ptr<EventImpl> &event)
632
{
633
{
633
  NS_LOG_FUNCTION (time << event);
634
  NS_LOG_FUNCTION (time << event);
634
  NS_ASSERT (false);
635
635
  EventId id;
636
  EventId id;
637
  {
638
    CriticalSection cs (m_mutex);
639
640
    uint64_t ts = m_synchronizer->GetCurrentRealtime () + time.GetTimeStep ();
641
    NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleReal(): schedule for time < m_currentTs");
642
    id = EventId (event, ts, m_uid);
643
    m_uid++;
644
    ++m_unscheduledEvents;
645
    m_events->Insert (id);
646
    m_synchronizer->Signal ();
647
  }
648
636
  return id;
649
  return id;
637
}
650
}
638
651
639
EventId
652
EventId
640
RealtimeSimulatorImpl::ScheduleRealNow (const Ptr<EventImpl> &event)
653
RealtimeSimulatorImpl::ScheduleRealNow (const Ptr<EventImpl> &event)
641
{
654
{
642
  NS_LOG_FUNCTION (event);
655
  NS_LOG_FUNCTION_NOARGS ();
643
  NS_ASSERT (false);
644
  EventId id;
656
  EventId id;
657
  {
658
    CriticalSection cs (m_mutex);
659
660
    uint64_t ts = m_synchronizer->GetCurrentRealtime ();
661
    NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleRealNow(): schedule for time < m_currentTs");
662
    id = EventId (event, ts, m_uid);
663
    m_uid++;
664
    ++m_unscheduledEvents;
665
    m_events->Insert (id);
666
    m_synchronizer->Signal ();
667
  }
668
645
  return id;
669
  return id;
646
}
670
}
647
671
648
Time
672
Time
649
RealtimeSimulatorImpl::RealNow (void) const
673
RealtimeSimulatorImpl::RealNow (void) const
650
{
674
{
651
  NS_ASSERT (false);
675
  return TimeStep (m_synchronizer->GetCurrentRealtime ());
652
  return TimeStep (m_currentTs);
653
}
676
}
654
655
677
656
EventId
678
EventId
657
RealtimeSimulatorImpl::ScheduleDestroy (const Ptr<EventImpl> &event)
679
RealtimeSimulatorImpl::ScheduleDestroy (const Ptr<EventImpl> &event)
(-)a/samples/main-test-sync.cc (-2 / +2 lines)
 Lines 126-134   test (void) Link Here 
126
  FakeNetDevice fnd;
126
  FakeNetDevice fnd;
127
127
128
  // 
128
  // 
129
  // Make sure ScheduleNow works when the system isn't running
129
  // Make sure ScheduleRealNow works when the system isn't running
130
  //
130
  //
131
  Simulator::ScheduleNow(&first_function);
131
  RealtimeSimulatorExtension::ScheduleRealNow(&first_function);
132
132
133
  // 
133
  // 
134
  // drive the progression of m_currentTs at a ten millisecond rate
134
  // drive the progression of m_currentTs at a ten millisecond rate
(-)a/src/simulator/realtime-simulator-impl.cc (-1 / +5 lines)
 Lines 657-663   RealtimeSimulatorImpl::ScheduleRealNow ( Link Here 
657
  {
657
  {
658
    CriticalSection cs (m_mutex);
658
    CriticalSection cs (m_mutex);
659
659
660
    uint64_t ts = m_synchronizer->GetCurrentRealtime ();
660
    //
661
    // If the simulator is running, we're pacing and have a meaningful 
662
    // realtime clock.  If we're not, then m_currentTs is were we stopped.
663
    // 
664
    uint64_t ts = m_running ? m_synchronizer->GetCurrentRealtime () : m_currentTs;
661
    NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleRealNow(): schedule for time < m_currentTs");
665
    NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleRealNow(): schedule for time < m_currentTs");
662
    id = EventId (event, ts, m_uid);
666
    id = EventId (event, ts, m_uid);
663
    m_uid++;
667
    m_uid++;

Return to bug 376