using namespace std;
-PacketQueue::PacketQueue(EventManager& _em, const std::string& _label)
- : em(_em), sendEvent(this), drainManager(NULL), label(_label),
- waitingOnRetry(false)
+PacketQueue::PacketQueue(EventManager& _em, const std::string& _label,
+ bool disable_sanity_check)
+ : em(_em), sendEvent(this), _disableSanityCheck(disable_sanity_check),
+ label(_label), waitingOnRetry(false)
{
}
// add a very basic sanity check on the port to ensure the
// invisible buffer is not growing beyond reasonable limits
- if (transmitList.size() > 100) {
+ if (!_disableSanityCheck && transmitList.size() > 100) {
panic("Packet queue %s has grown beyond 100 packets\n",
name());
}
- // if requested, force the timing to be in-order by changing the when
- // parameter
- if (force_order && !transmitList.empty()) {
- Tick back = transmitList.back().tick;
-
- // fudge timing if required; relies on the code below to do the right
- // thing (push_back) with the updated time-stamp
- if (when < back) {
- DPRINTF(PacketQueue, "%s force_order shifted packet %s address "\
- "%x from %lu to %lu\n", __func__, pkt->cmdString(),
- pkt->getAddr(), when, back);
- when = back;
- }
- }
-
- // nothing on the list, or earlier than current front element,
- // schedule an event
- if (transmitList.empty() || when < transmitList.front().tick) {
- // force_order-ed in here only when list is empty
- assert(!force_order || transmitList.empty());
- // note that currently we ignore a potentially outstanding retry
- // and could in theory put a new packet at the head of the
- // transmit list before retrying the existing packet
- transmitList.emplace_front(DeferredPacket(when, pkt));
+ // nothing on the list
+ if (transmitList.empty()) {
+ transmitList.emplace_front(when, pkt);
schedSendEvent(when);
return;
}
// ourselves again before we had a chance to update waitingOnRetry
// assert(waitingOnRetry || sendEvent.scheduled());
- // list is non-empty and this belongs at the end
- if (when >= transmitList.back().tick) {
- transmitList.emplace_back(DeferredPacket(when, pkt));
- return;
- }
-
- // forced orders never need insertion in the middle
- assert(!force_order);
-
- // this belongs in the middle somewhere, insertion sort
- auto i = transmitList.begin();
- ++i; // already checked for insertion at front
- while (i != transmitList.end() && when >= i->tick)
- ++i;
- transmitList.emplace(i, DeferredPacket(when, pkt));
+ // this belongs in the middle somewhere, so search from the end to
+ // order by tick; however, if force_order is set, also make sure
+ // not to re-order in front of some existing packet with the same
+ // address
+ auto i = transmitList.end();
+ --i;
+ while (i != transmitList.begin() && when < i->tick &&
+ !(force_order && i->pkt->getAddr() == pkt->getAddr()))
+ --i;
+
+ // emplace inserts the element before the position pointed to by
+ // the iterator, so advance it one step
+ transmitList.emplace(++i, when, pkt);
}
void
} else {
// we get a MaxTick when there is no more to send, so if we're
// draining, we may be done at this point
- if (drainManager && transmitList.empty() && !sendEvent.scheduled()) {
+ if (drainState() == DrainState::Draining &&
+ transmitList.empty() && !sendEvent.scheduled()) {
+
DPRINTF(Drain, "PacketQueue done draining,"
"processing drain event\n");
- drainManager->signalDrainDone();
- drainManager = NULL;
+ signalDrainDone();
}
}
}
sendDeferredPacket();
}
-unsigned int
-PacketQueue::drain(DrainManager *dm)
+DrainState
+PacketQueue::drain()
{
- if (transmitList.empty())
- return 0;
- DPRINTF(Drain, "PacketQueue not drained\n");
- drainManager = dm;
- return 1;
+ if (transmitList.empty()) {
+ return DrainState::Drained;
+ } else {
+ DPRINTF(Drain, "PacketQueue not drained\n");
+ return DrainState::Draining;
+ }
}
ReqPacketQueue::ReqPacketQueue(EventManager& _em, MasterPort& _masterPort,