Project

General

Profile

Statistics
| Branch: | Revision:

root / src / sim / casyncmodule.cc @ 3e29b8a0

History | View | Annotate | Download (17.2 KB)

1 01873262 Georg Kunz
//=========================================================================
2
//  CASYNCMODULE.CC - part of
3
//
4
//                  OMNeT++/OMNEST
5
//           Discrete System Simulation in C++
6
//
7
//
8
//   Member functions of
9
//    cAsyncModule : derived class of cSimpleModule for asynchronous event handling
10
//
11
//  Author: Georg Kunz
12
//
13
//=========================================================================
14
15
/*--------------------------------------------------------------*
16
  Copyright (C) 2009 Georg Kunz
17

18
  This file is distributed WITHOUT ANY WARRANTY. See the file
19
  `license' for details on this and other legal matters.
20
*--------------------------------------------------------------*/
21
22
#include <cstring>
23 200f3cf8 Simon Tenbusch
#include <sstream>
24 01873262 Georg Kunz
#include <stdlib.h>
25
26
#include "casyncmodule.h"
27
#include "cthreadpool.h"
28
#include "cconfiguration.h"
29
#include "cconfigoption.h"
30 200f3cf8 Simon Tenbusch
#include "../envir/envirbase.h"
31
#include "cstringtokenizer.h"
32 01873262 Georg Kunz
33
Register_PerRunConfigOption(CFGID_ASYNCMODULE_PARZERODUR, "parallelize-zero-duration-events", CFG_BOOL, "false", "Parallelize Events with zero duration");
34 200f3cf8 Simon Tenbusch
Register_PerObjectConfigOption(CFGID_NUM_LOCAL_RNGS, "number-local-rngs", CFG_INT, "1", "Number of RNGS per module");
35
Register_PerObjectConfigOption(CFGID_LOCAL_RNG_SEED, "local-rng-seed", CFG_STRING, "", "A whitespace seperated list of the seeds for each RNG of the corresponding module, eg '24 232 342 auto 342'");
36 01873262 Georg Kunz
37
38
cAsyncModule::cAsyncModule(const char *name, cModule *parent, unsigned stacksize) :
39
                t_end(0.0)
