@@ -412,6 +412,18 @@ class TestSignalListener : public cListener
412412 virtual void receiveSignal(cComponent *, simsignal_t, cObject *, cObject *) override { numSignals++; }
413413};
414414
415+ class TestPacketArrivalListener : public cListener
416+ {
417+ public:
418+ int numSignals = 0;
419+ cGate *lastArrivalGate = nullptr;
420+
421+ virtual void receiveSignal(cComponent *, simsignal_t, cObject *value, cObject *) override {
422+ numSignals++;
423+ lastArrivalGate = check_and_cast<Packet *>(value)->getArrivalGate();
424+ }
425+ };
426+
415427class TestOrderedSignalListener : public cListener
416428{
417429 public:
@@ -3311,46 +3323,124 @@ auto deferredFrames = deferredInProgressFrames.releaseFrames();
33113323ASSERT(deferredFrames.size() == 1);
33123324delete deferredFrames.at(0);
33133325
3314- // A simulation-registered real queue records selected-dequeue residence and
3315- // emits its semantic pull exactly once.
3316- Packet *compoundPacket = nullptr;
3326+ // A real queue with a downstream collector predicate-dequeues a non-front
3327+ // packet, records its residence and semantic pull once, and animates it to the
3328+ // collector while retaining the front packet.
33173329{
33183330 TestPacketPulledListener pullListener;
3319- auto leafQueue = createPacketQueue("selectedDequeueQueue");
3331+ TestPacketDropCallback removalCallback;
3332+ auto leafQueueModule = cModuleType::get("inet.queueing.queue.PacketQueue")->create("selectedDequeueQueue", this);
3333+ auto sinkModule = cModuleType::get("inet.queueing.sink.FullPacketSink")->create("selectedDequeueSink", this);
3334+ leafQueueModule->gate("out")->connectTo(sinkModule->gate("in"));
3335+ leafQueueModule->callInitialize();
3336+ sinkModule->callInitialize();
3337+ auto leafQueue = check_and_cast<queueing::PacketQueue *>(leafQueueModule);
33203338 pullListener.leaf = leafQueue;
33213339 leafQueue->subscribe(packetPulledSignal, &pullListener);
3322- compoundPacket = new Packet("compoundPacket", makeQosHeader(peer1, 1, SequenceNumberCyclic(1)));
3323- auto queueingTimeTag = compoundPacket->addRegionTag<QueueingTimeTag>();
3340+ leafQueue->addPacketCallback(&removalCallback);
3341+ auto frontPacket = new Packet("selectedDequeueFront", makeShared<ByteCountChunk>(B(1)));
3342+ auto selectedPacket = new Packet("selectedDequeueMatch", makeQosHeader(peer1, 1, SequenceNumberCyclic(1)));
3343+ auto queueingTimeTag = selectedPacket->addRegionTag<QueueingTimeTag>();
33243344 queueingTimeTag->setBitTotalTimesArraySize(1);
33253345 queueingTimeTag->setBitTotalTimes(0, 0);
33263346 queueingTimeTag->setPacketTotalTimesArraySize(1);
33273347 queueingTimeTag->setPacketTotalTimes(0, 0);
3328- compoundPacket->addRegionTag<PacketEventTag>();
3329- compoundPacket->setArrivalTime(simTime() - 1);
3330- leafQueue->pushPacket(compoundPacket, nullptr);
3331- auto dequeuedPacket = leafQueue->dequeuePacket([compoundPacket](const Packet *packet) { return packet == compoundPacket; });
3332- ASSERT(dequeuedPacket == compoundPacket);
3348+ selectedPacket->addRegionTag<PacketEventTag>();
3349+ selectedPacket->setArrivalTime(simTime() - 1);
3350+ leafQueue->pushPacket(frontPacket, nullptr);
3351+ leafQueue->pushPacket(selectedPacket, nullptr);
3352+ auto dequeuedPacket = leafQueue->dequeuePacket([selectedPacket](const Packet *packet) { return packet == selectedPacket; });
3353+ ASSERT(dequeuedPacket == selectedPacket);
33333354 int numQueuedEvents = 0;
3334- compoundPacket ->mapAllRegionTags<PacketEventTag>(b(0), compoundPacket ->getTotalLength(), [&](b, b, const Ptr<const PacketEventTag>& tag) {
3355+ selectedPacket ->mapAllRegionTags<PacketEventTag>(b(0), selectedPacket ->getTotalLength(), [&](b, b, const Ptr<const PacketEventTag>& tag) {
33353356 for (size_t i = 0; i < tag->getPacketEventsArraySize(); i++)
33363357 if (tag->getPacketEvents(i)->getKind() == PEK_QUEUED)
33373358 numQueuedEvents++;
33383359 });
33393360 simtime_t totalQueueingTime = -1;
3340- compoundPacket ->mapAllRegionTags<QueueingTimeTag>(b(0), compoundPacket ->getTotalLength(), [&](b, b, const Ptr<const QueueingTimeTag>& tag) {
3361+ selectedPacket ->mapAllRegionTags<QueueingTimeTag>(b(0), selectedPacket ->getTotalLength(), [&](b, b, const Ptr<const QueueingTimeTag>& tag) {
33413362 ASSERT(tag->getPacketTotalTimesArraySize() == 1);
33423363 totalQueueingTime = tag->getPacketTotalTimes(0);
33433364 });
33443365 ASSERT(numQueuedEvents == 1);
33453366 ASSERT(totalQueueingTime == 1);
3346- ASSERT(leafQueue->getNumPackets() == 0);
3367+ ASSERT(leafQueue->getNumPackets() == 1);
3368+ ASSERT(leafQueue->getPacket(0) == frontPacket);
33473369 ASSERT(pullListener.numLeafPulls == 1);
3370+ ASSERT(removalCallback.numDequeuedPackets == 1);
3371+ ASSERT(selectedPacket->getArrivalGate() == sinkModule->gate("in"));
33483372 leafQueue->unsubscribe(packetPulledSignal, &pullListener);
3349- leafQueue->callFinish();
3350- leafQueue->deleteModule();
3351- compoundPacket = nullptr;
3373+ leafQueue->removePacketCallback(&removalCallback);
3374+ leafQueue->removePacket(frontPacket);
3375+ take(frontPacket);
3376+ take(selectedPacket);
3377+ delete frontPacket;
3378+ delete selectedPacket;
3379+ sinkModule->callFinish();
3380+ leafQueueModule->callFinish();
3381+ sinkModule->deleteModule();
3382+ leafQueueModule->deleteModule();
3383+ }
3384+
3385+ // Predicate extraction through a concrete PacketFlowBase module processes a
3386+ // non-front packet once. The queue animates it to the flow input before the
3387+ // flow signals, and the flow then animates it to the final collector.
3388+ {
3389+ TestPacketPulledListener pullListener;
3390+ TestPacketDropCallback removalCallback;
3391+ TestPacketArrivalListener flowInputListener;
3392+ TestPacketArrivalListener flowOutputListener;
3393+ auto leafQueueModule = cModuleType::get("inet.queueing.queue.PacketQueue")->create("selectedFlowLeaf", this);
3394+ auto gateModule = cModuleType::get("inet.queueing.gate.PacketGate")->create("selectedFlowGate", this);
3395+ auto sinkModule = cModuleType::get("inet.queueing.sink.FullPacketSink")->create("selectedFlowSink", this);
3396+ gateModule->par("initiallyOpen").setBoolValue(true);
3397+ gateModule->par("openTime").setDoubleValue(10);
3398+ gateModule->par("closeTime").setDoubleValue(20);
3399+ leafQueueModule->gate("out")->connectTo(gateModule->gate("in"));
3400+ gateModule->gate("out")->connectTo(sinkModule->gate("in"));
3401+ leafQueueModule->callInitialize();
3402+ gateModule->callInitialize();
3403+ sinkModule->callInitialize();
3404+ auto leafQueue = check_and_cast<queueing::PacketQueue *>(leafQueueModule);
3405+ auto packetGate = check_and_cast<queueing::PacketGate *>(gateModule);
3406+ auto packetExtractor = check_and_cast<queueing::IPacketExtractor *>(gateModule);
3407+ pullListener.leaf = leafQueue;
3408+ leafQueue->subscribe(packetPulledSignal, &pullListener);
3409+ leafQueue->addPacketCallback(&removalCallback);
3410+ gateModule->subscribe(packetPulledInSignal, &flowInputListener);
3411+ gateModule->subscribe(packetPulledOutSignal, &flowOutputListener);
3412+ auto frontPacket = new Packet("selectedFlowFront", makeShared<ByteCountChunk>(B(1)));
3413+ auto selectedPacket = new Packet("selectedFlowMatch", makeShared<ByteCountChunk>(B(1)));
3414+ leafQueue->pushPacket(frontPacket, nullptr);
3415+ leafQueue->pushPacket(selectedPacket, nullptr);
3416+ auto dequeuedPacket = packetExtractor->dequeuePacket([selectedPacket](const Packet *packet) { return packet == selectedPacket; });
3417+ ASSERT(dequeuedPacket == selectedPacket);
3418+ ASSERT(leafQueue->getNumPackets() == 1);
3419+ ASSERT(leafQueue->getPacket(0) == frontPacket);
3420+ ASSERT(pullListener.numLeafPulls == 1);
3421+ ASSERT(removalCallback.numDequeuedPackets == 1);
3422+ ASSERT(flowInputListener.numSignals == 1);
3423+ ASSERT(flowInputListener.lastArrivalGate == gateModule->gate("in"));
3424+ ASSERT(flowOutputListener.numSignals == 1);
3425+ ASSERT(flowOutputListener.lastArrivalGate == gateModule->gate("in"));
3426+ ASSERT(packetGate->resolveDirective('p') == "1");
3427+ ASSERT(selectedPacket->getArrivalGate() == sinkModule->gate("in"));
3428+ leafQueue->unsubscribe(packetPulledSignal, &pullListener);
3429+ leafQueue->removePacketCallback(&removalCallback);
3430+ gateModule->unsubscribe(packetPulledInSignal, &flowInputListener);
3431+ gateModule->unsubscribe(packetPulledOutSignal, &flowOutputListener);
3432+ leafQueue->removePacket(frontPacket);
3433+ take(frontPacket);
3434+ take(selectedPacket);
3435+ delete frontPacket;
3436+ delete selectedPacket;
3437+ sinkModule->callFinish();
3438+ gateModule->callFinish();
3439+ leafQueueModule->callFinish();
3440+ sinkModule->deleteModule();
3441+ gateModule->deleteModule();
3442+ leafQueueModule->deleteModule();
33523443}
3353- delete compoundPacket;
33543444
33553445// Ordinary queue overflow must not trigger channel-access re-evaluation, while
33563446// cancelling a dropped setup transaction must immediately release held traffic.
0 commit comments