Statistics
| Branch: | Revision:

root / src / sim / cmessage.cc @ cbd2c699

History | View | Annotate | Download (17.4 KB)

1 01873262 Georg Kunz
//========================================================================
2
//  CMESSAGE.CC - part of
3
//
4
//                 OMNeT++/OMNEST
5
//              Discrete System Simulation in C++
6
//
7
//   Member functions of
8
//    cMessage       : the message class
9
//
10
//  Author: Andras Varga
11
//
12
//========================================================================
13
14
/*--------------------------------------------------------------*
15
  Copyright (C) 1992-2008 Andras Varga
16
  Copyright (C) 2006-2008 OpenSim Ltd.
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 <stdio.h>  // sprintf
23
#include <sstream>
24
#include "globals.h"
25
#include "cmodule.h"
26
#include "csimplemodule.h"
27
#include "cmessage.h"
28
#include "cexception.h"
29
#include "cenvir.h"
30
31
#ifdef WITH_PARSIM
32
#include "ccommbuffer.h"
33
#endif
34
35
USING_NAMESPACE
36
37
// comment out to disable reference-counting for encapsulated messages
38
#define REFCOUNTING
39
40
using std::ostream;
41
42
#ifdef WITHOUT_CPACKET
43
#undef cMessage
44
#endif
45
46
Register_Class(cMessage);
47
Register_Class(cPacket);
48
49
// static members of cMessage
50
AO_t cMessage::next_id = 0;
51
AO_t cMessage::total_msgs = 0;
52
AO_t cMessage::live_msgs = 0;
53
54
cMessage::cMessage(const cMessage& msg) : cOwnedObject(msg)
55
{
56
    parlistp = NULL;
57
    ctrlp = NULL;
58
    heapindex = -1;
59
    prev_event_num = -1;
60
    operator=(msg);
61
62
    msgid = AO_fetch_and_add1(&next_id);
63
    AO_fetch_and_add1(&total_msgs);
64
    AO_fetch_and_add1(&live_msgs);
65 d493d3f2 Georg Kunz
66
    schedulingOrderId = 0;
67 01873262 Georg Kunz
}
68
69
cMessage::cMessage(const char *name, short k) : cOwnedObject(name, false)
70
{
71
    // name pooling is off for messages by default, as unique names are quite common
72
    msgkind = k;
73
    prior = 0;
74
    parlistp = NULL;
75
    contextptr = NULL;
76
    ctrlp = NULL;
77
    srcprocid = -1;
78
79
    frommod = fromgate = -1;
80
    tomod = togate = -1;
81
    created = simulation.getSimTime();
82
    sent = delivd = tstamp = 0;
83
    heapindex = -1;
84
    prev_event_num = -1;
85
86 cbd2c699 Mirko Stoffers
    eventDuration = SimTime::simTimeUninitialized;
87 01873262 Georg Kunz
    msgtreeid = msgid = AO_fetch_and_add1(&next_id);
88
    AO_fetch_and_add1(&total_msgs);
89
    AO_fetch_and_add1(&live_msgs);
90 d493d3f2 Georg Kunz
91
    parentStartTime = SimTime::simTimeZero;
92
    parentExecutionOrderId = 0;
93
    schedulingOrderId = 0;
94 01873262 Georg Kunz
}
95
96
cMessage::~cMessage()
97
{
98
#ifndef WITHOUT_CPACKET
99
    EVCB.messageDeleted(this);
100
#endif
101
102
    if (parlistp)
103
        dropAndDelete(parlistp);
104
105
    if (ctrlp) {
106
        if (ctrlp->isOwnedObject())
107
            dropAndDelete(static_cast<cOwnedObject *>(ctrlp));
108
        else
109
            delete ctrlp;
110
    }
111
    AO_fetch_and_sub1(&live_msgs);
112
}
113
114
std::string cMessage::info() const
115
{
116
    if (tomod<0)
117
        return std::string("(new msg)");
118
119
    std::stringstream out;
120
    const char *deletedstr = "<deleted module>";
121
122
    if (delivd > simulation.getSimTime())
123
    {
124
        // if it arrived in the past, dt is usually unimportant, don't print it
125
        out << "at T=" << delivd << ", in dt=" << (delivd - simulation.getSimTime()) << "; ";
126
    }
127
128
#define MODNAME(modp) ((modp) ? (modp)->getFullPath().c_str() : deletedstr)
129
    if (getKind()==MK_STARTER)
130
    {
131
        cModule *tomodp = simulation.getModule(tomod);
132
        out << "starter for " << MODNAME(tomodp) << " (id=" << tomod << ") ";
133
    }
134
    else if (getKind()==MK_TIMEOUT)
135
    {
136
        cModule *tomodp = simulation.getModule(tomod);
137
        out << "timeoutmsg for " << MODNAME(tomodp) << " (id=" << tomod << ") ";
138
    }
139
    else if (frommod==tomod)
140
    {
141
        cModule *tomodp = simulation.getModule(tomod);
142
        out << "selfmsg for " << MODNAME(tomodp) << " (id=" << tomod << ") ";
143
    }
144
    else
145
    {
146
        cModule *frommodp = simulation.getModule(frommod);
147
        cModule *tomodp = simulation.getModule(tomod);
148
        out << "src=" << MODNAME(frommodp) << " (id=" << frommod << ") ";
149
        out << " dest=" << MODNAME(tomodp) << " (id=" << tomod << ") ";
150
    }
151
#undef MODNAME
152
153
    if (ctrlp)
154
        out << "  control info: (" << ctrlp->getClassName() << ") " << ctrlp->getFullName() << "\n";
155
156
    return out.str();
157
}
158
159
void cMessage::forEachChild(cVisitor *v)
160
{
161
    if (parlistp)
162
        v->visit(parlistp);
163
}
164
165
std::string cMessage::detailedInfo() const
166
{
167
    return "";  // all fields are available via reflection, no point in repeating them here
168
}
169
170
void cMessage::parsimPack(cCommBuffer *buffer)
171
{
172
#ifndef WITH_PARSIM
173
    throw cRuntimeError(this,eNOPARSIM);
174
#else
175
    cOwnedObject::parsimPack(buffer);
176
177
    if (contextptr || ctrlp)
178
        throw cRuntimeError(this,"parsimPack(): cannot pack object with contextPointer or controlInfo set");
179
180
    buffer->pack(msgkind);
181
    buffer->pack(prior);
182
    buffer->pack(tstamp);
183
184
    buffer->pack(frommod);
185
    buffer->pack(fromgate);
186
    buffer->pack(tomod);
187
    buffer->pack(togate);
188
    buffer->pack(created);
189
    buffer->pack(sent);
190
    buffer->pack(delivd);
191
    buffer->pack(heapindex);
192
    buffer->pack(insertordr);
193
194
    // note: do not pack msgid and treeid, because they'd conflict
195
    // with ids assigned at the destination partition
196
197
    if (buffer->packFlag(parlistp!=NULL))
198
        buffer->packObject(parlistp);
199
#endif
200
}
201
202
void cMessage::parsimUnpack(cCommBuffer *buffer)
203
{
204
#ifndef WITH_PARSIM
205
    throw cRuntimeError(this,eNOPARSIM);
206
#else
207
    cOwnedObject::parsimUnpack(buffer);
208
209
    buffer->unpack(msgkind);
210
    buffer->unpack(prior);
211
    buffer->unpack(tstamp);
212
213
    buffer->unpack(frommod);
214
    buffer->unpack(fromgate);
215
    buffer->unpack(tomod);
216
    buffer->unpack(togate);
217
    buffer->unpack(created);
218
    buffer->unpack(sent);
219
    buffer->unpack(delivd);
220
    buffer->unpack(heapindex);
221
    buffer->unpack(insertordr);
222
223
    if (buffer->checkFlag())
224
        take(parlistp = (cArray *) buffer->unpackObject());
225
#endif
226
}
227
228
cMessage& cMessage::operator=(const cMessage& msg)
229
{
230
    if (this==&msg) return *this;
231
232
    cOwnedObject::operator=(msg);
233
234
    msgkind = msg.msgkind;
235
    prior = msg.prior;
236
    tstamp = msg.tstamp;
237
    srcprocid = msg.srcprocid;
238
239
    created = msg.created;
240
241
    dropAndDelete(parlistp);
242
    if (msg.parlistp)
243
        take(parlistp = (cArray *)msg.parlistp->dup());
244
    else
245
        parlistp = NULL;
246
247
    contextptr = msg.contextptr;
248
249
    frommod = msg.frommod;
250
    fromgate = msg.fromgate;
251
    tomod = msg.tomod;
252
    togate = msg.togate;
253
254
    sent = msg.sent;
255
    delivd = msg.delivd;
256
257
    msgtreeid = msg.msgtreeid;
258
259 d493d3f2 Georg Kunz
    parentStartTime = msg.parentStartTime;
260
    parentExecutionOrderId = msg.parentExecutionOrderId;
261
262 01873262 Georg Kunz
    return *this;
263
}
264
265
void cMessage::_createparlist()
266
{
267
    parlistp = new cArray("parameters", 5, 5);
268
    take(parlistp);
269
}
270
271
void cMessage::setControlInfo(cObject *p)
272
{
273
    if (!p)
274
        throw cRuntimeError(this,"setControlInfo(): pointer is NULL");
275
    if (ctrlp)
276
        throw cRuntimeError(this,"setControlInfo(): message already has control info attached");
277
    if (dynamic_cast<cOwnedObject *>(p))
278
        take((cOwnedObject *)p);
279
    ctrlp = p;
280
}
281
282
cObject *cMessage::removeControlInfo()
283
{
284
    cObject *p = ctrlp;
285
    ctrlp = NULL;
286
    if (dynamic_cast<cOwnedObject *>(p))
287
        drop((cOwnedObject *)p);
288
    return p;
289
}
290
291
cMsgPar& cMessage::par(int n)
292
{
293
    cArray& parlist = getParList();
294
    cObject *p = parlist.get(n);
295
    if (!p)
296
        throw cRuntimeError(this,"par(int): has no parameter #%d",n);
297
    if (!dynamic_cast<cMsgPar *>(p))
298
        throw cRuntimeError(this,"par(int): parameter #%d is of type %s, not cMsgPar",n, p->getClassName());
299
    return *(cMsgPar *)p;
300
}
301
302
cMsgPar& cMessage::par(const char *s)
303
{
304
    cArray& parlist = getParList();
305
    cObject *p = parlist.get(s);
306
    if (!p)
307
        throw cRuntimeError(this,"par(const char *): has no parameter called `%s'",s);
308
    if (!dynamic_cast<cMsgPar *>(p))
309
        throw cRuntimeError(this,"par(const char *): parameter `%s' is of type %s, not cMsgPar",s, p->getClassName());
310
    return *(cMsgPar *)p;
311
}
312
313
int cMessage::findPar(const char *s) const
314
{
315
    return !parlistp ? -1 : parlistp->find(s);
316
}
317
318
cGate *cMessage::getSenderGate() const
319
{
320
    if (frommod<0 || fromgate<0)  return NULL;
321
    cModule *mod = simulation.getModule(frommod);
322
    return !mod ? NULL : mod->gate(fromgate);
323
}
324
325
cGate *cMessage::getArrivalGate() const
326
{
327
    if (tomod<0 || togate<0)  return NULL;
328
    cModule *mod = simulation.getModule(tomod);
329
    return !mod ? NULL : mod->gate(togate);
330
}
331
332
bool cMessage::arrivedOn(const char *gatename) const
333
{
334
    cGate *arrgate = getArrivalGate();
335
    return arrgate && arrgate->isName(gatename);
336
}
337
338
bool cMessage::arrivedOn(const char *gatename, int gateindex) const
339
{
340
    cGate *arrgate = getArrivalGate();
341
    return arrgate && arrgate->isName(gatename) && arrgate->getIndex()==gateindex;
342
}
343
344
const char *cMessage::getDisplayString() const
345
{
346
    return ""; // clients may redefine this method to get messages with custom appearance
347
}
348
349
void cMessage::setSentFrom(cModule *module, int gateId, simtime_t_cref t)
350
{
351
    frommod = module ? module->getId() : -1;
352
    fromgate = gateId;
353
    sent = t;
354
}
355
356
void cMessage::setArrival(cModule *module, int gateId, simtime_t_cref t)
357
{
358
    tomod = module ? module->getId() : -1;
359
    togate = gateId;
360
    delivd = t;
361
}
362
363
void cMessage::setArrival(cModule *module, int gateId)
364
{
365
    tomod = module ? module->getId() : -1;
366
    togate = gateId;
367
}
368
369
void cMessage::setArrivalTime(simtime_t t)
370
{
371
    delivd = t;
372
}
373
374 96e929a8 Simon Tenbusch
simtime_t cMessage::getEventDuration() {
375 cbd2c699 Mirko Stoffers
    if (eventDuration == SimTime::simTimeUninitialized) {
376 96e929a8 Simon Tenbusch
        cSimpleModule* mod = (cSimpleModule*) simulation.getModule(getArrivalModuleId());
377 fbe00e73 Mirko Stoffers
        if (mod) {
378 0e7ff5c8 Simon Tenbusch
            // block if another thread is busy inside this module
379
            // then set the module to busy
380
            // this must only be unset after the corresponding event has been processed,
381
            // since otherwise the return value of getProcessingDelay is not deterministically determined
382
            // (in the mean time there may have been other events, changing the outcome of getProcessingDelay)
383 fbe00e73 Mirko Stoffers
            mod->waitIfBusy();
384
            mod->setBusy();
385 cbd2c699 Mirko Stoffers
            eventDuration = mod->getProcessingDelay(this);
386 96e929a8 Simon Tenbusch
        }
387
    }
388 cbd2c699 Mirko Stoffers
    return eventDuration;
389 96e929a8 Simon Tenbusch
}
390
391 01873262 Georg Kunz
//----
392
393
cPacket::cPacket(const cPacket& pkt) : cMessage(pkt)
394
{
395
    encapmsg = NULL;
396
    sharecount = 0;
397
    operator=(pkt);
398
}
399
400
cPacket::cPacket(const char *name, short k, int64 l) : cMessage(name, k)
401
{
402
    len = l;
403
    encapmsg = NULL;
404 cbd2c699 Mirko Stoffers
    eventDuration = 0;
405 01873262 Georg Kunz
    sharecount = 0;
406
}
407
408
cPacket::~cPacket()
409
{
410
#ifdef WITHOUT_CPACKET
411
    EVCB.messageDeleted(this);
412
#endif
413
414
    if (encapmsg)
415
#ifdef REFCOUNTING
416
        _deleteEncapMsg();
417
#else
418
        dropAndDelete(encapmsg);
419
#endif
420
}
421
422
std::string cPacket::info() const  //FIXME revise
423
{
424
//    if (tomod<0)
425
//        return std::string("(new msg)");
426
427
    std::stringstream out;
428
//    const char *deletedstr = "<deleted module>";
429
//
430
//    if (delivd > simulation.getSimTime())
431
//    {
432
//        // if it arrived in the past, dt is usually unimportant, don't print it
433
//        out << "at T=" << delivd << ", in dt=" << (delivd - simulation.getSimTime()) << "; ";
434
//    }
435
//
436
//#define MODNAME(modp) ((modp) ? (modp)->getFullPath().c_str() : deletedstr)
437
//    if (getKind()==MK_STARTER)
438
//    {
439
//        cModule *tomodp = simulation.getModule(tomod);
440
//        out << "starter for " << MODNAME(tomodp) << " (id=" << tomod << ") ";
441
//    }
442
//    else if (getKind()==MK_TIMEOUT)
443
//    {
444
//        cModule *tomodp = simulation.getModule(tomod);
445
//        out << "timeoutmsg for " << MODNAME(tomodp) << " (id=" << tomod << ") ";
446
//    }
447
//    else if (frommod==tomod)
448
//    {
449
//        cModule *tomodp = simulation.getModule(tomod);
450
//        out << "selfmsg for " << MODNAME(tomodp) << " (id=" << tomod << ") ";
451
//    }
452
//    else
453
//    {
454
//        cModule *frommodp = simulation.getModule(frommod);
455
//        cModule *tomodp = simulation.getModule(tomod);
456
//        out << "src=" << MODNAME(frommodp) << " (id=" << frommod << ") ";
457
//        out << " dest=" << MODNAME(tomodp) << " (id=" << tomod << ") ";
458
//    }
459
//#undef MODNAME
460
//
461
//    if (encapmsg)
462
//        // #ifdef REFCOUNTING const_cast<cPacket *>(this)->_detachEncapMsg();  // see _detachEncapMsg() comment why this might be needed
463
//        out << "  encapsulates: (" << encapmsg->getClassName() << ")" << encapmsg->getFullName();
464
//
465
//    if (ctrlp)
466
//        out << "  control info: (" << ctrlp->getClassName() << ") " << ctrlp->getFullName() << "\n";
467
//
468
    return out.str();
469
}
470
471
void cPacket::forEachChild(cVisitor *v)
472
{
473
    cMessage::forEachChild(v);
474
475
    if (encapmsg)
476
    {
477
#ifdef REFCOUNTING
478
        _detachEncapMsg();  // see method comment why this is needed
479
#endif
480
        v->visit(encapmsg);
481
    }
482
}
483
484
std::string cPacket::detailedInfo() const
485
{
486
    return "";  // all fields are available via reflection, no point in repeating them here
487
}
488
489
void cPacket::parsimPack(cCommBuffer *buffer)
490
{
491
#ifndef WITH_PARSIM
492
    throw cRuntimeError(this,eNOPARSIM);
493
#else
494
    cMessage::parsimPack(buffer);
495
    buffer->pack(len);
496
    buffer->pack(duration);
497
    if (buffer->packFlag(encapmsg!=NULL))
498
        buffer->packObject(encapmsg);
499
#endif
500
}
501
502
void cPacket::parsimUnpack(cCommBuffer *buffer)
503
{
504
#ifndef WITH_PARSIM
505
    throw cRuntimeError(this,eNOPARSIM);
506
#else
507
    ASSERT(sharecount==0);
508
    cMessage::parsimUnpack(buffer);
509
    buffer->unpack(len);
510
    buffer->unpack(duration);
511
    if (buffer->checkFlag())
512
        take(encapmsg = (cPacket *) buffer->unpackObject());
513
#endif
514
}
515
516
cPacket& cPacket::operator=(const cPacket& msg)
517
{
518
    if (this==&msg) return *this;
519
520
    cMessage::operator=(msg);
521
522
#ifdef REFCOUNTING
523
    if (sharecount!=0)
524
        throw cRuntimeError(this,"operator=(): this message is refcounted (shared between "
525
                                 "several messages), it is forbidden to change it");
526
#endif
527
528
    len = msg.len;
529
    duration = msg.duration;
530
531
#ifndef REFCOUNTING
532
    dropAndDelete(encapmsg);
533
    if (msg.encapmsg)
534
        take(encapmsg = (cPacket *)msg.encapmsg->dup());
535
    else
536
        encapmsg = NULL;
537
#else
538
    if (encapmsg)
539
        _deleteEncapMsg();
540
    encapmsg = msg.encapmsg;
541
    if (encapmsg && ++encapmsg->sharecount==0)   // sharecount overflow
542
    {
543
        --encapmsg->sharecount;
544
        take(encapmsg = (cPacket *)encapmsg->dup());
545
    }
546
#endif
547
548
    return *this;
549
}
550
551
#ifdef REFCOUNTING
552
void cPacket::_deleteEncapMsg()
553
{
554
    if (encapmsg->sharecount>0)
555
    {
556
        encapmsg->sharecount--;
557
        if (encapmsg->ownerp == this)
558
            encapmsg->ownerp = NULL;
559
    }
560
    else
561
    {
562
        // note: dropAndDelete(encapmsg) cannot be used, because due to sharecounting
563
        // ownerp is not valid (may be any former owner, possibly deleted since then)
564
        encapmsg->ownerp = NULL;
565
        delete encapmsg;
566
    }
567
}
568
#endif
569
570
#ifdef REFCOUNTING
571
void cPacket::_detachEncapMsg()
572
{
573
    if (encapmsg->sharecount>0)
574
    {
575
        // "de-share" object - create our own copy
576
        encapmsg->sharecount--;
577
        if (encapmsg->ownerp == this)
578
            encapmsg->ownerp = NULL;
579
        take(encapmsg = (cPacket *)encapmsg->dup());
580
    }
581
    else
582
    {
583
        // note: due to sharecounting, ownerp may be pointing to a previous owner -- fix it
584
        encapmsg->ownerp = this;
585
    }
586
}
587
#endif
588
589
void cPacket::setBitLength(int64 l)
590
{
591
    if (l<0)
592
        throw cRuntimeError(this,"setBitLength(): negative length %"INT64_PRINTF_FORMAT"d", l);
593
    len = l;
594
}
595
596
void cPacket::addBitLength(int64 l)
597
{
598
    len += l;
599
    if (len<0)
600
        throw cRuntimeError(this,"addBitLength(): length became negative (%"INT64_PRINTF_FORMAT") after adding %"INT64_PRINTF_FORMAT"d", len, l);
601
}
602
603
void cPacket::encapsulate(cPacket *msg)
604
{
605
    if (encapmsg)
606
        throw cRuntimeError(this,"encapsulate(): another message already encapsulated");
607
608
    if (msg)
609
    {
610
        if (msg->getOwner()!=simulation.getContextSimpleModule())
611
            throw cRuntimeError(this,"encapsulate(): not owner of message (%s)%s, owner is (%s)%s",
612
                                msg->getClassName(), msg->getFullName(),
613
                                msg->getOwner()->getClassName(), msg->getOwner()->getFullPath().c_str());
614
        take(encapmsg = msg);
615
#ifdef REFCOUNTING
616
        ASSERT(encapmsg->sharecount==0);
617
#endif
618
        len += encapmsg->len;
619
    }
620
}
621
622
cPacket *cPacket::decapsulate()
623
{
624
    if (!encapmsg)
625
        return NULL;
626
    if (len>0)
627
        len -= encapmsg->len;
628
    if (len<0)
629
        throw cRuntimeError(this,"decapsulate(): packet length is smaller than encapsulated packet");
630
631
#ifdef REFCOUNTING
632
    if (encapmsg->sharecount>0)
633
    {
634
        encapmsg->sharecount--;
635
        if (encapmsg->ownerp == this)
636
            encapmsg->ownerp = NULL;
637
        cPacket *msg = encapmsg->dup();
638
        encapmsg = NULL;
639
        return msg;
640
    }
641
    encapmsg->ownerp = this;
642
#endif
643
    cPacket *msg = encapmsg;
644
    encapmsg = NULL;
645
    if (msg) drop(msg);
646
    return msg;
647
}
648
649
cPacket *cPacket::getEncapsulatedPacket() const
650
{
651
#ifdef REFCOUNTING
652
    // encapmsg may be shared (sharecount>0) -- we'll make our own copy,
653
    // so that other messages are not affected in case the user modifies
654
    // the encapsulated message via the returned pointer.
655
    // Trick: this is a const method, so we can only do changes via a
656
    // non-const copy of the 'this' pointer.
657
    if (encapmsg)
658
        const_cast<cPacket *>(this)->_detachEncapMsg();
659
#endif
660
    return encapmsg;
661
}
662
663
long cPacket::getEncapsulationId() const
664
{
665
    // find innermost msg. Note: don't use getEncapsulatedPacket() because it does copy-on-touch of shared msgs
666
    const cPacket *msg = this;
667
    while (msg->encapmsg)
668
        msg = msg->encapmsg;
669
    return msg->getId();
670
}
671
672
long cPacket::getEncapsulationTreeId() const
673
{
674
    // find innermost msg. Note: don't use getEncapsulatedPacket() because it does copy-on-touch of shared msgs
675
    const cPacket *msg = this;
676
    while (msg->encapmsg)
677
        msg = msg->encapmsg;
678
    return msg->getTreeId();
679
}
680
681
682