//======================================================================== // CMESSAGE.CC - part of // OMNeT++/OMNEST // Discrete System Simulation in C++ // // Author: Andras Varga // //======================================================================== /*--------------------------------------------------------------* Copyright (C) 1992-2017 Andras Varga Copyright (C) 2006-2017 OpenSim Ltd. This file is distributed WITHOUT ANY WARRANTY. See the file `license' for details on this and other legal matters. *--------------------------------------------------------------*/ #include #include "omnetpp/globals.h" #include "omnetpp/cmodule.h" #include "omnetpp/csimplemodule.h" #include "omnetpp/cmessage.h" #include "omnetpp/cexception.h" #include "omnetpp/cenvir.h" #ifdef WITH_PARSIM #include "omnetpp/ccommbuffer.h" #endif namespace omnetpp { using std::ostream; Register_Class(cMessage); // static members of cMessage long cMessage::nextMessageId = 0; long cMessage::totalMsgCount = 0; long cMessage::liveMsgCount = 0; cMessage::cMessage(const cMessage& msg) : cEvent(msg) { parList = nullptr; controlInfo = nullptr; heapIndex = -1; copy(msg); messageId = nextMessageId++; totalMsgCount++; liveMsgCount++; cMessage *nonConstMsg = const_cast(&msg); EVCB.messageCloned(nonConstMsg, this); // after envir notification nonConstMsg->previousEventNumber = previousEventNumber = getSimulation()->getEventNumber(); } cMessage::cMessage(const char *name, short k) : cEvent(name) { // name pooling is off for messages by default, as unique names are quite common messageKind = k; parList = nullptr; contextPointer = nullptr; controlInfo = nullptr; srcProcId = -1; senderModuleId = senderGateId = -1; targetModuleId = targetGateId = -1; creationTime = getSimulation()->getSimTime(); sendTime = timestamp = 0; messageTreeId = messageId = nextMessageId++; totalMsgCount++; liveMsgCount++; previousEventNumber = -1; EVCB.messageCreated(this); // after envir notification previousEventNumber = getSimulation()->getEventNumber(); } cMessage::~cMessage() { EVCB.messageDeleted(this); if (parList) dropAndDelete(parList); if (controlInfo) { if (controlInfo->isOwnedObject()) dropAndDelete((cOwnedObject *)controlInfo); else delete controlInfo; } if ((flags & FL_ISPRIVATECOPY) == 0) liveMsgCount--; } std::string cMessage::str() const { if (targetModuleId < 0) return std::string("(new msg)"); std::stringstream out; const char *deletedstr = ""; simtime_t t = getArrivalTime(); if (t > getSimulation()->getSimTime()) { // if it arrived in the past, dt is usually unimportant, don't print it simtime_t dt = t - getSimulation()->getSimTime(); out << "at t=" << t << ", in dt=" << dt.ustr() << "; "; } #define MODNAME(modp) ((modp) ? (modp)->getFullPath().c_str() : deletedstr) if (getKind() == MK_STARTER) { cModule *tomodp = getSimulation()->getModule(targetModuleId); out << "starter for " << MODNAME(tomodp) << " (id=" << targetModuleId << ") "; } else if (getKind() == MK_TIMEOUT) { cModule *tomodp = getSimulation()->getModule(targetModuleId); out << "timeoutmsg for " << MODNAME(tomodp) << " (id=" << targetModuleId << ") "; } else if (senderModuleId == targetModuleId) { cModule *tomodp = getSimulation()->getModule(targetModuleId); out << "selfmsg for " << MODNAME(tomodp) << " (id=" << targetModuleId << ") "; } else { cModule *frommodp = getSimulation()->getModule(senderModuleId); cModule *tomodp = getSimulation()->getModule(targetModuleId); out << "src=" << MODNAME(frommodp) << " (id=" << senderModuleId << ") "; out << " dest=" << MODNAME(tomodp) << " (id=" << targetModuleId << ") "; } #undef MODNAME if (controlInfo) out << " control info: (" << controlInfo->getClassName() << ") " << controlInfo->getFullName() << "\n"; return out.str(); } void cMessage::forEachChild(cVisitor *v) { if (parList) v->visit(parList); if (controlInfo) v->visit(controlInfo); } void cMessage::parsimPack(cCommBuffer *buffer) const { #ifndef WITH_PARSIM throw cRuntimeError(this, E_NOPARSIM); #else cEvent::parsimPack(buffer); if (contextPointer || controlInfo) throw cRuntimeError(this,"parsimPack(): Cannot pack object with contextPointer or controlInfo set"); buffer->pack(messageKind); buffer->pack(timestamp); buffer->pack(senderModuleId); buffer->pack(senderGateId); buffer->pack(targetModuleId); buffer->pack(targetGateId); buffer->pack(creationTime); buffer->pack(sendTime); // note: do not pack msgid and treeid, because they'd conflict // with ids assigned at the destination partition if (buffer->packFlag(parList != nullptr)) buffer->packObject(parList); #endif } void cMessage::parsimUnpack(cCommBuffer *buffer) { #ifndef WITH_PARSIM throw cRuntimeError(this, E_NOPARSIM); #else cEvent::parsimUnpack(buffer); buffer->unpack(messageKind); buffer->unpack(timestamp); buffer->unpack(senderModuleId); buffer->unpack(senderGateId); buffer->unpack(targetModuleId); buffer->unpack(targetGateId); buffer->unpack(creationTime); buffer->unpack(sendTime); if (buffer->checkFlag()) take(parList = (cArray *)buffer->unpackObject()); #endif } cMessage& cMessage::operator=(const cMessage& msg) { if (this == &msg) return *this; cEvent::operator=(msg); copy(msg); return *this; } void cMessage::copy(const cMessage& msg) { messageKind = msg.messageKind; timestamp = msg.timestamp; srcProcId = msg.srcProcId; creationTime = msg.creationTime; dropAndDelete(parList); if (msg.parList) take(parList = (cArray *)msg.parList->dup()); else parList = nullptr; contextPointer = msg.contextPointer; senderModuleId = msg.senderModuleId; senderGateId = msg.senderGateId; targetModuleId = msg.targetModuleId; targetGateId = msg.targetGateId; sendTime = msg.sendTime; messageTreeId = msg.messageTreeId; } void cMessage::_createparlist() { parList = new cArray("parameters", 5, 5); take(parList); } cMessage *cMessage::privateDup() const { cMessage *ret = dup(); ret->messageId = messageId; ret->flags |= FL_ISPRIVATECOPY; ret->removeFromOwnershipTree(); totalMsgCount--; liveMsgCount--; return ret; } void cMessage::setControlInfo(cObject *p) { if (!p) throw cRuntimeError(this, "setControlInfo(): Pointer is nullptr"); if (controlInfo) throw cRuntimeError(this, "setControlInfo(): Message already has control info attached"); if (p->isOwnedObject()) take((cOwnedObject *)p); controlInfo = p; } cObject *cMessage::removeControlInfo() { cObject *p = controlInfo; controlInfo = nullptr; if (p && p->isOwnedObject()) drop((cOwnedObject *)p); return p; } cObject *cMessage::getTargetObject() const { return getArrivalModule(); } cMsgPar& cMessage::par(int index) { cArray& parlist = getParList(); cObject *p = parlist.get(index); if (!p) throw cRuntimeError(this, "par(int): Has no parameter #%d", index); if (!dynamic_cast(p)) throw cRuntimeError(this, "par(int): Parameter #%d is of type %s, not cMsgPar", index, p->getClassName()); return *(cMsgPar *)p; } cMsgPar& cMessage::par(const char *name) { cArray& parlist = getParList(); cObject *p = parlist.get(name); if (!p) throw cRuntimeError(this, "par(const char *): Has no parameter called '%s'", name); if (!dynamic_cast(p)) throw cRuntimeError(this, "par(const char *): Parameter '%s' is of type %s, not cMsgPar", name, p->getClassName()); return *(cMsgPar *)p; } int cMessage::findPar(const char *name) const { return !parList ? -1 : parList->find(name); } cGate *cMessage::getSenderGate() const { if (senderModuleId < 0 || senderGateId < 0) return nullptr; cModule *mod = getSimulation()->getModule(senderModuleId); return !mod ? nullptr : mod->gate(senderGateId); } cGate *cMessage::getArrivalGate() const { if (targetModuleId < 0 || targetGateId < 0) return nullptr; cModule *mod = getSimulation()->getModule(targetModuleId); return !mod ? nullptr : mod->gate(targetGateId); } bool cMessage::arrivedOn(const char *gateName) const { cGate *arrgate = getArrivalGate(); return arrgate && arrgate->isName(gateName); } bool cMessage::arrivedOn(const char *gateName, int gateIndex) const { cGate *arrgate = getArrivalGate(); return arrgate && arrgate->isName(gateName) && arrgate->getIndex() == gateIndex; } const char *cMessage::getDisplayString() const { return ""; // clients may redefine this method to get messages with custom appearance } void cMessage::setSentFrom(cModule *module, int gateId, simtime_t_cref t) { senderModuleId = module ? module->getId() : -1; senderGateId = gateId; sendTime = t; } bool cMessage::isStale() { // check that destination module still exists and is alive cSimpleModule *module = dynamic_cast(getSimulation()->getModule(targetModuleId)); return !module || module->isTerminated(); } void cMessage::execute() { throw new cRuntimeError("Illegal call to cMessage::execute()"); } } // namespace omnetpp