diff --git a/src/cpu/thread_state.cc b/src/cpu/thread_state.cc index 93dd1e2eb..4b65ca4b8 100644 --- a/src/cpu/thread_state.cc +++ b/src/cpu/thread_state.cc @@ -125,7 +125,10 @@ ThreadState::connectPhysPort() // @todo: For now this disregards any older port that may have // already existed. Fix this memory leak once the bus port IDs // for functional ports is resolved. - physPort = new FunctionalPort(csprintf("%s-%d-funcport", + if (physPort) + physPort->removeConn(); + else + physPort = new FunctionalPort(csprintf("%s-%d-funcport", baseCpu->name(), tid)); connectToMemFunc(physPort); } @@ -136,7 +139,10 @@ ThreadState::connectVirtPort() // @todo: For now this disregards any older port that may have // already existed. Fix this memory leak once the bus port IDs // for functional ports is resolved. - virtPort = new VirtualPort(csprintf("%s-%d-vport", + if (virtPort) + virtPort->removeConn(); + else + virtPort = new VirtualPort(csprintf("%s-%d-vport", baseCpu->name(), tid)); connectToMemFunc(virtPort); } diff --git a/src/mem/bus.cc b/src/mem/bus.cc index cc2137e66..4988df3c5 100644 --- a/src/mem/bus.cc +++ b/src/mem/bus.cc @@ -34,6 +34,8 @@ */ +#include + #include "base/misc.hh" #include "base/trace.hh" #include "mem/bus.hh" @@ -52,20 +54,30 @@ Bus::getPort(const std::string &if_name, int idx) } // if_name ignored? forced to be empty? - int id = interfaces.size(); + int id = maxId++; + assert(maxId < std::numeric_limits::max()); BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id); - interfaces.push_back(bp); + interfaces[id] = bp; return bp; } +void +Bus::deletePortRefs(Port *p) +{ + BusPort *bp = dynamic_cast(p); + if (bp == NULL) + panic("Couldn't convert Port* to BusPort*\n"); + interfaces.erase(bp->getId()); +} + /** Get the ranges of anyone other buses that we are connected to. */ void Bus::init() { - std::vector::iterator intIter; + m5::hash_map::iterator intIter; for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) - (*intIter)->sendStatusChange(Port::RangeChange); + intIter->second->sendStatusChange(Port::RangeChange); } Bus::BusFreeEvent::BusFreeEvent(Bus *_bus) : Event(&mainEventQueue), bus(_bus) @@ -186,7 +198,7 @@ Bus::recvTiming(PacketPtr pkt) return false; } } else { - assert(dest >= 0 && dest < interfaces.size()); + assert(dest >= 0 && dest < maxId); assert(dest != pkt->getSrc()); // catch infinite loops port = interfaces[dest]; } @@ -435,7 +447,6 @@ Bus::recvStatusChange(Port::Status status, int id) { AddrRangeList ranges; AddrRangeList snoops; - int x; AddrRangeIter iter; assert(status == Port::RangeChange && @@ -457,7 +468,7 @@ Bus::recvStatusChange(Port::Status status, int id) } } else { - assert((id < interfaces.size() && id >= 0) || id == defaultId); + assert((id < maxId && id >= 0) || id == defaultId); Port *port = interfaces[id]; range_map::iterator portIter; std::vector::iterator snoopIter; @@ -502,9 +513,11 @@ Bus::recvStatusChange(Port::Status status, int id) // tell all our peers that our address range has changed. // Don't tell the device that caused this change, it already knows - for (x = 0; x < interfaces.size(); x++) - if (x != id) - interfaces[x]->sendStatusChange(Port::RangeChange); + m5::hash_map::iterator intIter; + + for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) + if (intIter->first != id) + intIter->second->sendStatusChange(Port::RangeChange); if (id != defaultId && defaultPort) defaultPort->sendStatusChange(Port::RangeChange); diff --git a/src/mem/bus.hh b/src/mem/bus.hh index 350a67b43..6706b6c77 100644 --- a/src/mem/bus.hh +++ b/src/mem/bus.hh @@ -42,6 +42,7 @@ #include #include "base/range.hh" +#include "base/hashmap.hh" #include "base/range_map.hh" #include "mem/mem_object.hh" #include "mem/packet.hh" @@ -212,9 +213,12 @@ class Bus : public MemObject bool inRetry; + /** max number of bus ids we've handed out so far */ + short maxId; + /** An array of pointers to the peer port interfaces connected to this bus.*/ - std::vector interfaces; + m5::hash_map interfaces; /** An array of pointers to ports that retry should be called on because the * original send failed for whatever reason.*/ @@ -252,6 +256,7 @@ class Bus : public MemObject /** A function used to return the port associated with this bus object. */ virtual Port *getPort(const std::string &if_name, int idx = -1); + virtual void deletePortRefs(Port *p); virtual void init(); @@ -261,7 +266,7 @@ class Bus : public MemObject bool responder_set) : MemObject(n), busId(bus_id), clock(_clock), width(_width), tickNextIdle(0), drainEvent(NULL), busIdle(this), inRetry(false), - defaultPort(NULL), responderSet(responder_set) + maxId(0), defaultPort(NULL), responderSet(responder_set) { //Both the width and clock period must be positive if (width <= 0) diff --git a/src/mem/cache/cache.hh b/src/mem/cache/cache.hh index 26dab2179..722ce216b 100644 --- a/src/mem/cache/cache.hh +++ b/src/mem/cache/cache.hh @@ -331,6 +331,7 @@ class Cache : public BaseCache Cache(const std::string &_name, Params ¶ms); virtual Port *getPort(const std::string &if_name, int idx = -1); + virtual void deletePortRefs(Port *p); virtual void recvStatusChange(Port::Status status, bool isCpuSide); diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh index dac2b93a4..056f6033f 100644 --- a/src/mem/cache/cache_impl.hh +++ b/src/mem/cache/cache_impl.hh @@ -1100,7 +1100,7 @@ Cache::getPort(const std::string &if_name, int idx) } else if (if_name == "functional") { - return new CpuSidePort(name() + "-cpu_side_port", this); + return new CpuSidePort(name() + "-cpu_side_funcport", this); } else if (if_name == "cpu_side") { @@ -1121,6 +1121,15 @@ Cache::getPort(const std::string &if_name, int idx) else panic("Port name %s unrecognized\n", if_name); } +template +void +Cache::deletePortRefs(Port *p) +{ + if (cpuSidePort == p || memSidePort == p) + panic("Can only delete functional ports\n"); + // nothing else to do +} + template bool diff --git a/src/mem/mem_object.cc b/src/mem/mem_object.cc index d4d3fd283..ef31cf999 100644 --- a/src/mem/mem_object.cc +++ b/src/mem/mem_object.cc @@ -35,5 +35,10 @@ MemObject::MemObject(const std::string &name) : SimObject(name) { } +void +MemObject::deletePortRefs(Port *p) +{ + panic("This object does not support port deletion\n"); +} DEFINE_SIM_OBJECT_CLASS_NAME("MemObject", MemObject) diff --git a/src/mem/mem_object.hh b/src/mem/mem_object.hh index d12eeffe0..ec6fa2b2a 100644 --- a/src/mem/mem_object.hh +++ b/src/mem/mem_object.hh @@ -51,6 +51,10 @@ class MemObject : public SimObject public: /** Additional function to return the Port of a memory object. */ virtual Port *getPort(const std::string &if_name, int idx = -1) = 0; + + /** Tell object that this port is about to disappear, so it should remove it + * from any structures that it's keeping it in. */ + virtual void deletePortRefs(Port *p) ; }; #endif //__MEM_MEM_OBJECT_HH__ diff --git a/src/mem/port.cc b/src/mem/port.cc index 048d7cf6d..e75e50e4d 100644 --- a/src/mem/port.cc +++ b/src/mem/port.cc @@ -36,6 +36,7 @@ #include "base/chunk_generator.hh" #include "base/trace.hh" +#include "mem/mem_object.hh" #include "mem/port.hh" void @@ -45,6 +46,15 @@ Port::setPeer(Port *port) peer = port; } +void +Port::removeConn() +{ + if (peer->getOwner()) + peer->getOwner()->deletePortRefs(peer); + delete peer; + peer = NULL; +} + void Port::blobHelper(Addr addr, uint8_t *p, int size, MemCmd cmd) { diff --git a/src/mem/port.hh b/src/mem/port.hh index fdb5bfab4..52162bf76 100644 --- a/src/mem/port.hh +++ b/src/mem/port.hh @@ -131,6 +131,11 @@ class Port /** Function to return the owner of this port. */ MemObject *getOwner() { return owner; } + /** Inform the peer port to delete itself and notify it's owner about it's + * demise. */ + void removeConn(); + + protected: /** These functions are protected because they should only be