Statistics
| Branch: | Revision:

root / src / sim / cmessage.cc @ e26d3d25

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

    
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
}
66

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

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

    
84
    duration = -1;
85
    t_start = -1;
86

    
87
    msgtreeid = msgid = AO_fetch_and_add1(&next_id);
88
    AO_fetch_and_add1(&total_msgs);
89
    AO_fetch_and_add1(&live_msgs);
90
}
91

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

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

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

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

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

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

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

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

    
152
    return out.str();
153
}
154

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

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

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

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

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

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

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

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

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

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

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

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

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

    
228
    cOwnedObject::operator=(msg);
229

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

    
235
    created = msg.created;
236

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

    
243
    contextptr = msg.contextptr;
244

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

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

    
253
    msgtreeid = msg.msgtreeid;
254

    
255
    return *this;
256
}
257

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
367
//----
368

    
369
cPacket::cPacket(const cPacket& pkt) : cMessage(pkt)
370
{
371
    encapmsg = NULL;
372
    sharecount = 0;
373
    operator=(pkt);
374
}
375

    
376
cPacket::cPacket(const char *name, short k, int64 l) : cMessage(name, k)
377
{
378
    len = l;
379
    encapmsg = NULL;
380
    duration = 0;
381
    sharecount = 0;
382
}
383

    
384
cPacket::~cPacket()
385
{
386
#ifdef WITHOUT_CPACKET
387
    EVCB.messageDeleted(this);
388
#endif
389

    
390
    if (encapmsg)
391
#ifdef REFCOUNTING
392
        _deleteEncapMsg();
393
#else
394
        dropAndDelete(encapmsg);
395
#endif
396
}
397

    
398
std::string cPacket::info() const  //FIXME revise
399
{
400
//    if (tomod<0)
401
//        return std::string("(new msg)");
402

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

    
447
void cPacket::forEachChild(cVisitor *v)
448
{
449
    cMessage::forEachChild(v);
450

    
451
    if (encapmsg)
452
    {
453
#ifdef REFCOUNTING
454
        _detachEncapMsg();  // see method comment why this is needed
455
#endif
456
        v->visit(encapmsg);
457
    }
458
}
459

    
460
std::string cPacket::detailedInfo() const
461
{
462
    return "";  // all fields are available via reflection, no point in repeating them here
463
}
464

    
465
void cPacket::parsimPack(cCommBuffer *buffer)
466
{
467
#ifndef WITH_PARSIM
468
    throw cRuntimeError(this,eNOPARSIM);
469
#else
470
    cMessage::parsimPack(buffer);
471
    buffer->pack(len);
472
    buffer->pack(duration);
473
    if (buffer->packFlag(encapmsg!=NULL))
474
        buffer->packObject(encapmsg);
475
#endif
476
}
477

    
478
void cPacket::parsimUnpack(cCommBuffer *buffer)
479
{
480
#ifndef WITH_PARSIM
481
    throw cRuntimeError(this,eNOPARSIM);
482
#else
483
    ASSERT(sharecount==0);
484
    cMessage::parsimUnpack(buffer);
485
    buffer->unpack(len);
486
    buffer->unpack(duration);
487
    if (buffer->checkFlag())
488
        take(encapmsg = (cPacket *) buffer->unpackObject());
489
#endif
490
}
491

    
492
cPacket& cPacket::operator=(const cPacket& msg)
493
{
494
    if (this==&msg) return *this;
495

    
496
    cMessage::operator=(msg);
497

    
498
#ifdef REFCOUNTING
499
    if (sharecount!=0)
500
        throw cRuntimeError(this,"operator=(): this message is refcounted (shared between "
501
                                 "several messages), it is forbidden to change it");
502
#endif
503

    
504
    len = msg.len;
505
    duration = msg.duration;
506
    t_start = msg.t_start;
507

    
508
#ifndef REFCOUNTING
509
    dropAndDelete(encapmsg);
510
    if (msg.encapmsg)
511
        take(encapmsg = (cPacket *)msg.encapmsg->dup());
512
    else
513
        encapmsg = NULL;
514
#else
515
    if (encapmsg)
516
        _deleteEncapMsg();
517
    encapmsg = msg.encapmsg;
518
    if (encapmsg && ++encapmsg->sharecount==0)   // sharecount overflow
519
    {
520
        --encapmsg->sharecount;
521
        take(encapmsg = (cPacket *)encapmsg->dup());
522
    }
523
#endif
524

    
525
    return *this;
526
}
527

    
528
#ifdef REFCOUNTING
529
void cPacket::_deleteEncapMsg()
530
{
531
    if (encapmsg->sharecount>0)
532
    {
533
        encapmsg->sharecount--;
534
        if (encapmsg->ownerp == this)
535
            encapmsg->ownerp = NULL;
536
    }
537
    else
538
    {
539
        // note: dropAndDelete(encapmsg) cannot be used, because due to sharecounting
540
        // ownerp is not valid (may be any former owner, possibly deleted since then)
541
        encapmsg->ownerp = NULL;
542
        delete encapmsg;
543
    }
544
}
545
#endif
546

    
547
#ifdef REFCOUNTING
548
void cPacket::_detachEncapMsg()
549
{
550
    if (encapmsg->sharecount>0)
551
    {
552
        // "de-share" object - create our own copy
553
        encapmsg->sharecount--;
554
        if (encapmsg->ownerp == this)
555
            encapmsg->ownerp = NULL;
556
        take(encapmsg = (cPacket *)encapmsg->dup());
557
    }
558
    else
559
    {
560
        // note: due to sharecounting, ownerp may be pointing to a previous owner -- fix it
561
        encapmsg->ownerp = this;
562
    }
563
}
564
#endif
565

    
566
void cPacket::setBitLength(int64 l)
567
{
568
    if (l<0)
569
        throw cRuntimeError(this,"setBitLength(): negative length %"INT64_PRINTF_FORMAT"d", l);
570
    len = l;
571
}
572

    
573
void cPacket::addBitLength(int64 l)
574
{
575
    len += l;
576
    if (len<0)
577
        throw cRuntimeError(this,"addBitLength(): length became negative (%"INT64_PRINTF_FORMAT") after adding %"INT64_PRINTF_FORMAT"d", len, l);
578
}
579

    
580
void cPacket::encapsulate(cPacket *msg)
581
{
582
    if (encapmsg)
583
        throw cRuntimeError(this,"encapsulate(): another message already encapsulated");
584

    
585
    if (msg)
586
    {
587
        if (msg->getOwner()!=simulation.getContextSimpleModule())
588
            throw cRuntimeError(this,"encapsulate(): not owner of message (%s)%s, owner is (%s)%s",
589
                                msg->getClassName(), msg->getFullName(),
590
                                msg->getOwner()->getClassName(), msg->getOwner()->getFullPath().c_str());
591
        take(encapmsg = msg);
592
#ifdef REFCOUNTING
593
        ASSERT(encapmsg->sharecount==0);
594
#endif
595
        len += encapmsg->len;
596
    }
597
}
598

    
599
cPacket *cPacket::decapsulate()
600
{
601
    if (!encapmsg)
602
        return NULL;
603
    if (len>0)
604
        len -= encapmsg->len;
605
    if (len<0)
606
        throw cRuntimeError(this,"decapsulate(): packet length is smaller than encapsulated packet");
607

    
608
#ifdef REFCOUNTING
609
    if (encapmsg->sharecount>0)
610
    {
611
        encapmsg->sharecount--;
612
        if (encapmsg->ownerp == this)
613
            encapmsg->ownerp = NULL;
614
        cPacket *msg = encapmsg->dup();
615
        encapmsg = NULL;
616
        return msg;
617
    }
618
    encapmsg->ownerp = this;
619
#endif
620
    cPacket *msg = encapmsg;
621
    encapmsg = NULL;
622
    if (msg) drop(msg);
623
    return msg;
624
}
625

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

    
640
long cPacket::getEncapsulationId() const
641
{
642
    // find innermost msg. Note: don't use getEncapsulatedPacket() because it does copy-on-touch of shared msgs
643
    const cPacket *msg = this;
644
    while (msg->encapmsg)
645
        msg = msg->encapmsg;
646
    return msg->getId();
647
}
648

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

    
658

    
659

    
660

    
661