Project

General

Profile

Statistics
| Branch: | Revision:

root / src / sim / casyncmodule.cc @ f40e1183

History | View | Annotate | Download (13.7 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
#include <stdlib.h>
24
25
#include "casyncmodule.h"
26
#include "cthreadpool.h"
27
#include "cconfiguration.h"
28
#include "cconfigoption.h"
29
30
31
Register_PerRunConfigOption(CFGID_ASYNCMODULE_PARZERODUR, "parallelize-zero-duration-events", CFG_BOOL, "false", "Parallelize Events with zero duration");
32
33
34
cAsyncModule::cAsyncModule(const char *name, cModule *parent, unsigned stacksize) :
35
                t_end(0.0)
36
{
37
    //
38
        // how many local random number generators do we need? This should become a
39
        // special parameter of every asyncmodule. Not yet implemented.
40
        //
41
        unsigned nrNumGens = 1;
42
        /*
43
         cPar *p = (cPar*)paramv.get("number-local-rngs");
44
         if (p)
45
         nrNumGens = *p;
46

47
         std::cout << "number-local-rngs in " << fullName() << ": " << nrNumGens << std::endl;
48
         */
49
        numGen = new cNumberGenerator(nrNumGens);
50
51
        //
52
        // find out if events with 0 durations also be parallelized?
53
        //
54
        parZeroDur = ev.getConfig()->getAsBool(CFGID_ASYNCMODULE_PARZERODUR);
55
56
        //
57
        // init state flag to non-busy since no thread is active yet
58
        //
59
        AO_store(&busy, 0);
60
}
61
62
63
cAsyncModule::~cAsyncModule()
64
{
65
  delete numGen;
66
}
67
68
69
int cAsyncModule::scheduleAt(simtime_t t, cMessage *msg)
70
{
71 96e929a8 Simon Tenbusch
    msg->setEventDuration(-1);
72
73 01873262 Georg Kunz
    //
74
    // check current state
75
    //
76 f40e1183 Georg Kunz
    if (executionState == asynchronous)
77 01873262 Georg Kunz
    {
78
        if (msg==NULL)
79
          throw cRuntimeError("scheduleAt(): message pointer is NULL");
80
        if (t < t_end)
81
                throw cRuntimeError("scheduleAt(): event cannot be scheduled at "
82
                                "%s because this precedes the end of the processing duration "
83
                                "at %s of the scheduling event.",
84
                                t.str().c_str(), t_end.str().c_str());
85
86
        // insert this message in the FES. When the scheduler arrives at this
87
        // message it will trigger the processing of the associated task
88
        msg->setSentFrom(this, -1, t_end);
89
        msg->setArrival(this, -1, t);
90 96e929a8 Simon Tenbusch
91
92 01873262 Georg Kunz
        simulation.msgQueue.insert(msg);
93
        return 0;
94
    }
95
    else // synch execution
96
    {
97
        return cSimpleModule::scheduleAt(t, msg);
98
    }
99
}
100
101
102
void cAsyncModule::callHandleAsyncMessage(cMessage* msg)
103
{
104
    //
105 f40e1183 Georg Kunz
    // set execution state
106 01873262 Georg Kunz
    //
107 f40e1183 Georg Kunz
    executionState = asynchronous;
108 01873262 Georg Kunz
109
    //
110
    // set the simtime for this event
111
    //
112
    cThreadPool::setSimTime(msg->getArrivalTime());
113
    // corresponds to setContextModule(mod);
114
    cThreadPool::setContext(this);
115
    cThreadPool::setDefaultOwner(this);
116
117 f40e1183 Georg Kunz
    //
118
    // update meta data
119
    //
120
    prepareHandleMessage(msg);
121 01873262 Georg Kunz
122
    //
123
    // call the actual method
124
    //
125
    handleMessage(msg);
126
}
127
128
129
void cAsyncModule::callHandleMessage(cMessage* msg)
130
{
131
    //
132 f40e1183 Georg Kunz
    // set execution state
133 01873262 Georg Kunz
    //
134 f40e1183 Georg Kunz
    executionState = synchronous;
135 01873262 Georg Kunz
136 f40e1183 Georg Kunz
    //
137
    // update meta data
138
    //
139
    prepareHandleMessage(msg);
140 01873262 Georg Kunz
141 f40e1183 Georg Kunz
    //
142
    // call the actual method
143
    //
144
    handleMessage(msg);
145
}
146
147
148
void cAsyncModule::prepareHandleMessage(cMessage* msg)
149
{
150
    //
151
    // set some internal state
152
    //
153 01873262 Georg Kunz
    t_end = msg->getArrivalTime() + msg->getEventDuration();
154
155 f40e1183 Georg Kunz
156 01873262 Georg Kunz
    //
157
    // take ownership of the message only after the test above
158
    //
159
    this->take(msg);
160
161
    //
162 f40e1183 Georg Kunz
    // reset message counter
163 01873262 Georg Kunz
    //
164 f40e1183 Georg Kunz
    sentMessageCount = 0;
165 01873262 Georg Kunz
}
166
167
int cAsyncModule::send(cMessage *msg, int gateid)
168
{
169
    return sendDelayed(msg, 0.0, gateid);
170
}
171
172
173
int cAsyncModule::send(cMessage *msg, const char *gatename, int sn)
174
{
175
    return sendDelayed(msg, 0.0, gatename, sn);
176
}
177
178
179
int cAsyncModule::send(cMessage *msg, cGate *outputgate)
180
{
181
    return sendDelayed(msg, 0.0, outputgate);
182
}
183
184
185
int cAsyncModule::sendDelayed(cMessage *msg, simtime_t delay, int gateid)
186
{
187
    cGate *outgate = gate(gateid);
188
    if (outgate==NULL)
189
        throw cRuntimeError("send()/sendDelayed(): module has no gate #%d", gateid);
190
191
    return sendDelayed(msg, delay, outgate);
192
}
193
194
195
int cAsyncModule::sendDelayed(cMessage *msg, simtime_t delay, const char *gatename, int sn)
196
{
197
    cGate *outgate = gate(gatename, sn);
198
    if (outgate==NULL)
199
       throw cRuntimeError(sn<0 ? "send()/sendDelayed(): module has no gate `%s'":
200
                               "send()/sendDelayed(): module has no gate `%s[%d]'",gatename,sn);
201
202
    return sendDelayed(msg, delay, outgate);
203
}
204
205
206
int cAsyncModule::sendDelayed(cMessage *msg, simtime_t delay, cGate *outputgate)
207
{
208 96e929a8 Simon Tenbusch
    msg->setEventDuration(-1);
209
210 01873262 Georg Kunz
    //
211
    // check current state
212
    //
213 f40e1183 Georg Kunz
    if (executionState == asynchronous)
214 01873262 Georg Kunz
    {
215
        //
216
        // error checking, omit ownership checks if it breaks
217
        //
218
        if (outputgate==NULL)
219
            throw cRuntimeError("send()/sendDelayed(): gate pointer is NULL");
220
        if (outputgate->getType()=='I')
221
            throw cRuntimeError("send()/sendDelayed(): cannot send via an input gate (`%s')",outputgate->getName());
222
        if (!outputgate->getNextGate())  // NOTE: without this error check, msg would become self-message
223
            throw cRuntimeError("send()/sendDelayed(): gate `%s' not connected",outputgate->getFullName());
224
        if (msg==NULL)
225
            throw cRuntimeError("send()/sendDelayed(): message pointer is NULL");
226
        if (msg->getOwner()!=this)
227
        {
228
            if (this!=simulation.getContext())
229
                throw cRuntimeError("send()/sendDelayed() of module (%s)%s called in the context of "
230
                                        "module (%s)%s: method called from the latter module "
231
                                        "lacks Enter_Method() or Enter_Method_Silent()? "
232
                                        "Also, if message to be sent is passed from that module, "
233
                                        "you'll need to call take(msg) after Enter_Method() as well",
234
                                        getClassName(), getFullPath().c_str(),
235
                                        simulation.getContext()->getClassName(),
236
                                        simulation.getContext()->getFullPath().c_str());
237
            else if (msg->getOwner()==&simulation.msgQueue && msg->isSelfMessage() && msg->getArrivalModuleId()==getId())
238
                throw cRuntimeError("send()/sendDelayed(): cannot send message (%s)%s, it is "
239
                                        "currently scheduled as a self-message for this module",
240
                                        msg->getClassName(), msg->getName());
241
            else if (msg->getOwner()==&simulation.msgQueue && msg->isSelfMessage())
242
                throw cRuntimeError("send()/sendDelayed(): cannot send message (%s)%s, it is "
243
                                        "currently scheduled as a self-message for ANOTHER module",
244
                                        msg->getClassName(), msg->getName());
245
            else if (msg->getOwner()==&simulation.msgQueue)
246
                throw cRuntimeError("send()/sendDelayed(): cannot send message (%s)%s, it is "
247
                                        "currently in scheduled-events, being underway between two modules",
248
                                        msg->getClassName(), msg->getName());
249
            else
250
                throw cRuntimeError("send()/sendDelayed(): cannot send message (%s)%s, "
251
                                        "it is currently contained/owned by (%s)%s",
252
                                        msg->getClassName(), msg->getName(), msg->getOwner()->getClassName(),
253
                                        msg->getOwner()->getFullPath().c_str());
254
        }
255
256
        simtime_t t = simTime();
257
        if (delay<0.0)
258
            throw cRuntimeError("sendDelayed(): negative delay %s",delay.str().c_str());
259
        if (t+delay<t_end) // TODO: Consider channel delay!
260
            throw cRuntimeError("sendDelayed(): send delay shorter than processing delay %s", delay.str().c_str());
261
262
        //
263
        // set message parameters and send it
264
        //
265
        msg->setSentFrom(this, outputgate->getId(), t+delay);
266
        bool keepit = outputgate->deliver(msg, t+delay);
267
        if (!keepit)
268
            delete msg;
269
270
        return 0;
271
    }
272
    else // syncExecution
273
    {
274
        return cSimpleModule::sendDelayed(msg, delay, outputgate);
275
    }
276
}
277
278
279
int cAsyncModule::sendDirect(cMessage *msg, simtime_t delay, simtime_t duration, cModule *mod, int inputgateid)
280
{
281
    cGate *togate = mod->gate(inputgateid);
282
    if (togate==NULL)
283
        throw cRuntimeError("sendDirect(): module `%s' has no gate #%d",
284
                                mod->getFullPath().c_str(), inputgateid);
285
286
    return sendDirect(msg, delay, duration, togate);
287
}
288
289
290
int cAsyncModule::sendDirect(cMessage *msg, simtime_t delay, simtime_t duration, cModule *mod, const char *inputgatename, int sn)
291
{
292
    if (!mod)
293
        throw cRuntimeError("sendDirect(): module ptr is NULL");
294
    cGate *togate = mod->gate(inputgatename,sn);
295
    if (togate==NULL)
296
        throw cRuntimeError(sn<0 ? "sendDirect(): module `%s' has no gate `%s'":
297
                                "sendDirect(): module `%s' has no gate `%s[%d]'",
298
                                mod->getFullPath().c_str(), inputgatename, sn);
299
    return sendDirect(msg, delay, duration, togate);
300
}
301
302
303
int cAsyncModule::sendDirect(cMessage *msg, simtime_t delay, simtime_t duration, cGate *togate)
304
{
305 96e929a8 Simon Tenbusch
306
    msg->setEventDuration(-1);
307
308 01873262 Georg Kunz
    //
309
    // check current state
310
    //
311 f40e1183 Georg Kunz
    if (executionState == asynchronous)
312 01873262 Georg Kunz
    {
313
        //
314
        // error checking
315
        //
316
        // Note: it is permitted to send to an output gate. It is especially useful
317
        // with several submodules sending to a single output gate of their parent module.
318
        if (togate==NULL)
319
                throw cRuntimeError("sendDirect(): destination gate pointer is NULL");
320
        if (togate->getPreviousGate())
321
                throw cRuntimeError("sendDirect(): module must have dedicated gate(s) for receiving via sendDirect()"
322
                                                                " (\"from\" side of dest. gate `%s' should NOT be connected)",togate->getFullPath().c_str());
323
        if (msg==NULL)
324
                throw cRuntimeError("sendDirect(): message pointer is NULL");
325
        if (msg->getOwner()!=this)
326
        {
327
                if (this!=simulation.getContext())
328
                        throw cRuntimeError("sendDirect() of module (%s)%s called in the context of "
329
                                                                        "module (%s)%s: method called from the latter module "
330
                                                                        "lacks Enter_Method() or Enter_Method_Silent()? "
331
                                                                        "Also, if message to be sent is passed from that module, "
332
                                                                        "you'll need to call take(msg) after Enter_Method() as well",
333
                                                                        getClassName(), getFullPath().c_str(),
334
                                                                        simulation.getContext()->getClassName(),
335
                                                                        simulation.getContext()->getFullPath().c_str());
336
                else if (msg->getOwner()==&simulation.msgQueue && msg->isSelfMessage() && msg->getArrivalModuleId()==getId())
337
                        throw cRuntimeError("sendDirect(): cannot send message (%s)%s, it is "
338
                                                                        "currently scheduled as a self-message for this module",
339
                                                                        msg->getClassName(), msg->getName());
340
                else if (msg->getOwner()==&simulation.msgQueue && msg->isSelfMessage())
341
                        throw cRuntimeError("sendDirect(): cannot send message (%s)%s, it is "
342
                                                                        "currently scheduled as a self-message for ANOTHER module",
343
                                                                        msg->getClassName(), msg->getName());
344
                else if (msg->getOwner()==&simulation.msgQueue)
345
                        throw cRuntimeError("sendDirect(): cannot send message (%s)%s, it is "
346
                                                                        "currently in scheduled-events, being underway between two modules",
347
                                                                        msg->getClassName(), msg->getName());
348
                else
349
                        throw cRuntimeError("sendDirect(): cannot send message (%s)%s, "
350
                                                                        "it is currently contained/owned by (%s)%s",
351
                                                                        msg->getClassName(), msg->getName(), msg->getOwner()->getClassName(),
352
                                                                        msg->getOwner()->getFullPath().c_str());
353
        }
354
355
        // set message parameters and send it
356
        simtime_t time = simTime();
357
        if (time + delay < t_end) // TODO: Consider channel delay!
358
            throw cRuntimeError("sendDelayed(): send delay shorter than processing delay %s",delay.str().c_str());
359
360
        msg->setSentFrom(this, -1, time);
361
362
        bool keepit = togate->deliver(msg, time + delay);
363
        if (!keepit)
364
                delete msg;
365
        return 0;
366
    }
367
    else  // sync execution
368
    {
369
            return cSimpleModule::sendDirect(msg, delay, duration, togate);
370
    }
371
}