ns-3 Direct Code Execution
Home
Tutorials ▼
Docs ▼
Wiki
Manual
Develop ▼
API
Bugs
API
Main Page
Related Pages
Namespaces
Classes
Files
File List
File Members
All
Classes
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Friends
Macros
Pages
task-manager.cc
Go to the documentation of this file.
1
#include "
task-manager.h
"
2
#include "
fiber-manager.h
"
3
#include "
ucontext-fiber-manager.h
"
4
#include "
pthread-fiber-manager.h
"
5
#include "
task-scheduler.h
"
6
#include "ns3/log.h"
7
#include "ns3/uinteger.h"
8
#include "ns3/enum.h"
9
#include "ns3/simulator.h"
10
#include "ns3/node.h"
11
#include "ns3/node-list.h"
12
#include "
dce-manager.h
"
13
#include "
dce-stdio.h
"
14
#include "
process.h
"
15
#include "
utils.h
"
16
#include "
process-delay-model.h
"
17
#include "
dce-cxa.h
"
18
19
namespace
ns3 {
20
21
NS_LOG_COMPONENT_DEFINE
(
"TaskManager"
);
22
NS_OBJECT_ENSURE_REGISTERED
(TaskManager);
23
24
25
26
bool
27
Task::IsActive
(
void
)
const
28
{
29
return
m_state
==
Task::ACTIVE
;
30
}
31
bool
32
Task::IsRunning
(
void
)
const
33
{
34
return
m_state
==
Task::RUNNING
;
35
}
36
bool
37
Task::IsBlocked
(
void
)
const
38
{
39
return
m_state
==
Task::BLOCKED
;
40
}
41
bool
42
Task::IsDead
(
void
)
const
43
{
44
return
m_state
==
Task::DEAD
;
45
}
46
void
47
Task::SetExtraContext
(
void
*ctx)
48
{
49
m_extraContext
= ctx;
50
}
51
void
52
Task::SetContext
(
void
*ctx)
53
{
54
m_context
= ctx;
55
}
56
void
*
57
Task::GetExtraContext
(
void
)
const
58
{
59
return
m_extraContext
;
60
}
61
void
*
62
Task::GetContext
(
void
)
const
63
{
64
return
m_context
;
65
}
66
67
void
68
Task::SetSwitchNotifier
(
void
(*fn)(
enum
SwitchType
,
void
*),
void
*context)
69
{
70
m_switchNotifier
= fn;
71
m_switchNotifierContext
= context;
72
}
73
74
Task::~Task
()
75
{
76
}
77
78
79
TypeId
80
TaskManager::GetTypeId
(
void
)
81
{
82
static
TypeId tid = TypeId (
"ns3::TaskManager"
)
83
.SetParent<Object> ()
84
.AddConstructor<TaskManager> ()
85
.AddAttribute (
"DefaultStackSize"
,
86
"The default size of the stack of every task created by this manager."
,
87
UintegerValue (8192),
88
MakeUintegerAccessor (&
TaskManager::m_defaultStackSize
),
89
MakeUintegerChecker<uint32_t> (4096))
90
.AddAttribute (
"FiberManagerType"
,
91
"The type of FiberManager implementation to use to allocate, "
92
"deallocate and switch among fibers."
,
93
TypeId::ATTR_CONSTRUCT,
94
EnumValue (
PTHREAD_FIBER_MANAGER
),
95
MakeEnumAccessor (&
TaskManager::SetFiberManagerType
),
96
MakeEnumChecker (
PTHREAD_FIBER_MANAGER
,
"PthreadFiberManager"
,
97
UCONTEXT_FIBER_MANAGER
,
"UcontextFiberManager"
))
98
;
99
return
tid;
100
}
101
102
TaskManager::TaskManager
()
103
: m_current (0),
104
m_scheduler (0),
105
m_fiberManager (0),
106
m_reSchedule (0),
107
m_disposing (0),
108
m_todoOnMain (0),
109
m_noSignal (0),
110
m_hightask (0)
111
{
112
NS_LOG_FUNCTION (
this
);
113
}
114
TaskManager::~TaskManager
()
115
{
116
NS_LOG_FUNCTION (
this
);
117
GarbageCollectDeadTasks
();
118
m_fiberManager
->
Delete
(
m_mainFiber
);
119
delete
m_fiberManager
;
120
121
m_mainFiber
= 0;
122
m_fiberManager
= 0;
123
m_scheduler
= 0;
124
}
125
126
void
TaskManager::DoDispose
(
void
)
127
{
128
if
(
m_disposing
)
129
{
130
return
;
131
}
132
m_disposing
= 1;
133
134
// Flush every FILEs in every processes.
135
Ptr<DceManager> dceManager = this->GetObject<DceManager> ();
136
137
if
(0 != dceManager)
138
{
139
std::map<uint16_t, Process *> procs = dceManager->GetProcs ();
140
std::map<uint16_t, Process *>::iterator it;
141
142
for
(it = procs.begin (); it != procs.end (); it++)
143
{
144
if
(0 != it->second)
145
{
146
gDisposingThreadContext
= it->second->threads.back ();
147
148
// call atexit handler for linux kernel
149
dce___cxa_finalize
(0);
150
if
(0 !=
gDisposingThreadContext
)
151
{
152
Process
*p = it->second;
153
for
(std::vector<FILE *>::const_iterator i = p->
openStreams
.begin ();
154
i != p->
openStreams
.end (); ++i)
155
{
156
fflush (*i);
157
}
158
}
159
gDisposingThreadContext
= 0;
160
}
161
}
162
}
163
Object::DoDispose
();
164
}
165
166
void
167
TaskManager::GarbageCollectDeadTasks
(
void
)
168
{
169
NS_LOG_FUNCTION (
this
);
170
while
(!
m_deadTasks
.empty ())
171
{
172
Task
*task =
m_deadTasks
.front ();
173
m_deadTasks
.pop_front ();
174
NS_LOG_DEBUG (
"delete "
<< task);
175
if
(task->
m_fiber
)
176
{
177
m_fiberManager
->
Delete
(task->
m_fiber
);
178
}
179
task->
m_waitTimer
.Cancel ();
180
task->
m_fiber
= 0;
181
delete
task;
182
}
183
m_deadTasks
.clear ();
184
}
185
186
187
void
188
TaskManager::SetScheduler
(Ptr<TaskScheduler> scheduler)
189
{
190
m_scheduler
= scheduler;
191
}
192
193
void
194
TaskManager::SetDelayModel
(Ptr<ProcessDelayModel> model)
195
{
196
m_delayModel
= model;
197
}
198
199
Task
*
200
TaskManager::Start
(
void
(*fn)(
void
*),
void
*context)
201
{
202
return
Start
(fn, context,
m_defaultStackSize
);
203
}
204
// At every switch of context this method is called and it runs the signal handlers of pending signals.
205
static
void
SwitchNotifEatSignal
(
void
)
206
{
207
TaskManager
*manager =
TaskManager::Current
();
208
if
(manager == 0)
209
{
210
return
;
211
}
212
if
(!manager->
CurrentTask
())
213
{
214
return
;
215
}
216
Thread
*current =
Current
();
217
if
(0 == current)
218
{
219
return
;
220
}
221
if
(manager->
GetNoSignal
())
222
{
223
return
;
224
}
225
UtilsDoSignal
() ;
226
}
227
Task *
228
TaskManager::Start
(
void
(*fn)(
void
*),
void
*context, uint32_t stackSize)
229
{
230
NS_LOG_FUNCTION (
this
<< fn << context << stackSize);
231
Task
*task =
new
Task
();
232
struct
StartTaskContext
*ctx =
new
StartTaskContext
();
233
ctx->
function
= fn;
234
ctx->
context
= context;
235
task->
m_fiber
=
m_fiberManager
->
Create
(&
TaskManager::Trampoline
, ctx, stackSize);
236
NS_LOG_DEBUG (
"create "
<< task <<
" fiber="
<< task->
m_fiber
);
237
task->
m_state
=
Task::BLOCKED
;
// must call Wakeup on task later.
238
task->
m_context
= 0;
239
task->
m_extraContext
= 0;
240
task->
m_switchNotifier
= 0;
241
task->
m_switchNotifierContext
= 0;
242
Wakeup
(task);
243
return
task;
244
}
245
246
Task
*
247
TaskManager::Clone
(
Task
*task)
248
{
249
Task
*clone =
new
Task
();
250
clone->
m_state
=
Task::BLOCKED
;
// must call Wakeup on task later.
251
clone->
m_context
= 0;
252
clone->
m_extraContext
= 0;
253
clone->
m_switchNotifier
= 0;
254
clone->
m_switchNotifierContext
= 0;
255
struct
Fiber
*cloneFiber =
m_fiberManager
->
Clone
(task->
m_fiber
);
256
NS_LOG_DEBUG (
"clone "
<< clone <<
" fiber="
<< cloneFiber);
257
if
(cloneFiber != 0)
258
{
259
// parent.
260
clone->
m_fiber
= cloneFiber;
261
Wakeup
(clone);
262
return
clone;
263
}
264
return
0;
265
}
266
267
void
268
TaskManager::Trampoline
(
void
*context)
269
{
270
struct
StartTaskContext
*ctx = (
struct
StartTaskContext
*)context;
271
void (*fn)(
void
*) = ctx->
function
;
272
void
*fn_context = ctx->
context
;
273
delete
ctx;
274
fn (fn_context);
275
NS_FATAL_ERROR (
"The user function must not return."
);
276
}
277
278
void
279
TaskManager::Stop
(
Task
*task)
280
{
281
NS_LOG_FUNCTION (
this
<< task);
282
if
(
m_current
== task)
283
{
284
// we ignore Stop on self.
285
return
;
286
}
287
288
// we can delete the task immediately.
289
NS_LOG_DEBUG (
"delete "
<< task <<
" fiber="
<< task->
m_fiber
);
290
m_scheduler
->Dequeue (task);
291
if
(task->
m_fiber
)
292
{
293
m_fiberManager
->
Delete
(task->
m_fiber
);
294
}
295
task->
m_state
=
Task::DEAD
;
296
task->
m_waitTimer
.Cancel ();
297
task->
m_fiber
= 0;
298
delete
task;
299
}
300
301
void
302
TaskManager::Wakeup
(
Task
*task)
303
{
304
NS_LOG_FUNCTION (
this
<< task << task->
m_state
);
305
if
(task->
m_state
==
Task::ACTIVE
306
|| task->
m_state
==
Task::RUNNING
)
307
{
308
return
;
309
}
310
task->
m_state
=
Task::ACTIVE
;
311
m_scheduler
->Enqueue (task);
312
if
((0 ==
m_current
) && (!
m_nextSchedule
.IsRunning ()))
313
{
314
m_nextSchedule
= Simulator::ScheduleNow (&
TaskManager::Schedule
,
this
);
315
}
316
}
317
318
void
319
TaskManager::Sleep
(
void
)
320
{
321
NS_LOG_FUNCTION (
this
<<
m_current
);
322
NS_ASSERT (
m_current
!= 0);
323
NS_ASSERT (
m_current
->
m_state
==
Task::RUNNING
);
324
Task
*current =
m_current
;
325
current->
m_state
=
Task::BLOCKED
;
326
Schedule
();
327
}
328
329
Time
330
TaskManager::Sleep
(Time timeout)
331
{
332
NS_LOG_FUNCTION (
this
<<
m_current
);
333
NS_ASSERT (
m_current
!= 0);
334
NS_ASSERT (
m_current
->
m_state
==
Task::RUNNING
);
335
Time expectedEnd = Simulator::Now () + timeout;
336
Task
*current =
m_current
;
337
current->
m_state
=
Task::BLOCKED
;
338
if
(!timeout.IsZero ())
339
{
340
m_waitQueue
.push_back (
Sleeper
(current,timeout));
341
}
342
Schedule
();
343
current->
m_waitTimer
.Cancel ();
344
if
(!timeout.IsZero ()
345
&& Simulator::Now () <= expectedEnd)
346
{
347
return
expectedEnd - Simulator::Now ();
348
}
349
return
Seconds (0.0);
350
}
351
void
352
TaskManager::Yield
(
void
)
353
{
354
NS_LOG_FUNCTION (
this
<<
m_current
);
355
NS_ASSERT (
m_current
!= 0);
356
NS_ASSERT (
m_current
->
m_state
==
Task::RUNNING
);
357
// re-queue to make sure it will be handled.
358
m_current
->
m_state
=
Task::ACTIVE
;
359
m_scheduler
->Enqueue (
m_current
);
360
Schedule
();
361
}
362
void
363
TaskManager::Exit
(
void
)
364
{
365
NS_LOG_FUNCTION (
this
<<
m_current
);
366
NS_ASSERT (
m_current
!= 0);
367
NS_ASSERT (
m_current
->
m_state
==
Task::RUNNING
);
368
Task
*current =
m_current
;
369
current->
m_state
=
Task::DEAD
;
370
current->
m_waitTimer
.Cancel ();
371
m_deadTasks
.push_back (current);
372
Schedule
();
373
}
374
375
void
376
TaskManager::EnterHiTask
(
Task
*task)
377
{
378
NS_LOG_FUNCTION (
this
<< task <<
m_hightask
);
379
NS_ASSERT (
m_hightask
== NULL);
380
m_hightask
= task;
381
}
382
void
383
TaskManager::LeaveHiTask
(
Task
*task)
384
{
385
NS_LOG_FUNCTION (
this
<< task <<
m_hightask
);
386
NS_ASSERT (
m_hightask
== task);
387
m_hightask
= NULL;
388
}
389
390
Task
*
391
TaskManager::CurrentTask
(
void
)
392
{
393
if
(
m_hightask
)
394
{
395
return
m_hightask
;
396
}
397
return
m_current
;
398
}
399
TaskManager
*
400
TaskManager::Current
(
void
)
401
{
402
uint32_t nodeId = Simulator::GetContext ();
403
if
(nodeId == 0xffffffff)
404
{
405
return
0;
406
}
407
Ptr<Node> node = NodeList::GetNode (nodeId);
408
Ptr<TaskManager> manager = node->GetObject<
TaskManager
> ();
409
return
PeekPointer (manager);
410
}
411
412
void
413
TaskManager::Schedule
(
void
)
414
{
415
NS_LOG_FUNCTION (
this
);
416
if
(
m_current
== 0)
417
{
418
// we have nothing to schedule from
419
struct
Task
*next =
m_scheduler
->PeekNext ();
420
if
(next != 0)
421
{
422
// and now, we have something to schedule to.
423
NS_LOG_DEBUG (
"Leaving main, entering "
<< next);
424
m_scheduler
->DequeueNext ();
425
m_current
= next;
426
NS_ASSERT (next->
m_state
==
Task::ACTIVE
);
427
next->
m_state
=
Task::RUNNING
;
428
m_delayModel
->RecordStart ();
429
if
(next->
m_switchNotifier
!= 0)
430
{
431
next->
m_switchNotifier
(
Task::TO
, next->
m_switchNotifierContext
);
432
}
433
again:
434
if
(next->
m_fiber
)
435
{
436
m_fiberManager
->
SwitchTo
(
m_mainFiber
, next->
m_fiber
);
437
}
438
if
(0 !=
m_todoOnMain
)
439
{
440
m_current
= next;
441
m_todoOnMain
->Invoke ();
442
delete
m_todoOnMain
;
443
m_todoOnMain
= 0;
444
goto
again;
445
}
446
if
(
m_reSchedule
)
447
{
448
NS_LOG_DEBUG (
"Delayed schedule "
<<
m_reScheduleTime
);
449
m_reSchedule
=
false
;
450
if
(
m_reScheduleTime
> Time (0))
451
{
452
Simulator::Schedule
(
m_reScheduleTime
, &
TaskManager::Schedule
,
this
);
453
}
454
else
455
{
456
Simulator::ScheduleNow (&
TaskManager::Schedule
,
this
);
457
}
458
}
459
}
460
else
461
{
462
// but, we have nothing to schedule to.
463
}
464
while
(
m_waitQueue
.size () > 0)
465
{
466
Sleeper
s =
m_waitQueue
.front ();
467
s.
m_task
->
m_waitTimer
=
Simulator::Schedule
(s.
m_timeout
, &
TaskManager::EndWait
,
this
, s.
m_task
);
468
m_waitQueue
.pop_front ();
469
}
470
GarbageCollectDeadTasks
();
471
}
472
else
473
{
474
// we have something to schedule from.
475
// but, we have nothing to schedule to so, we go back to the main task.
476
Time delay =
m_delayModel
->RecordEnd ();
477
struct
Task
*next =
m_scheduler
->PeekNext ();
478
NS_LOG_DEBUG (
"Leaving "
<<
m_current
<<
", delay "
<< delay <<
" next = "
<< next <<
" entering main"
);
479
if
(next != 0)
480
{
481
// but before leaving, we check if we have further processes active, and,
482
// if so, make sure we will schedule them later.
483
m_reSchedule
=
true
;
484
m_reScheduleTime
= delay;
485
}
486
struct
Fiber
*fiber =
m_current
->
m_fiber
;
487
if
(
m_current
->
m_switchNotifier
!= 0)
488
{
489
m_current
->
m_switchNotifier
(
Task::FROM
,
m_current
->
m_switchNotifierContext
);
490
}
491
m_current
= 0;
492
if
(fiber)
493
{
494
m_fiberManager
->
SwitchTo
(fiber,
m_mainFiber
);
495
}
496
}
497
}
498
499
void
500
TaskManager::SetFiberManagerType
(
enum
FiberManagerType
type)
501
{
502
NS_LOG_FUNCTION (
this
<< type);
503
switch
(type)
504
{
505
case
UCONTEXT_FIBER_MANAGER
:
506
m_fiberManager
=
new
UcontextFiberManager
();
507
break
;
508
case
PTHREAD_FIBER_MANAGER
:
509
m_fiberManager
=
new
PthreadFiberManager
();
510
break
;
511
default
:
512
NS_ASSERT (
false
);
513
break
;
514
}
515
m_fiberManager
->
SetSwitchNotification
(
SwitchNotifEatSignal
);
516
m_mainFiber
=
m_fiberManager
->
CreateFromCaller
();
517
}
518
519
520
void
521
TaskManager::EndWait
(
Task
*task)
522
{
523
if
(task->
m_state
==
Task::BLOCKED
)
524
{
525
Wakeup
(task);
526
}
527
}
528
529
void
530
TaskManager::SetSwitchNotify
(
void
(*fn)(
void
))
531
{
532
m_fiberManager
->
SetSwitchNotification
(fn);
533
}
534
uint32_t
535
TaskManager::GetStackSize
(
Task
*task)
const
536
{
537
return
m_fiberManager
->
GetStackSize
(task->
m_fiber
);
538
}
539
void
540
TaskManager::ExecOnMain
(EventImpl *e)
541
{
542
if
(
m_current
== 0)
543
{
544
e->Invoke ();
545
delete
e;
546
}
547
else
548
{
549
m_todoOnMain
= e;
550
struct
Fiber
*fiber =
m_current
->
m_fiber
;
551
m_current
= 0;
552
m_noSignal
=
true
;
553
m_fiberManager
->
SwitchTo
(fiber,
m_mainFiber
);
554
}
555
}
556
EventId
557
TaskManager::ScheduleMain
(Time
const
&time, EventImpl *e)
558
{
559
EventId ret;
560
561
ExecOnMain
(MakeEvent (&
TaskManager::MainSchedule
, &ret, time,e));
562
563
return
ret;
564
}
565
void
566
TaskManager::MainSchedule
(EventId *res,Time
const
&time, EventImpl *e)
567
{
568
*res =
Simulator::Schedule
(time, e);
569
}
570
bool
571
TaskManager::GetNoSignal
()
572
{
573
bool
ret =
m_noSignal
;
574
m_noSignal
=
false
;
575
return
ret;
576
}
577
}
// namespace ns3
model
task-manager.cc
Generated on Fri Aug 30 2013 13:57:56 for ns-3-dce by
1.8.1.2