40
{
41
        //
42 200f3cf8 Simon Tenbusch
        // find out if events with 0 durations should also be parallelized?
43 01873262 Georg Kunz
        //
44
        parZeroDur = ev.getConfig()->getAsBool(CFGID_ASYNCMODULE_PARZERODUR);
45
46
        //
47
        // init state flag to non-busy since no thread is active yet
48
        //
49
        AO_store(&busy, 0);
50 342aee1b Georg Kunz
51
        //
52 012a5b2a Georg Kunz
        // needs to be initialized here for use during model initialization
53 342aee1b Georg Kunz
        //
54
        scheduledMessageCount = 0;
55 d669a8ab Simon Tenbusch
    currentEventPriority = 0;
56 012a5b2a Georg Kunz
57
        //
58
        // initialize with the current time. This variable is already used when
59
        // scheduling events during the initialization phase of the simulation.
60 200f3cf8 Simon Tenbusch
        // Hence, it needs to be initialized. However, we cannot assume 0 here since
61 012a5b2a Georg Kunz
        // the constructor is also called during dynamic module creation at any
62
        // point in time during the simulation.
63
        //
64
        now = simTime();
65 d669a8ab Simon Tenbusch
66 01873262 Georg Kunz
}
67
68
69
cAsyncModule::~cAsyncModule()
70
{
71 f857128b Simon Tenbusch
72 01873262 Georg Kunz
}
73
74 200f3cf8 Simon Tenbusch
void cAsyncModule::initLocalRNGs()
75
{
76
    //TODO
77
    unsigned nrNumGens;
78
    unsigned long * seeds;
79
80
    //
81
    // how many local random number generators do we need?
82
    // default is 1
83
    //
84
    nrNumGens = ev.getConfig()->parseLong(
85
            ev.getConfig()->getPerObjectConfigValue(getFullPath().c_str(),
86
                    "number-local-rngs"), "1", 1);
87
88
    //
89
    // read the seeds from ini file
90
    //
91
    const char * seedString = ev.getConfig()->getPerObjectConfigValue(
92
            getFullPath().c_str(), "local-rng-seed");
93
94
    //
95
    // setup seeds for each RNG
96
    //
97
    seeds = new unsigned long[nrNumGens];
98
    cStringTokenizer tokenizer(seedString);
99
    const char * token = NULL;
100
    for (unsigned i = 0; i < nrNumGens; i++)
101
    {
102
        if (tokenizer.hasMoreTokens())
103
        {
104
            token = tokenizer.nextToken();
105
            if (strcmp(token, "auto") == 0)
106
            {
107
                token = NULL;
108
            }
109
        }
110
111
        EnvirBase* e = dynamic_cast<EnvirBase*> (&ev);
112
        if (e != NULL)
113
        {
114
            if (token)
115
            {
116
                //if the seed is set in the ini for this module, use ini-settings
117
                //with fallback to autogeneration if parsing failes
118
                seeds[i] = ev.getConfig()->parseLong(token, "",
119
                        e->getSeedGenerator()->intRand());
120
            }
121
            else
122
            {
123
                //else use SeedGenerator for automatic seed generation.
124
                seeds[i] = e->getSeedGenerator()->intRand();
125
            }
126
            token = NULL;
127
        }
128
        else
129
        {
130
            throw cRuntimeError(
131
                    "cAsyncModule: Failed to initialize Number Generator, dynamic cast to EnvirBase failed.");
132
        }
133
    }
134
135
    //
136
    // generate the required number of RNGs with the corresponding seeds
137
    //
138 f857128b Simon Tenbusch
    setupSeeds(nrNumGens,seeds);
139 200f3cf8 Simon Tenbusch
    delete[] seeds;
140
141
}
142 01873262 Georg Kunz
143 d493d3f2 Georg Kunz
void cAsyncModule::setMessageMetaData(cMessage* msg)
144 01873262 Georg Kunz
{
145 0e7ff5c8 Simon Tenbusch
    msg->setEventDuration(SimTime::simTimeUninitialized);
146 d493d3f2 Georg Kunz
    msg->setSchedulingOrderId(scheduledMessageCount++);
147
    msg->setParentExecutionOrderId(executionOrderId);
148
    msg->setParentStartTime(now);
149
}
150 96e929a8 Simon Tenbusch
151 d493d3f2 Georg Kunz
int cAsyncModule::scheduleAt(simtime_t t, cMessage *msg)
152
{
153 eefbed01 Georg Kunz
    setMessageMetaData(msg);
154
155 01873262 Georg Kunz
    //
156
    // check current state
157
    //
158 f40e1183 Georg Kunz
    if (executionState == asynchronous)
159 01873262 Georg Kunz
    {
160
        if (msg==NULL)
161
          throw cRuntimeError("scheduleAt(): message pointer is NULL");
162
        if (t < t_end)
163
                throw cRuntimeError("scheduleAt(): event cannot be scheduled at "
164
                                "%s because this precedes the end of the processing duration "
165
                                "at %s of the scheduling event.",
166
                                t.str().c_str(), t_end.str().c_str());
167
168 d669a8ab Simon Tenbusch
        if (t == now && currentEventPriority < msg->getSchedulingPriority()) {
169 97ccebed Simon Tenbusch
            throw cRuntimeError("scheduleAt(): priority of scheduled Event larger than scheduling event and equal starting times => scheduling in the past");
170 d669a8ab Simon Tenbusch
        }
171 01873262 Georg Kunz
        // insert this message in the FES. When the scheduler arrives at this
172
        // message it will trigger the processing of the associated task
173
        msg->setSentFrom(this, -1, t_end);
174
        msg->setArrival(this, -1, t);
175 96e929a8 Simon Tenbusch
176 01873262 Georg Kunz
        simulation.msgQueue.insert(msg);
177
        return 0;
178
    }
179
    else // synch execution
180
    {
181
        return cSimpleModule::scheduleAt(t, msg);
182
    }
183
}
184
185
186
void cAsyncModule::callHandleAsyncMessage(cMessage* msg)
187
{
188
    //
189 f40e1183 Georg Kunz
    // set execution state
190 01873262 Georg Kunz
    //
191 f40e1183 Georg Kunz
    executionState = asynchronous;
192 01873262 Georg Kunz
193
    //
194
    // set the simtime for this event
195
    //
196
    cThreadPool::setSimTime(msg->getArrivalTime());
197
    // corresponds to setContextModule(mod);
198
    cThreadPool::setContext(this);
199
    cThreadPool::setDefaultOwner(this);
200
201 f40e1183 Georg Kunz
    //
202
    // update meta data
203
    //
204
    prepareHandleMessage(msg);
205 01873262 Georg Kunz
206
    //
207
    // call the actual method
208
    //
209
    handleMessage(msg);
210
}
211
212
213
void cAsyncModule::callHandleMessage(cMessage* msg)
214
{
215
    //
216 f40e1183 Georg Kunz
    // set execution state
217 01873262 Georg Kunz
    //
218 f40e1183 Georg Kunz
    executionState = synchronous;
219 01873262 Georg Kunz
220 f40e1183 Georg Kunz
    //
221
    // update meta data
222
    //
223
    prepareHandleMessage(msg);
224 01873262 Georg Kunz
225 f40e1183 Georg Kunz
    //
226
    // call the actual method
227
    //
228
    handleMessage(msg);
229
}
230
231
232
void cAsyncModule::prepareHandleMessage(cMessage* msg)
233
{
234
    //
235
    // set some internal state
236
    //
237 01873262 Georg Kunz
    t_end = msg->getArrivalTime() + msg->getEventDuration();
238 d493d3f2 Georg Kunz
    now = msg->getArrivalTime();
239 d669a8ab Simon Tenbusch
    currentEventPriority = msg->getSchedulingPriority();
240 f40e1183 Georg Kunz
241 01873262 Georg Kunz
    //
242
    // take ownership of the message only after the test above
243
    //
244
    this->take(msg);
245
246
    //
247 f40e1183 Georg Kunz
    // reset message counter
248 77cb9420 Simon Tenbusch
    // message 0 is the barriermsg
249 01873262 Georg Kunz
    //
250 77cb9420 Simon Tenbusch
    scheduledMessageCount = 1;
251 d493d3f2 Georg Kunz
252
    executionOrderId = msg->getExecutionOrderId();
253 d669a8ab Simon Tenbusch
254 01873262 Georg Kunz
}
255
256
int cAsyncModule::send(cMessage *msg, int gateid)
257
{
258
    return sendDelayed(msg, 0.0, gateid);
259
}
260
261
262
int cAsyncModule::send(cMessage *msg, const char *gatename, int sn)
263
{
264
    return sendDelayed(msg, 0.0, gatename, sn);
265
}
266
267
268
int cAsyncModule::send(cMessage *msg, cGate *outputgate)
269
{
270
    return sendDelayed(msg, 0.0, outputgate);
271
}
272
273
274
int cAsyncModule::sendDelayed(cMessage *msg, simtime_t delay, int gateid)
275
{
276
    cGate *outgate = gate(gateid);
277
    if (outgate==NULL)
278
        throw cRuntimeError("send()/sendDelayed(): module has no gate #%d", gateid);
279
280
    return sendDelayed(msg, delay, outgate);
281
}
282
283
284
int cAsyncModule::sendDelayed(cMessage *msg, simtime_t delay, const char *gatename, int sn)
285
{
286
    cGate *outgate = gate(gatename, sn);
287
    if (outgate==NULL)
288
       throw cRuntimeError(sn<0 ? "send()/sendDelayed(): module has no gate `%s'":
289
                               "send()/sendDelayed(): module has no gate `%s[%d]'",gatename,sn);
290
291
    return sendDelayed(msg, delay, outgate);
292
}
293
294
295
int cAsyncModule::sendDelayed(cMessage *msg, simtime_t delay, cGate *outputgate)
296
{
297 eefbed01 Georg Kunz
    setMessageMetaData(msg);
298
299 01873262 Georg Kunz
    //
300
    // check current state
301
    //
302 f40e1183 Georg Kunz
    if (executionState == asynchronous)
303 01873262 Georg Kunz
    {
304
        //
305
        // error checking, omit ownership checks if it breaks
306
        //
307
        if (outputgate==NULL)
308
            throw cRuntimeError("send()/sendDelayed(): gate pointer is NULL");
309
        if (outputgate->getType()=='I')
310
            throw cRuntimeError("send()/sendDelayed(): cannot send via an input gate (`%s')",outputgate->getName());
311
        if (!outputgate->getNextGate())  // NOTE: without this error check, msg would become self-message
312
            throw cRuntimeError("send()/sendDelayed(): gate `%s' not connected",outputgate->getFullName());
313
        if (msg==NULL)
314
            throw cRuntimeError("send()/sendDelayed(): message pointer is NULL");
315
        if (msg->getOwner()!=this)
316
        {
317
            if (this!=simulation.getContext())
318
                throw cRuntimeError("send()/sendDelayed() of module (%s)%s called in the context of "
319
                                        "module (%s)%s: method called from the latter module "
320
                                        "lacks Enter_Method() or Enter_Method_Silent()? "
321
                                        "Also, if message to be sent is passed from that module, "
322
                                        "you'll need to call take(msg) after Enter_Method() as well",
323
                                        getClassName(), getFullPath().c_str(),
324
                                        simulation.getContext()->getClassName(),
325
                                        simulation.getContext()->getFullPath().c_str());
326
            else if (msg->getOwner()==&simulation.msgQueue && msg->isSelfMessage() && msg->getArrivalModuleId()==getId())
327
                throw cRuntimeError("send()/sendDelayed(): cannot send message (%s)%s, it is "
328
                                        "currently scheduled as a self-message for this module",
329
                                        msg->getClassName(), msg->getName());
330
            else if (msg->getOwner()==&simulation.msgQueue && msg->isSelfMessage())
331
                throw cRuntimeError("send()/sendDelayed(): cannot send message (%s)%s, it is "
332
                                        "currently scheduled as a self-message for ANOTHER module",
333
                                        msg->getClassName(), msg->getName());
334
            else if (msg->getOwner()==&simulation.msgQueue)
335
                throw cRuntimeError("send()/sendDelayed(): cannot send message (%s)%s, it is "
336
                                        "currently in scheduled-events, being underway between two modules",
337
                                        msg->getClassName(), msg->getName());
338
            else
339
                throw cRuntimeError("send()/sendDelayed(): cannot send message (%s)%s, "
340
                                        "it is currently contained/owned by (%s)%s",
341
                                        msg->getClassName(), msg->getName(), msg->getOwner()->getClassName(),
342
                                        msg->getOwner()->getFullPath().c_str());
343
        }
344
345 012a5b2a Georg Kunz
        if (delay < 0.0)
346 01873262 Georg Kunz
            throw cRuntimeError("sendDelayed(): negative delay %s",delay.str().c_str());
347 012a5b2a Georg Kunz
348
        simtime_t arrivalTime = now + delay;
349
        if (arrivalTime < t_end) // TODO: Consider channel delay!
350 01873262 Georg Kunz
            throw cRuntimeError("sendDelayed(): send delay shorter than processing delay %s", delay.str().c_str());
351
352 d669a8ab Simon Tenbusch
        if (delay == 0 && currentEventPriority < msg->getSchedulingPriority()) {
353 97ccebed Simon Tenbusch
            throw cRuntimeError("sendDelayed(): priority of scheduled Event larger than scheduling event and equal starting times => scheduling in the past");
354 d669a8ab Simon Tenbusch
        }
355 01873262 Georg Kunz
        //
356
        // set message parameters and send it
357
        //
358 012a5b2a Georg Kunz
        msg->setSentFrom(this, outputgate->getId(), arrivalTime);
359
        bool keepit = outputgate->deliver(msg, arrivalTime);
360 01873262 Georg Kunz
        if (!keepit)
361
            delete msg;
362
363
        return 0;
364
    }
365
    else // syncExecution
366
    {
367
        return cSimpleModule::sendDelayed(msg, delay, outputgate);
368
    }
369
}
370
371
372
int cAsyncModule::sendDirect(cMessage *msg, simtime_t delay, simtime_t duration, cModule *mod, int inputgateid)
373
{
374
    cGate *togate = mod->gate(inputgateid);
375
    if (togate==NULL)
376
        throw cRuntimeError("sendDirect(): module `%s' has no gate #%d",
377
                                mod->getFullPath().c_str(), inputgateid);
378
379
    return sendDirect(msg, delay, duration, togate);
380
}
381
382
383
int cAsyncModule::sendDirect(cMessage *msg, simtime_t delay, simtime_t duration, cModule *mod, const char *inputgatename, int sn)
384
{
385
    if (!mod)
386
        throw cRuntimeError("sendDirect(): module ptr is NULL");
387
    cGate *togate = mod->gate(inputgatename,sn);
388
    if (togate==NULL)
389
        throw cRuntimeError(sn<0 ? "sendDirect(): module `%s' has no gate `%s'":
390
                                "sendDirect(): module `%s' has no gate `%s[%d]'",
391
                                mod->getFullPath().c_str(), inputgatename, sn);
392
    return sendDirect(msg, delay, duration, togate);
393
}
394
395
396
int cAsyncModule::sendDirect(cMessage *msg, simtime_t delay, simtime_t duration, cGate *togate)
397
{
398 eefbed01 Georg Kunz
    setMessageMetaData(msg);
399
400 01873262 Georg Kunz
    //
401
    // check current state
402
    //
403 f40e1183 Georg Kunz
    if (executionState == asynchronous)
404 01873262 Georg Kunz
    {
405
        //
406
        // error checking
407
        //
408
        // Note: it is permitted to send to an output gate. It is especially useful
409
        // with several submodules sending to a single output gate of their parent module.
410
        if (togate==NULL)
411
                throw cRuntimeError("sendDirect(): destination gate pointer is NULL");
412
        if (togate->getPreviousGate())
413
                throw cRuntimeError("sendDirect(): module must have dedicated gate(s) for receiving via sendDirect()"
414
                                                                " (\"from\" side of dest. gate `%s' should NOT be connected)",togate->getFullPath().c_str());
415
        if (msg==NULL)
416
                throw cRuntimeError("sendDirect(): message pointer is NULL");
417
        if (msg->getOwner()!=this)
418
        {
419
                if (this!=simulation.getContext())
420
                        throw cRuntimeError("sendDirect() of module (%s)%s called in the context of "
421
                                                                        "module (%s)%s: method called from the latter module "
422
                                                                        "lacks Enter_Method() or Enter_Method_Silent()? "
423
                                                                        "Also, if message to be sent is passed from that module, "
424
                                                                        "you'll need to call take(msg) after Enter_Method() as well",
425
                                                                        getClassName(), getFullPath().c_str(),
426
                                                                        simulation.getContext()->getClassName(),
427
                                                                        simulation.getContext()->getFullPath().c_str());
428
                else if (msg->getOwner()==&simulation.msgQueue && msg->isSelfMessage() && msg->getArrivalModuleId()==getId())
429
                        throw cRuntimeError("sendDirect(): cannot send message (%s)%s, it is "
430
                                                                        "currently scheduled as a self-message for this module",
431
                                                                        msg->getClassName(), msg->getName());
432
                else if (msg->getOwner()==&simulation.msgQueue && msg->isSelfMessage())
433
                        throw cRuntimeError("sendDirect(): cannot send message (%s)%s, it is "
434
                                                                        "currently scheduled as a self-message for ANOTHER module",
435
                                                                        msg->getClassName(), msg->getName());
436
                else if (msg->getOwner()==&simulation.msgQueue)
437
                        throw cRuntimeError("sendDirect(): cannot send message (%s)%s, it is "
438
                                                                        "currently in scheduled-events, being underway between two modules",
439
                                                                        msg->getClassName(), msg->getName());
440
                else
441
                        throw cRuntimeError("sendDirect(): cannot send message (%s)%s, "
442
                                                                        "it is currently contained/owned by (%s)%s",
443
                                                                        msg->getClassName(), msg->getName(), msg->getOwner()->getClassName(),
444
                                                                        msg->getOwner()->getFullPath().c_str());
445
        }
446
447 012a5b2a Georg Kunz
        simtime_t arrivalTime = now + delay;
448
        if (arrivalTime < t_end) // TODO: Consider channel delay!
449 d669a8ab Simon Tenbusch
            throw cRuntimeError("sendDirect(): send delay shorter than processing delay %s",delay.str().c_str());
450
451
        if (delay == 0 && currentEventPriority < msg->getSchedulingPriority()) {
452 97ccebed Simon Tenbusch
            throw cRuntimeError("sendDirect(): priority of scheduled Event larger than scheduling event and equal starting times => scheduling in the past");
453 d669a8ab Simon Tenbusch
        }
454 01873262 Georg Kunz
455 012a5b2a Georg Kunz
        // set message parameters and send it
456
        msg->setSentFrom(this, -1, now);
457 01873262 Georg Kunz
458 012a5b2a Georg Kunz
        bool keepit = togate->deliver(msg, arrivalTime);
459 01873262 Georg Kunz
        if (!keepit)
460
                delete msg;
461
        return 0;
462
    }
463
    else  // sync execution
464
    {
465
            return cSimpleModule::sendDirect(msg, delay, duration, togate);
466
    }
467
}