Project

General

Profile

Statistics
| Branch: | Revision:

root / src / sim / cmessage.cc @ 0e7ff5c8

History | View | Annotate | Download (17.5 KB)

1
//========================================================================
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
#include "casyncmodule.h"
31

    
32
#ifdef WITH_PARSIM
33
#include "ccommbuffer.h"
34
#endif
35

    
36
USING_NAMESPACE
37

    
38
// comment out to disable reference-counting for encapsulated messages
39
#define REFCOUNTING
40

    
41
using std::ostream;
42

    
43
#ifdef WITHOUT_CPACKET
44
#undef cMessage
45
#endif
46

    
47
Register_Class(cMessage);
48
Register_Class(cPacket);
49

    
50
// static members of cMessage
51
AO_t cMessage::next_id = 0;
52
AO_t cMessage::total_msgs = 0;
53
AO_t cMessage::live_msgs = 0;
54

    
55
cMessage::cMessage(const cMessage& msg) : cOwnedObject(msg)
56
{
57
    parlistp = NULL;
58
    ctrlp = NULL;
59
    heapindex = -1;
60
    prev_event_num = -1;
61
    operator=(msg);
62

    
63
    msgid = AO_fetch_and_add1(&next_id);
64
    AO_fetch_and_add1(&total_msgs);
65
    AO_fetch_and_add1(&live_msgs);
66

    
67
    schedulingOrderId = 0;
68
}
69

    
70
cMessage::cMessage(const char *name, short k) : cOwnedObject(name, false)
71
{
72
    // name pooling is off for messages by default, as unique names are quite common
73
    msgkind = k;
74
    prior = 0;
75
    parlistp = NULL;
76
    contextptr = NULL;
77
    ctrlp = NULL;
78
    srcprocid = -1;
79

    
80
    frommod = fromgate = -1;
81
    tomod = togate = -1;
82
    created = simulation.getSimTime();
83
    sent = delivd = tstamp = 0;
84
    heapindex = -1;
85
    prev_event_num = -1;
86

    
87
    duration = SimTime::simTimeUninitialized;
88
    msgtreeid = msgid = AO_fetch_and_add1(&next_id);
89
    AO_fetch_and_add1(&total_msgs);
90
    AO_fetch_and_add1(&live_msgs);
91

    
92
    parentStartTime = SimTime::simTimeZero;
93
    parentExecutionOrderId = 0;
94
    schedulingOrderId = 0;
95
}
96

    
97
cMessage::~cMessage()
98
{
99
#ifndef WITHOUT_CPACKET
100
    EVCB.messageDeleted(this);
101
#endif
102

    
103
    if (parlistp)
104
        dropAndDelete(parlistp);
105

    
106
    if (ctrlp) {
107
        if (ctrlp->isOwnedObject())
108
            dropAndDelete(static_cast<cOwnedObject *>(ctrlp));
109
        else
110
            delete ctrlp;
111
    }
112
    AO_fetch_and_sub1(&live_msgs);
113
}
114

    
115
std::string cMessage::info() const
116
{
117
    if (tomod<0)
118
        return std::string("(new msg)");
119

    
120
    std::stringstream out;
121
    const char *deletedstr = "<deleted module>";
122

    
123
    if (delivd > simulation.getSimTime())
124
    {
125
        // if it arrived in the past, dt is usually unimportant, don't print it
126
        out << "at T=" << delivd << ", in dt=" << (delivd - simulation.getSimTime()) << "; ";
127
    }
128

    
129
#define MODNAME(modp) ((modp) ? (modp)->getFullPath().c_str() : deletedstr)
130
    if (getKind()==MK_STARTER)
131
    {
132
        cModule *tomodp = simulation.getModule(tomod);
133
        out << "starter for " << MODNAME(tomodp) << " (id=" << tomod << ") ";
134
    }
135
    else if (getKind()==MK_TIMEOUT)
136
    {
137
        cModule *tomodp = simulation.getModule(tomod);
138
        out << "timeoutmsg for " << MODNAME(tomodp) << " (id=" << tomod << ") ";
139
    }
140
    else if (frommod==tomod)
141
    {
142
        cModule *tomodp = simulation.getModule(tomod);
143
        out << "selfmsg for " << MODNAME(tomodp) << " (id=" << tomod << ") ";
144
    }
145
    else
146
    {
147
        cModule *frommodp = simulation.getModule(frommod);
148
        cModule *tomodp = simulation.getModule(tomod);
149
        out << "src=" << MODNAME(frommodp) << " (id=" << frommod << ") ";
150
        out << " dest=" << MODNAME(tomodp) << " (id=" << tomod << ") ";
151
    }
152
#undef MODNAME
153

    
154
    if (ctrlp)
155
        out << "  control info: (" << ctrlp->getClassName() << ") " << ctrlp->getFullName() << "\n";
156

    
157
    return out.str();
158
}
159

    
160
void cMessage::forEachChild(cVisitor *v)
161
{
162
    if (parlistp)
163
        v->visit(parlistp);
164
}
165

    
166
std::string cMessage::detailedInfo() const
167
{
168
    return "";  // all fields are available via reflection, no point in repeating them here
169
}
170

    
171
void cMessage::parsimPack(cCommBuffer *buffer)
172
{
173
#ifndef WITH_PARSIM
174
    throw cRuntimeError(this,eNOPARSIM);
175
#else
176
    cOwnedObject::parsimPack(buffer);
177

    
178
    if (contextptr || ctrlp)
179
        throw cRuntimeError(this,"parsimPack(): cannot pack object with contextPointer or controlInfo set");
180

    
181
    buffer->pack(msgkind);
182
    buffer->pack(prior);
183
    buffer->pack(tstamp);
184

    
185
    buffer->pack(frommod);
186
    buffer->pack(fromgate);
187
    buffer->pack(tomod);
188
    buffer->pack(togate);
189
    buffer->pack(created);
190
    buffer->pack(sent);
191
    buffer->pack(delivd);
192
    buffer->pack(heapindex);
193
    buffer->pack(insertordr);
194

    
195
    // note: do not pack msgid and treeid, because they'd conflict
196
    // with ids assigned at the destination partition
197

    
198
    if (buffer->packFlag(parlistp!=NULL))
199
        buffer->packObject(parlistp);
200
#endif
201
}
202

    
203
void cMessage::parsimUnpack(cCommBuffer *buffer)
204
{
205
#ifndef WITH_PARSIM
206
    throw cRuntimeError(this,eNOPARSIM);
207
#else
208
    cOwnedObject::parsimUnpack(buffer);
209

    
210
    buffer->unpack(msgkind);
211
    buffer->unpack(prior);
212
    buffer->unpack(tstamp);
213

    
214
    buffer->unpack(frommod);
215
    buffer->unpack(fromgate);
216
    buffer->unpack(tomod);
217
    buffer->unpack(togate);
218
    buffer->unpack(created);
219
    buffer->unpack(sent);
220
    buffer->unpack(delivd);
221
    buffer->unpack(heapindex);
222
    buffer->unpack(insertordr);
223

    
224
    if (buffer->checkFlag())
225
        take(parlistp = (cArray *) buffer->unpackObject());
226
#endif
227
}
228

    
229
cMessage& cMessage::operator=(const cMessage& msg)
230
{
231
    if (this==&msg) return *this;
232

    
233
    cOwnedObject::operator=(msg);
234

    
235
    msgkind = msg.msgkind;
236
    prior = msg.prior;
237
    tstamp = msg.tstamp;
238
    srcprocid = msg.srcprocid;
239

    
240
    created = msg.created;
241

    
242
    dropAndDelete(parlistp);
243
    if (msg.parlistp)
244
        take(parlistp = (cArray *)msg.parlistp->dup());
245
    else
246
        parlistp = NULL;
247

    
248
    contextptr = msg.contextptr;
249

    
250
    frommod = msg.frommod;
251
    fromgate = msg.fromgate;
252
    tomod = msg.tomod;
253
    togate = msg.togate;
254

    
255
    sent = msg.sent;
256
    delivd = msg.delivd;
257

    
258
    msgtreeid = msg.msgtreeid;
259

    
260
    parentStartTime = msg.parentStartTime;
261
    parentExecutionOrderId = msg.parentExecutionOrderId;
262

    
263
    return *this;
264
}
265

    
266
void cMessage::_createparlist()
267
{
268
    parlistp = new cArray("parameters", 5, 5);
269
    take(parlistp);
270
}
271

    
272
void cMessage::setControlInfo(cObject *p)
273
{
274
    if (!p)
275
        throw cRuntimeError(this,"setControlInfo(): pointer is NULL");
276
    if (ctrlp)
277
        throw cRuntimeError(this,"setControlInfo(): message already has control info attached");
278
    if (dynamic_cast<cOwnedObject *>(p))
279
        take((cOwnedObject *)p);
280
    ctrlp = p;
281
}
282

    
283
cObject *cMessage::removeControlInfo()
284
{
285
    cObject *p = ctrlp;
286
    ctrlp = NULL;
287
    if (dynamic_cast<cOwnedObject *>(p))
288
        drop((cOwnedObject *)p);
289
    return p;
290
}
291

    
292
cMsgPar& cMessage::par(int n)
293
{
294
    cArray& parlist = getParList();
295
    cObject *p = parlist.get(n);
296
    if (!p)
297
        throw cRuntimeError(this,"par(int): has no parameter #%d",n);
298
    if (!dynamic_cast<cMsgPar *>(p))
299
        throw cRuntimeError(this,"par(int): parameter #%d is of type %s, not cMsgPar",n, p->getClassName());
300
    return *(cMsgPar *)p;
301
}
302

    
303
cMsgPar& cMessage::par(const char *s)
304
{
305
    cArray& parlist = getParList();
306
    cObject *p = parlist.get(s);
307
    if (!p)
308
        throw cRuntimeError(this,"par(const char *): has no parameter called `%s'",s);
309
    if (!dynamic_cast<cMsgPar *>(p))
310
        throw cRuntimeError(this,"par(const char *): parameter `%s' is of type %s, not cMsgPar",s, p->getClassName());
311
    return *(cMsgPar *)p;
312
}
313

    
314
int cMessage::findPar(const char *s) const
315
{
316
    return !parlistp ? -1 : parlistp->find(s);
317
}
318

    
319
cGate *cMessage::getSenderGate() const
320
{
321
    if (frommod<0 || fromgate<0)  return NULL;
322
    cModule *mod = simulation.getModule(frommod);
323
    return !mod ? NULL : mod->gate(fromgate);
324
}
325

    
326
cGate *cMessage::getArrivalGate() const
327
{
328
    if (tomod<0 || togate<0)  return NULL;
329
    cModule *mod = simulation.getModule(tomod);
330
    return !mod ? NULL : mod->gate(togate);
331
}
332

    
333
bool cMessage::arrivedOn(const char *gatename) const
334
{
335
    cGate *arrgate = getArrivalGate();
336
    return arrgate && arrgate->isName(gatename);
337
}
338

    
339
bool cMessage::arrivedOn(const char *gatename, int gateindex) const
340
{
341
    cGate *arrgate = getArrivalGate();
342
    return arrgate && arrgate->isName(gatename) && arrgate->getIndex()==gateindex;
343
}
344

    
345
const char *cMessage::getDisplayString() const
346
{
347
    return ""; // clients may redefine this method to get messages with custom appearance
348
}
349

    
350
void cMessage::setSentFrom(cModule *module, int gateId, simtime_t_cref t)
351
{
352
    frommod = module ? module->getId() : -1;
353
    fromgate = gateId;
354
    sent = t;
355
}
356

    
357
void cMessage::setArrival(cModule *module, int gateId, simtime_t_cref t)
358
{
359
    tomod = module ? module->getId() : -1;
360
    togate = gateId;
361
    delivd = t;
362
}
363

    
364
void cMessage::setArrival(cModule *module, int gateId)
365
{
366
    tomod = module ? module->getId() : -1;
367
    togate = gateId;
368
}
369

    
370
void cMessage::setArrivalTime(simtime_t t)
371
{
372
    delivd = t;
373
}
374

    
375
simtime_t cMessage::getEventDuration() {
376
    if (duration == SimTime::simTimeUninitialized) {
377
        cSimpleModule* mod = (cSimpleModule*) simulation.getModule(getArrivalModuleId());
378
        if (mod && mod->isAsyncModule()) {
379
            // block if another thread is busy inside this module
380
            // then set the module to busy
381
            // this must only be unset after the corresponding event has been processed,
382
            // since otherwise the return value of getProcessingDelay is not deterministically determined
383
            // (in the mean time there may have been other events, changing the outcome of getProcessingDelay)
384
            ((cAsyncModule*) mod)->waitIfBusy();
385
            ((cAsyncModule*) mod)->setBusy();
386
            duration = ((cAsyncModule*) mod)->getProcessingDelay(this);
387
        }
388
    }
389
    return duration;
390
}
391

    
392
//----
393

    
394
cPacket::cPacket(const cPacket& pkt) : cMessage(pkt)
395
{
396
    encapmsg = NULL;
397
    sharecount = 0;
398
    operator=(pkt);
399
}
400

    
401
cPacket::cPacket(const char *name, short k, int64 l) : cMessage(name, k)
402
{
403
    len = l;
404
    encapmsg = NULL;
405
    duration = 0;
406
    sharecount = 0;
407
}
408

    
409
cPacket::~cPacket()
410
{
411
#ifdef WITHOUT_CPACKET
412
    EVCB.messageDeleted(this);
413
#endif
414

    
415
    if (encapmsg)
416
#ifdef REFCOUNTING
417
        _deleteEncapMsg();
418
#else
419
        dropAndDelete(encapmsg);
420
#endif
421
}
422

    
423
std::string cPacket::info() const  //FIXME revise
424
{
425
//    if (tomod<0)
426
//        return std::string("(new msg)");
427

    
428
    std::stringstream out;
429
//    const char *deletedstr = "<deleted module>";
430
//
431
//    if (delivd > simulation.getSimTime())
432
//    {
433
//        // if it arrived in the past, dt is usually unimportant, don't print it
434
//        out << "at T=" << delivd << ", in dt=" << (delivd - simulation.getSimTime()) << "; ";
435
//    }
436
//
437
//#define MODNAME(modp) ((modp) ? (modp)->getFullPath().c_str() : deletedstr)
438
//    if (getKind()==MK_STARTER)
439
//    {
440
//        cModule *tomodp = simulation.getModule(tomod);
441
//        out << "starter for " << MODNAME(tomodp) << " (id=" << tomod << ") ";
442
//    }
443
//    else if (getKind()==MK_TIMEOUT)
444
//    {
445
//        cModule *tomodp = simulation.getModule(tomod);
446
//        out << "timeoutmsg for " << MODNAME(tomodp) << " (id=" << tomod << ") ";
447
//    }
448
//    else if (frommod==tomod)
449
//    {
450
//        cModule *tomodp = simulation.getModule(tomod);
451
//        out << "selfmsg for " << MODNAME(tomodp) << " (id=" << tomod << ") ";
452
//    }
453
//    else
454
//    {
455
//        cModule *frommodp = simulation.getModule(frommod);
456
//        cModule *tomodp = simulation.getModule(tomod);
457
//        out << "src=" << MODNAME(frommodp) << " (id=" << frommod << ") ";
458
//        out << " dest=" << MODNAME(tomodp) << " (id=" << tomod << ") ";
459
//    }
460
//#undef MODNAME
461
//
462
//    if (encapmsg)
463
//        // #ifdef REFCOUNTING const_cast<cPacket *>(this)->_detachEncapMsg();  // see _detachEncapMsg() comment why this might be needed
464
//        out << "  encapsulates: (" << encapmsg->getClassName() << ")" << encapmsg->getFullName();
465
//
466
//    if (ctrlp)
467
//        out << "  control info: (" << ctrlp->getClassName() << ") " << ctrlp->getFullName() << "\n";
468
//
469
    return out.str();
470
}
471

    
472
void cPacket::forEachChild(cVisitor *v)
473
{
474
    cMessage::forEachChild(v);
475

    
476
    if (encapmsg)
477
    {
478
#ifdef REFCOUNTING
479
        _detachEncapMsg();  // see method comment why this is needed
480
#endif
481
        v->visit(encapmsg);
482
    }
483
}
484

    
485
std::string cPacket::detailedInfo() const
486
{
487
    return "";  // all fields are available via reflection, no point in repeating them here
488
}
489

    
490
void cPacket::parsimPack(cCommBuffer *buffer)
491
{
492
#ifndef WITH_PARSIM
493
    throw cRuntimeError(this,eNOPARSIM);
494
#else
495
    cMessage::parsimPack(buffer);
496
    buffer->pack(len);
497
    buffer->pack(duration);
498
    if (buffer->packFlag(encapmsg!=NULL))
499
        buffer->packObject(encapmsg);
500
#endif
501
}
502

    
503
void cPacket::parsimUnpack(cCommBuffer *buffer)
504
{
505
#ifndef WITH_PARSIM
506
    throw cRuntimeError(this,eNOPARSIM);
507
#else
508
    ASSERT(sharecount==0);
509
    cMessage::parsimUnpack(buffer);
510
    buffer->unpack(len);
511
    buffer->unpack(duration);
512
    if (buffer->checkFlag())
513
        take(encapmsg = (cPacket *) buffer->unpackObject());
514
#endif
515
}
516

    
517
cPacket& cPacket::operator=(const cPacket& msg)
518
{
519
    if (this==&msg) return *this;
520

    
521
    cMessage::operator=(msg);
522

    
523
#ifdef REFCOUNTING
524
    if (sharecount!=0)
525
        throw cRuntimeError(this,"operator=(): this message is refcounted (shared between "
526
                                 "several messages), it is forbidden to change it");
527
#endif
528

    
529
    len = msg.len;
530
    duration = msg.duration;
531

    
532
#ifndef REFCOUNTING
533
    dropAndDelete(encapmsg);
534
    if (msg.encapmsg)
535
        take(encapmsg = (cPacket *)msg.encapmsg->dup());
536
    else
537
        encapmsg = NULL;
538
#else
539
    if (encapmsg)
540
        _deleteEncapMsg();
541
    encapmsg = msg.encapmsg;
542
    if (encapmsg && ++encapmsg->sharecount==0)   // sharecount overflow
543
    {
544
        --encapmsg->sharecount;
545
        take(encapmsg = (cPacket *)encapmsg->dup());
546
    }
547
#endif
548

    
549
    return *this;
550
}
551

    
552
#ifdef REFCOUNTING
553
void cPacket::_deleteEncapMsg()
554
{
555
    if (encapmsg->sharecount>0)
556
    {
557
        encapmsg->sharecount--;
558
        if (encapmsg->ownerp == this)
559
            encapmsg->ownerp = NULL;
560
    }
561
    else
562
    {
563
        // note: dropAndDelete(encapmsg) cannot be used, because due to sharecounting
564
        // ownerp is not valid (may be any former owner, possibly deleted since then)
565
        encapmsg->ownerp = NULL;
566
        delete encapmsg;
567
    }
568
}
569
#endif
570

    
571
#ifdef REFCOUNTING
572
void cPacket::_detachEncapMsg()
573
{
574
    if (encapmsg->sharecount>0)
575
    {
576
        // "de-share" object - create our own copy
577
        encapmsg->sharecount--;
578
        if (encapmsg->ownerp == this)
579
            encapmsg->ownerp = NULL;
580
        take(encapmsg = (cPacket *)encapmsg->dup());
581
    }
582
    else
583
    {
584
        // note: due to sharecounting, ownerp may be pointing to a previous owner -- fix it
585
        encapmsg->ownerp = this;
586
    }
587
}
588
#endif
589

    
590
void cPacket::setBitLength(int64 l)
591
{
592
    if (l<0)
593
        throw cRuntimeError(this,"setBitLength(): negative length %"INT64_PRINTF_FORMAT"d", l);
594
    len = l;
595
}
596

    
597
void cPacket::addBitLength(int64 l)
598
{
599
    len += l;
600
    if (len<0)
601
        throw cRuntimeError(this,"addBitLength(): length became negative (%"INT64_PRINTF_FORMAT") after adding %"INT64_PRINTF_FORMAT"d", len, l);
602
}
603

    
604
void cPacket::encapsulate(cPacket *msg)
605
{
606
    if (encapmsg)
607
        throw cRuntimeError(this,"encapsulate(): another message already encapsulated");
608

    
609
    if (msg)
610
    {
611
        if (msg->getOwner()!=simulation.getContextSimpleModule())
612
            throw cRuntimeError(this,"encapsulate(): not owner of message (%s)%s, owner is (%s)%s",
613
                                msg->getClassName(), msg->getFullName(),
614
                                msg->getOwner()->getClassName(), msg->getOwner()->getFullPath().c_str());
615
        take(encapmsg = msg);
616
#ifdef REFCOUNTING
617
        ASSERT(encapmsg->sharecount==0);
618
#endif
619
        len += encapmsg->len;
620
    }
621
}
622

    
623
cPacket *cPacket::decapsulate()
624
{
625
    if (!encapmsg)
626
        return NULL;
627
    if (len>0)
628
        len -= encapmsg->len;
629
    if (len<0)
630
        throw cRuntimeError(this,"decapsulate(): packet length is smaller than encapsulated packet");
631

    
632
#ifdef REFCOUNTING
633
    if (encapmsg->sharecount>0)
634
    {
635
        encapmsg->sharecount--;
636
        if (encapmsg->ownerp == this)
637
            encapmsg->ownerp = NULL;
638
        cPacket *msg = encapmsg->dup();
639
        encapmsg = NULL;
640
        return msg;
641
    }
642
    encapmsg->ownerp = this;
643
#endif
644
    cPacket *msg = encapmsg;
645
    encapmsg = NULL;
646
    if (msg) drop(msg);
647
    return msg;
648
}
649

    
650
cPacket *cPacket::getEncapsulatedPacket() const
651
{
652
#ifdef REFCOUNTING
653
    // encapmsg may be shared (sharecount>0) -- we'll make our own copy,
654
    // so that other messages are not affected in case the user modifies
655
    // the encapsulated message via the returned pointer.
656
    // Trick: this is a const method, so we can only do changes via a
657
    // non-const copy of the 'this' pointer.
658
    if (encapmsg)
659
        const_cast<cPacket *>(this)->_detachEncapMsg();
660
#endif
661
    return encapmsg;
662
}
663

    
664
long cPacket::getEncapsulationId() const
665
{
666
    // find innermost msg. Note: don't use getEncapsulatedPacket() because it does copy-on-touch of shared msgs
667
    const cPacket *msg = this;
668
    while (msg->encapmsg)
669
        msg = msg->encapmsg;
670
    return msg->getId();
671
}
672

    
673
long cPacket::getEncapsulationTreeId() const
674
{
675
    // find innermost msg. Note: don't use getEncapsulatedPacket() because it does copy-on-touch of shared msgs
676
    const cPacket *msg = this;
677
    while (msg->encapmsg)
678
        msg = msg->encapmsg;
679
    return msg->getTreeId();
680
}
681

    
682

    
683

    
684