diff options
Diffstat (limited to 'src/mem/port.cc')
-rw-r--r-- | src/mem/port.cc | 65 |
1 files changed, 48 insertions, 17 deletions
diff --git a/src/mem/port.cc b/src/mem/port.cc index 0e03194c9..1e6989750 100644 --- a/src/mem/port.cc +++ b/src/mem/port.cc @@ -39,17 +39,25 @@ #include "mem/mem_object.hh" #include "mem/port.hh" +/** + * Special class for port objects that are used as peers for + * unconnected ports. Assigning instances of this class to newly + * allocated ports allows us to guarantee that every port has a peer + * object (so there's no need to check for null peer pointers), while + * catching uses of unconnected ports. + */ class DefaultPeerPort : public Port { protected: void blowUp() { - fatal("%s: Unconnected port!", peer->name()); + Port *peer = getPeer(); + fatal("unconnected port: %s", peer ? peer->name() : "<unknown>"); } public: - DefaultPeerPort() - : Port("default_port") + DefaultPeerPort(Port *_peer) + : Port("default_port", NULL, _peer) { } bool recvTiming(PacketPtr) @@ -88,36 +96,59 @@ class DefaultPeerPort : public Port bool isDefaultPort() const { return true; } }; -DefaultPeerPort defaultPeerPort; -Port::Port() - : peer(&defaultPeerPort), owner(NULL) +Port::Port(const std::string &_name, MemObject *_owner, Port *_peer) : + portName(_name), + peer(_peer ? _peer : new DefaultPeerPort(this)), + owner(_owner) { } -Port::Port(const std::string &_name, MemObject *_owner) - : portName(_name), peer(&defaultPeerPort), owner(_owner) +Port::~Port() { + disconnectFromPeer(); } -Port::~Port() +void +Port::disconnectFromPeer() { + if (peer) { + assert(peer->getPeer() == this); + peer->disconnect(); + } } void -Port::setPeer(Port *port) +Port::disconnect() { - DPRINTF(Config, "setting peer to %s\n", port->name()); - - peer = port; + // This notification should come only from our peer, so we must + // have one, + assert(peer != NULL); + // We must clear 'peer' here, else if owner->deletePort() calls + // delete on us then we'll recurse infinitely through the Port + // destructor. + peer = NULL; + // If owner->deletePort() returns true, then we've been deleted, + // so don't do anything but get out of here. If not, reset peer + // pointer to a DefaultPeerPort. + if (!(owner && owner->deletePort(this))) + peer = new DefaultPeerPort(this); } void -Port::removeConn() +Port::setPeer(Port *port) { - if (peer->getOwner()) - peer->getOwner()->deletePortRefs(peer); - peer = NULL; + DPRINTF(Config, "setting peer to %s, old peer %s\n", + port->name(), peer ? peer->name() : "<null>"); + + // You'd think we'd want to disconnect from the previous peer + // here, but it turns out that with some functional ports the old + // peer keeps using the connection, and it works because + // functional ports are unidirectional. + // + // disconnectFromPeer(); + + peer = port; } void |