Project

General

Profile

Statistics
| Branch: | Revision:

root / src / sim / cmessage.cc @ 96e929a8

History | View | Annotate | Download (16.7 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

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

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

    
85
    duration = -1;
86
    msgtreeid = msgid = AO_fetch_and_add1(&next_id);
87
    AO_fetch_and_add1(&total_msgs);
88
    AO_fetch_and_add1(&live_msgs);
89
}
90

    
91
cMessage::~cMessage()
92
{
93
#ifndef WITHOUT_CPACKET
94
    EVCB.messageDeleted(this);
95
#endif
96

    
97
    if (parlistp)
98
        dropAndDelete(parlistp);
99

    
100
    if (ctrlp) {
101
        if (ctrlp->isOwnedObject())
102
            dropAndDelete(static_cast<cOwnedObject *>(ctrlp));
103
        else
104
            delete ctrlp;
105
    }
106
    AO_fetch_and_sub1(&live_msgs);
107
}
108

    
109
std::string cMessage::info() const
110
{
111
    if (tomod<0)
112
        return std::string("(new msg)");
113

    
114
    std::stringstream out;
115
    const char *deletedstr = "<deleted module>";
116

    
117
    if (delivd > simulation.getSimTime())
118
    {
119
        // if it arrived in the past, dt is usually unimportant, don't print it
120
        out << "at T=" << delivd << ", in dt=" << (delivd - simulation.getSimTime()) << "; ";
121
    }
122

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

    
148
    if (ctrlp)
149
        out << "  control info: (" << ctrlp->getClassName() << ") " << ctrlp->getFullName() << "\n";
150

    
151
    return out.str();
152
}
153

    
154
void cMessage::forEachChild(cVisitor *v)
155
{
156
    if (parlistp)
157
        v->visit(parlistp);
158
}
159

    
160
std::string cMessage::detailedInfo() const
161
{
162
    return "";  // all fields are available via reflection, no point in repeating them here
163
}
164

    
165
void cMessage::parsimPack(cCommBuffer *buffer)
166
{
167
#ifndef WITH_PARSIM
168
    throw cRuntimeError(this,eNOPARSIM);
169
#else
170
    cOwnedObject::parsimPack(buffer);
171

    
172
    if (contextptr || ctrlp)
173
        throw cRuntimeError(this,"parsimPack(): cannot pack object with contextPointer or controlInfo set");
174

    
175
    buffer->pack(msgkind);
176
    buffer->pack(prior);
177
    buffer->pack(tstamp);
178

    
179
    buffer->pack(frommod);
180
    buffer->pack(fromgate);
181
    buffer->pack(tomod);
182
    buffer->pack(togate);
183
    buffer->pack(created);
184
    buffer->pack(sent);
185
    buffer->pack(delivd);
186
    buffer->pack(heapindex);
187
    buffer->pack(insertordr);
188

    
189
    // note: do not pack msgid and treeid, because they'd conflict
190
    // with ids assigned at the destination partition
191

    
192
    if (buffer->packFlag(parlistp!=NULL))
193
        buffer->packObject(parlistp);
194
#endif
195
}
196

    
197
void cMessage::parsimUnpack(cCommBuffer *buffer)
198
{
199
#ifndef WITH_PARSIM
200
    throw cRuntimeError(this,eNOPARSIM);
201
#else
202
    cOwnedObject::parsimUnpack(buffer);
203

    
204
    buffer->unpack(msgkind);
205
    buffer->unpack(prior);
206
    buffer->unpack(tstamp);
207

    
208
    buffer->unpack(frommod);
209
    buffer->unpack(fromgate);
210
    buffer->unpack(tomod);
211
    buffer->unpack(togate);
212
    buffer->unpack(created);
213
    buffer->unpack(sent);
214
    buffer->unpack(delivd);
215
    buffer->unpack(heapindex);
216
    buffer->unpack(insertordr);
217

    
218
    if (buffer->checkFlag())
219
        take(parlistp = (cArray *) buffer->unpackObject());
220
#endif
221
}
222

    
223
cMessage& cMessage::operator=(const cMessage& msg)
224
{
225
    if (this==&msg) return *this;
226

    
227
    cOwnedObject::operator=(msg);
228

    
229
    msgkind = msg.msgkind;
230
    prior = msg.prior;
231
    tstamp = msg.tstamp;
232
    srcprocid = msg.srcprocid;
233

    
234
    created = msg.created;
235

    
236
    dropAndDelete(parlistp);
237
    if (msg.parlistp)
238
        take(parlistp = (cArray *)msg.parlistp->dup());
239
    else
240
        parlistp = NULL;
241

    
242
    contextptr = msg.contextptr;
243

    
244
    frommod = msg.frommod;
245
    fromgate = msg.fromgate;
246
    tomod = msg.tomod;
247
    togate = msg.togate;
248

    
249
    sent = msg.sent;
250
    delivd = msg.delivd;
251

    
252
    msgtreeid = msg.msgtreeid;
253

    
254
    return *this;
255
}
256

    
257
void cMessage::_createparlist()
258
{
259
    parlistp = new cArray("parameters", 5, 5);
260
    take(parlistp);
261
}
262

    
263
void cMessage::setControlInfo(cObject *p)
264
{
265
    if (!p)
266
        throw cRuntimeError(this,"setControlInfo(): pointer is NULL");
267
    if (ctrlp)
268
        throw cRuntimeError(this,"setControlInfo(): message already has control info attached");
269
    if (dynamic_cast<cOwnedObject *>(p))
270
        take((cOwnedObject *)p);
271
    ctrlp = p;
272
}
273

    
274
cObject *cMessage::removeControlInfo()
275
{
276
    cObject *p = ctrlp;
277
    ctrlp = NULL;
278
    if (dynamic_cast<cOwnedObject *>(p))
279
        drop((cOwnedObject *)p);
280
    return p;
281
}
282

    
283
cMsgPar& cMessage::par(int n)
284
{
285
    cArray& parlist = getParList();
286
    cObject *p = parlist.get(n);
287
    if (!p)
288
        throw cRuntimeError(this,"par(int): has no parameter #%d",n);
289
    if (!dynamic_cast<cMsgPar *>(p))
290
        throw cRuntimeError(this,"par(int): parameter #%d is of type %s, not cMsgPar",n, p->getClassName());
291
    return *(cMsgPar *)p;
292
}
293

    
294
cMsgPar& cMessage::par(const char *s)
295
{
296
    cArray& parlist = getParList();
297
    cObject *p = parlist.get(s);
298
    if (!p)
299
        throw cRuntimeError(this,"par(const char *): has no parameter called `%s'",s);
300
    if (!dynamic_cast<cMsgPar *>(p))
301
        throw cRuntimeError(this,"par(const char *): parameter `%s' is of type %s, not cMsgPar",s, p->getClassName());
302
    return *(cMsgPar *)p;
303
}
304

    
305
int cMessage::findPar(const char *s) const
306
{
307
    return !parlistp ? -1 : parlistp->find(s);
308
}
309

    
310
cGate *cMessage::getSenderGate() const
311
{
312
    if (frommod<0 || fromgate<0)  return NULL;
313
    cModule *mod = simulation.getModule(frommod);
314
    return !mod ? NULL : mod->gate(fromgate);
315
}
316

    
317
cGate *cMessage::getArrivalGate() const
318
{
319
    if (tomod<0 || togate<0)  return NULL;
320
    cModule *mod = simulation.getModule(tomod);
321
    return !mod ? NULL : mod->gate(togate);
322
}
323

    
324
bool cMessage::arrivedOn(const char *gatename) const
325
{
326
    cGate *arrgate = getArrivalGate();
327
    return arrgate && arrgate->isName(gatename);
328
}
329

    
330
bool cMessage::arrivedOn(const char *gatename, int gateindex) const
331
{
332
    cGate *arrgate = getArrivalGate();
333
    return arrgate && arrgate->isName(gatename) && arrgate->getIndex()==gateindex;
334
}
335

    
336
const char *cMessage::getDisplayString() const
337
{
338
    return ""; // clients may redefine this method to get messages with custom appearance
339
}
340

    
341
void cMessage::setSentFrom(cModule *module, int gateId, simtime_t_cref t)
342
{
343
    frommod = module ? module->getId() : -1;
344
    fromgate = gateId;
345
    sent = t;
346
}
347

    
348
void cMessage::setArrival(cModule *module, int gateId, simtime_t_cref t)
349
{
350
    tomod = module ? module->getId() : -1;
351
    togate = gateId;
352
    delivd = t;
353
}
354

    
355
void cMessage::setArrival(cModule *module, int gateId)
356
{
357
    tomod = module ? module->getId() : -1;
358
    togate = gateId;
359
}
360

    
361
void cMessage::setArrivalTime(simtime_t t)
362
{
363
    delivd = t;
364
}
365

    
366
simtime_t cMessage::getEventDuration() {
367
    if (duration < 0) {
368
        cSimpleModule* mod = (cSimpleModule*) simulation.getModule(getArrivalModuleId());
369
        if (mod->isAsyncModule()) {
370
            duration = ((cAsyncModule*) mod)->getProcessingDelay(this);
371
        }
372
    }
373
    return duration;
374
}
375

    
376
//----
377

    
378
cPacket::cPacket(const cPacket& pkt) : cMessage(pkt)
379
{
380
    encapmsg = NULL;
381
    sharecount = 0;
382
    operator=(pkt);
383
}
384

    
385
cPacket::cPacket(const char *name, short k, int64 l) : cMessage(name, k)
386
{
387
    len = l;
388
    encapmsg = NULL;
389
    duration = 0;
390
    sharecount = 0;
391
}
392

    
393
cPacket::~cPacket()
394
{
395
#ifdef WITHOUT_CPACKET
396
    EVCB.messageDeleted(this);
397
#endif
398

    
399
    if (encapmsg)
400
#ifdef REFCOUNTING
401
        _deleteEncapMsg();
402
#else
403
        dropAndDelete(encapmsg);
404
#endif
405
}
406

    
407
std::string cPacket::info() const  //FIXME revise
408
{
409
//    if (tomod<0)
410
//        return std::string("(new msg)");
411

    
412
    std::stringstream out;
413
//    const char *deletedstr = "<deleted module>";
414
//
415
//    if (delivd > simulation.getSimTime())
416
//    {
417
//        // if it arrived in the past, dt is usually unimportant, don't print it
418
//        out << "at T=" << delivd << ", in dt=" << (delivd - simulation.getSimTime()) << "; ";
419
//    }
420
//
421
//#define MODNAME(modp) ((modp) ? (modp)->getFullPath().c_str() : deletedstr)
422
//    if (getKind()==MK_STARTER)
423
//    {
424
//        cModule *tomodp = simulation.getModule(tomod);
425
//        out << "starter for " << MODNAME(tomodp) << " (id=" << tomod << ") ";
426
//    }
427
//    else if (getKind()==MK_TIMEOUT)
428
//    {
429
//        cModule *tomodp = simulation.getModule(tomod);
430
//        out << "timeoutmsg for " << MODNAME(tomodp) << " (id=" << tomod << ") ";
431
//    }
432
//    else if (frommod==tomod)
433
//    {
434
//        cModule *tomodp = simulation.getModule(tomod);
435
//        out << "selfmsg for " << MODNAME(tomodp) << " (id=" << tomod << ") ";
436
//    }
437
//    else
438
//    {
439
//        cModule *frommodp = simulation.getModule(frommod);
440
//        cModule *tomodp = simulation.getModule(tomod);
441
//        out << "src=" << MODNAME(frommodp) << " (id=" << frommod << ") ";
442
//        out << " dest=" << MODNAME(tomodp) << " (id=" << tomod << ") ";
443
//    }
444
//#undef MODNAME
445
//
446
//    if (encapmsg)
447
//        // #ifdef REFCOUNTING const_cast<cPacket *>(this)->_detachEncapMsg();  // see _detachEncapMsg() comment why this might be needed
448
//        out << "  encapsulates: (" << encapmsg->getClassName() << ")" << encapmsg->getFullName();
449
//
450
//    if (ctrlp)
451
//        out << "  control info: (" << ctrlp->getClassName() << ") " << ctrlp->getFullName() << "\n";
452
//
453
    return out.str();
454
}
455

    
456
void cPacket::forEachChild(cVisitor *v)
457
{
458
    cMessage::forEachChild(v);
459

    
460
    if (encapmsg)
461
    {
462
#ifdef REFCOUNTING
463
        _detachEncapMsg();  // see method comment why this is needed
464
#endif
465
        v->visit(encapmsg);
466
    }
467
}
468

    
469
std::string cPacket::detailedInfo() const
470
{
471
    return "";  // all fields are available via reflection, no point in repeating them here
472
}
473

    
474
void cPacket::parsimPack(cCommBuffer *buffer)
475
{
476
#ifndef WITH_PARSIM
477
    throw cRuntimeError(this,eNOPARSIM);
478
#else
479
    cMessage::parsimPack(buffer);
480
    buffer->pack(len);
481
    buffer->pack(duration);
482
    if (buffer->packFlag(encapmsg!=NULL))
483
        buffer->packObject(encapmsg);
484
#endif
485
}
486

    
487
void cPacket::parsimUnpack(cCommBuffer *buffer)
488
{
489
#ifndef WITH_PARSIM
490
    throw cRuntimeError(this,eNOPARSIM);
491
#else
492
    ASSERT(sharecount==0);
493
    cMessage::parsimUnpack(buffer);
494
    buffer->unpack(len);
495
    buffer->unpack(duration);
496
    if (buffer->checkFlag())
497
        take(encapmsg = (cPacket *) buffer->unpackObject());
498
#endif
499
}
500

    
501
cPacket& cPacket::operator=(const cPacket& msg)
502
{
503
    if (this==&msg) return *this;
504

    
505
    cMessage::operator=(msg);
506

    
507
#ifdef REFCOUNTING
508
    if (sharecount!=0)
509
        throw cRuntimeError(this,"operator=(): this message is refcounted (shared between "
510
                                 "several messages), it is forbidden to change it");
511
#endif
512

    
513
    len = msg.len;
514
    duration = msg.duration;
515

    
516
#ifndef REFCOUNTING
517
    dropAndDelete(encapmsg);
518
    if (msg.encapmsg)
519
        take(encapmsg = (cPacket *)msg.encapmsg->dup());
520
    else
521
        encapmsg = NULL;
522
#else
523
    if (encapmsg)
524
        _deleteEncapMsg();
525
    encapmsg = msg.encapmsg;
526
    if (encapmsg && ++encapmsg->sharecount==0)   // sharecount overflow
527
    {
528
        --encapmsg->sharecount;
529
        take(encapmsg = (cPacket *)encapmsg->dup());
530
    }
531
#endif
532

    
533
    return *this;
534
}
535

    
536
#ifdef REFCOUNTING
537
void cPacket::_deleteEncapMsg()
538
{
539
    if (encapmsg->sharecount>0)
540
    {
541
        encapmsg->sharecount--;
542
        if (encapmsg->ownerp == this)
543
            encapmsg->ownerp = NULL;
544
    }
545
    else
546
    {
547
        // note: dropAndDelete(encapmsg) cannot be used, because due to sharecounting
548
        // ownerp is not valid (may be any former owner, possibly deleted since then)
549
        encapmsg->ownerp = NULL;
550
        delete encapmsg;
551
    }
552
}
553
#endif
554

    
555
#ifdef REFCOUNTING
556
void cPacket::_detachEncapMsg()
557
{
558
    if (encapmsg->sharecount>0)
559
    {
560
        // "de-share" object - create our own copy
561
        encapmsg->sharecount--;
562
        if (encapmsg->ownerp == this)
563
            encapmsg->ownerp = NULL;
564
        take(encapmsg = (cPacket *)encapmsg->dup());
565
    }
566
    else
567
    {
568
        // note: due to sharecounting, ownerp may be pointing to a previous owner -- fix it
569
        encapmsg->ownerp = this;
570
    }
571
}
572
#endif
573

    
574
void cPacket::setBitLength(int64 l)
575
{
576
    if (l<0)
577
        throw cRuntimeError(this,"setBitLength(): negative length %"INT64_PRINTF_FORMAT"d", l);
578
    len = l;
579
}
580

    
581
void cPacket::addBitLength(int64 l)
582
{
583
    len += l;
584
    if (len<0)
585
        throw cRuntimeError(this,"addBitLength(): length became negative (%"INT64_PRINTF_FORMAT") after adding %"INT64_PRINTF_FORMAT"d", len, l);
586
}
587

    
588
void cPacket::encapsulate(cPacket *msg)
589
{
590
    if (encapmsg)
591
        throw cRuntimeError(this,"encapsulate(): another message already encapsulated");
592

    
593
    if (msg)
594
    {
595
        if (msg->getOwner()!=simulation.getContextSimpleModule())
596
            throw cRuntimeError(this,"encapsulate(): not owner of message (%s)%s, owner is (%s)%s",
597
                                msg->getClassName(), msg->getFullName(),
598
                                msg->getOwner()->getClassName(), msg->getOwner()->getFullPath().c_str());
599
        take(encapmsg = msg);
600
#ifdef REFCOUNTING
601
        ASSERT(encapmsg->sharecount==0);
602
#endif
603
        len += encapmsg->len;
604
    }
605
}
606

    
607
cPacket *cPacket::decapsulate()
608
{
609
    if (!encapmsg)
610
        return NULL;
611
    if (len>0)
612
        len -= encapmsg->len;
613
    if (len<0)
614
        throw cRuntimeError(this,"decapsulate(): packet length is smaller than encapsulated packet");
615

    
616
#ifdef REFCOUNTING
617
    if (encapmsg->sharecount>0)
618
    {
619
        encapmsg->sharecount--;
620
        if (encapmsg->ownerp == this)
621
            encapmsg->ownerp = NULL;
622
        cPacket *msg = encapmsg->dup();
623
        encapmsg = NULL;
624
        return msg;
625
    }
626
    encapmsg->ownerp = this;
627
#endif
628
    cPacket *msg = encapmsg;
629
    encapmsg = NULL;
630
    if (msg) drop(msg);
631
    return msg;
632
}
633

    
634
cPacket *cPacket::getEncapsulatedPacket() const
635
{
636
#ifdef REFCOUNTING
637
    // encapmsg may be shared (sharecount>0) -- we'll make our own copy,
638
    // so that other messages are not affected in case the user modifies
639
    // the encapsulated message via the returned pointer.
640
    // Trick: this is a const method, so we can only do changes via a
641
    // non-const copy of the 'this' pointer.
642
    if (encapmsg)
643
        const_cast<cPacket *>(this)->_detachEncapMsg();
644
#endif
645
    return encapmsg;
646
}
647

    
648
long cPacket::getEncapsulationId() const
649
{
650
    // find innermost msg. Note: don't use getEncapsulatedPacket() because it does copy-on-touch of shared msgs
651
    const cPacket *msg = this;
652
    while (msg->encapmsg)
653
        msg = msg->encapmsg;
654
    return msg->getId();
655
}
656

    
657
long cPacket::getEncapsulationTreeId() const
658
{
659
    // find innermost msg. Note: don't use getEncapsulatedPacket() because it does copy-on-touch of shared msgs
660
    const cPacket *msg = this;
661
    while (msg->encapmsg)
662
        msg = msg->encapmsg;
663
    return msg->getTreeId();
664
}
665

    
666

    
667

    
668