Skip to content

Commit 745b687

Browse files
committed
LteMacUeD2D: refactor macHandleD2DModeSwitch()
This function: - Iterates through all outgoing connections to find connections that match the peer being switched - For OLD connections (being switched away from): - Clears MAC buffers (both virtual and real buffers) - Deletes connection data structures - Interrupts H-ARQ processes if needed - Sends notification to upper layers (RLC) - Cleans up LCG (Logical Channel Group) mappings - For NEW connections (being switched to): - Sends notification to upper layers to prepare for the new mode This was refactored into a 2-phase solution: 1. In phase 1, collect the list of NEW and OLD connections 2. In phase 2, interate over the NEW (and then the OLD) connections, and do the necessary actions (see above) This results in code that is easier to comprehend, and avoids potential iterator invalidation issue.
1 parent 1ed5ceb commit 745b687

1 file changed

Lines changed: 143 additions & 118 deletions

File tree

src/simu5g/stack/mac/LteMacUeD2D.cc

Lines changed: 143 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -842,156 +842,181 @@ void LteMacUeD2D::macHandleD2DModeSwitch(cPacket *pktAux)
842842
Direction newDirection = (newMode == DM) ? D2D : UL;
843843
Direction oldDirection = (oldMode == DM) ? D2D : UL;
844844

845-
// Find the correct connection involved in the mode switch
846-
for (auto& it : connDesc_) {
847-
MacCid cid = it.first;
848-
FlowControlInfo *lteInfo = &(it.second);
849-
850-
if (lteInfo->getD2dRxPeerId() == peerId && (Direction)lteInfo->getDirection() == oldDirection) {
851-
EV << NOW << " LteMacUeD2D::macHandleD2DModeSwitch - found old connection with cid " << cid << ", erasing buffered data" << endl;
852-
if (oldDirection != newDirection) {
853-
if (switchPkt->getClearRlcBuffer()) {
854-
EV << NOW << " LteMacUeD2D::macHandleD2DModeSwitch - erasing buffered data" << endl;
855-
856-
// Empty virtual buffer for the selected cid
857-
auto macBuff_it = macBuffers_.find(cid);
858-
if (macBuff_it != macBuffers_.end()) {
859-
while (!(macBuff_it->second->isEmpty()))
860-
macBuff_it->second->popFront();
861-
delete macBuff_it->second;
862-
macBuffers_.erase(macBuff_it);
863-
}
845+
// Find the correct connections involved in the mode switch
846+
// Use two-phase approach: first collect, then process
864847

865-
// Empty real buffer for the selected cid (they should be already empty)
866-
auto qit = macQueues_.find(cid);
867-
if (qit != macQueues_.end()) {
868-
while (qit->second->getQueueLength() > 0) {
869-
cPacket *pdu = qit->second->popFront();
870-
delete pdu;
871-
}
872-
delete qit->second;
873-
macQueues_.erase(qit);
848+
// Phase 1: Collect CIDs and flow info that need processing
849+
std::vector<std::pair<MacCid, FlowControlInfo>> oldConnections;
850+
std::vector<std::pair<MacCid, FlowControlInfo>> newConnections;
851+
852+
for (const auto& [cid, lteInfo] : connDesc_) {
853+
if (lteInfo.getD2dRxPeerId() == peerId && (Direction)lteInfo.getDirection() == oldDirection) {
854+
oldConnections.emplace_back(cid, lteInfo);
855+
}
856+
else if (lteInfo.getD2dRxPeerId() == peerId && (Direction)lteInfo.getDirection() == newDirection) {
857+
newConnections.emplace_back(cid, lteInfo);
858+
}
859+
}
860+
861+
// Phase 2: Process old connections (safe to modify containers now)
862+
for (const auto& [cid, lteInfo] : oldConnections) {
863+
EV << NOW << " LteMacUeD2D::macHandleD2DModeSwitch - found old connection with cid " << cid << ", erasing buffered data" << endl;
864+
if (oldDirection != newDirection) {
865+
if (switchPkt->getClearRlcBuffer()) {
866+
EV << NOW << " LteMacUeD2D::macHandleD2DModeSwitch - erasing buffered data" << endl;
867+
868+
// Empty virtual buffer for the selected cid
869+
auto macBuff_it = macBuffers_.find(cid);
870+
if (macBuff_it != macBuffers_.end()) {
871+
while (!(macBuff_it->second->isEmpty()))
872+
macBuff_it->second->popFront();
873+
delete macBuff_it->second;
874+
macBuffers_.erase(macBuff_it);
875+
}
876+
877+
// Empty real buffer for the selected cid (they should be already empty)
878+
auto qit = macQueues_.find(cid);
879+
if (qit != macQueues_.end()) {
880+
while (qit->second->getQueueLength() > 0) {
881+
cPacket *pdu = qit->second->popFront();
882+
delete pdu;
874883
}
884+
delete qit->second;
885+
macQueues_.erase(qit);
875886
}
887+
}
876888

877-
if (switchPkt->getInterruptHarq()) {
878-
EV << NOW << " LteMacUeD2D::macHandleD2DModeSwitch - interrupting H-ARQ processes" << endl;
889+
if (switchPkt->getInterruptHarq()) {
890+
EV << NOW << " LteMacUeD2D::macHandleD2DModeSwitch - interrupting H-ARQ processes" << endl;
879891

880-
// Interrupt H-ARQ processes for SL
881-
MacNodeId id = peerId;
882-
for (auto& mtit : harqTxBuffers_) {
883-
HarqTxBuffers::iterator hit = mtit.second.find(id);
884-
if (hit != mtit.second.end()) {
885-
for (int proc = 0; proc < (unsigned int)UE_TX_HARQ_PROCESSES; proc++) {
886-
hit->second->forceDropProcess(proc);
887-
}
892+
// Interrupt H-ARQ processes for SL
893+
MacNodeId id = peerId;
894+
for (auto& mtit : harqTxBuffers_) {
895+
HarqTxBuffers::iterator hit = mtit.second.find(id);
896+
if (hit != mtit.second.end()) {
897+
for (int proc = 0; proc < (unsigned int)UE_TX_HARQ_PROCESSES; proc++) {
898+
hit->second->forceDropProcess(proc);
888899
}
900+
}
889901

890-
// Interrupt H-ARQ processes for UL
891-
id = getMacCellId();
892-
hit = mtit.second.find(id);
893-
if (hit != mtit.second.end()) {
894-
for (int proc = 0; proc < (unsigned int)UE_TX_HARQ_PROCESSES; proc++) {
895-
hit->second->forceDropProcess(proc);
896-
}
902+
// Interrupt H-ARQ processes for UL
903+
id = getMacCellId();
904+
hit = mtit.second.find(id);
905+
if (hit != mtit.second.end()) {
906+
for (int proc = 0; proc < (unsigned int)UE_TX_HARQ_PROCESSES; proc++) {
907+
hit->second->forceDropProcess(proc);
897908
}
898909
}
899910
}
900911
}
912+
}
901913

902-
// Abort BSR requests
903-
bsrTriggered_ = false;
914+
// Abort BSR requests
915+
bsrTriggered_ = false;
904916

905-
auto pktDup = pkt->dup();
906-
auto switchPkt_dup = pktDup->removeAtFront<D2DModeSwitchNotification>();
907-
switchPkt_dup->setOldConnection(true);
908-
pktDup->insertAtFront(switchPkt_dup);
909-
*(pktDup->addTagIfAbsent<FlowControlInfo>()) = *lteInfo;
910-
sendUpperPackets(pktDup);
917+
auto pktDup = pkt->dup();
918+
auto switchPkt_dup = pktDup->removeAtFront<D2DModeSwitchNotification>();
919+
switchPkt_dup->setOldConnection(true);
920+
pktDup->insertAtFront(switchPkt_dup);
921+
*(pktDup->addTagIfAbsent<FlowControlInfo>()) = lteInfo;
922+
sendUpperPackets(pktDup);
911923

912-
if (oldDirection != newDirection && switchPkt->getClearRlcBuffer()) {
913-
EV << NOW << " LteMacUeD2D::macHandleD2DModeSwitch - clearing LCG map" << endl;
924+
if (oldDirection != newDirection && switchPkt->getClearRlcBuffer()) {
925+
EV << NOW << " LteMacUeD2D::macHandleD2DModeSwitch - clearing LCG map" << endl;
914926

915-
// Remove entry from lcgMap
916-
for (auto lt = lcgMap_.begin(); lt != lcgMap_.end(); ) {
917-
if (lt->second.first == cid) {
918-
lt = lcgMap_.erase(lt);
919-
}
920-
else {
921-
++lt;
922-
}
927+
// Remove entry from lcgMap
928+
for (auto lt = lcgMap_.begin(); lt != lcgMap_.end(); ) {
929+
if (lt->second.first == cid) {
930+
lt = lcgMap_.erase(lt);
931+
}
932+
else {
933+
++lt;
923934
}
924935
}
925-
EV << NOW << " LteMacUeD2D::macHandleD2DModeSwitch - send switch signal to the RLC TX entity corresponding to the old mode, cid " << cid << endl;
926936
}
927-
else if (lteInfo->getD2dRxPeerId() == peerId && (Direction)lteInfo->getDirection() == newDirection) {
928-
EV << NOW << " LteMacUeD2D::macHandleD2DModeSwitch - send switch signal to the RLC TX entity corresponding to the new mode, cid " << cid << endl;
929-
if (oldDirection != newDirection) {
930-
931-
auto pktDup = pkt->dup();
932-
auto switchPkt_dup = pktDup->removeAtFront<D2DModeSwitchNotification>();
933-
switchPkt_dup->setOldConnection(false);
934-
// switchPkt_dup->setSchedulingPriority(1); // always after the old mode
935-
pktDup->insertAtFront(switchPkt_dup);
936-
*(pktDup->addTagIfAbsent<FlowControlInfo>()) = *lteInfo;
937-
sendUpperPackets(pktDup);
938-
}
937+
EV << NOW << " LteMacUeD2D::macHandleD2DModeSwitch - send switch signal to the RLC TX entity corresponding to the old mode, cid " << cid << endl;
938+
}
939+
940+
// Phase 3: Process new connections
941+
for (const auto& [cid, lteInfo] : newConnections) {
942+
EV << NOW << " LteMacUeD2D::macHandleD2DModeSwitch - send switch signal to the RLC TX entity corresponding to the new mode, cid " << cid << endl;
943+
if (oldDirection != newDirection) {
944+
auto pktDup = pkt->dup();
945+
auto switchPkt_dup = pktDup->removeAtFront<D2DModeSwitchNotification>();
946+
switchPkt_dup->setOldConnection(false);
947+
// switchPkt_dup->setSchedulingPriority(1); // always after the old mode
948+
pktDup->insertAtFront(switchPkt_dup);
949+
*(pktDup->addTagIfAbsent<FlowControlInfo>()) = lteInfo;
950+
sendUpperPackets(pktDup);
939951
}
940952
}
941953
}
942954
else { // rx side
943955
Direction newDirection = (newMode == DM) ? D2D : DL;
944956
Direction oldDirection = (oldMode == DM) ? D2D : DL;
945957

946-
// Find the correct connection involved in the mode switch
947-
for (auto& item : connDescIn_) {
948-
MacCid cid = item.first;
949-
FlowControlInfo *lteInfo = &(item.second);
950-
if (lteInfo->getD2dTxPeerId() == peerId && (Direction)lteInfo->getDirection() == oldDirection) {
951-
EV << NOW << " LteMacUeD2D::macHandleD2DModeSwitch - found old connection with cid " << cid << ", send signal to the RLC RX entity" << endl;
952-
if (oldDirection != newDirection) {
953-
if (switchPkt->getInterruptHarq()) {
954-
// Interrupt H-ARQ processes for SL
955-
MacNodeId id = peerId;
956-
for (auto& mrit : harqRxBuffers_) {
957-
HarqRxBuffers::iterator hit = mrit.second.find(id);
958-
if (hit != mrit.second.end()) {
959-
for (unsigned int proc = 0; proc < (unsigned int)UE_RX_HARQ_PROCESSES; proc++) {
960-
unsigned int numUnits = hit->second->getProcess(proc)->getNumHarqUnits();
961-
for (unsigned int i = 0; i < numUnits; i++) {
962-
hit->second->getProcess(proc)->purgeCorruptedPdu(i); // delete contained PDU
963-
hit->second->getProcess(proc)->resetCodeword(i); // reset unit
964-
}
958+
// Find the correct connections involved in the mode switch
959+
// Use two-phase approach: first collect, then process
960+
961+
// Phase 1: Collect CIDs and flow info that need processing
962+
std::vector<std::pair<MacCid, FlowControlInfo>> oldRxConnections;
963+
std::vector<std::pair<MacCid, FlowControlInfo>> newRxConnections;
964+
965+
for (const auto& [cid, lteInfo] : connDescIn_) {
966+
if (lteInfo.getD2dTxPeerId() == peerId && (Direction)lteInfo.getDirection() == oldDirection) {
967+
oldRxConnections.emplace_back(cid, lteInfo);
968+
}
969+
else if (lteInfo.getD2dTxPeerId() == peerId && (Direction)lteInfo.getDirection() == newDirection) {
970+
newRxConnections.emplace_back(cid, lteInfo);
971+
}
972+
}
973+
974+
// Phase 2: Process old RX connections
975+
for (const auto& [cid, lteInfo] : oldRxConnections) {
976+
EV << NOW << " LteMacUeD2D::macHandleD2DModeSwitch - found old connection with cid " << cid << ", send signal to the RLC RX entity" << endl;
977+
if (oldDirection != newDirection) {
978+
if (switchPkt->getInterruptHarq()) {
979+
// Interrupt H-ARQ processes for SL
980+
MacNodeId id = peerId;
981+
for (auto& mrit : harqRxBuffers_) {
982+
HarqRxBuffers::iterator hit = mrit.second.find(id);
983+
if (hit != mrit.second.end()) {
984+
for (unsigned int proc = 0; proc < (unsigned int)UE_RX_HARQ_PROCESSES; proc++) {
985+
unsigned int numUnits = hit->second->getProcess(proc)->getNumHarqUnits();
986+
for (unsigned int i = 0; i < numUnits; i++) {
987+
hit->second->getProcess(proc)->purgeCorruptedPdu(i); // delete contained PDU
988+
hit->second->getProcess(proc)->resetCodeword(i); // reset unit
965989
}
966990
}
967991
}
968-
969-
// Clear mirror H-ARQ buffers
970-
enb_->deleteHarqBuffersMirrorD2D(peerId, nodeId_);
971-
972-
// Notify that this UE is switching during this TTI
973-
resetHarq_[peerId] = NOW;
974992
}
975993

976-
auto pktDup = pkt->dup();
977-
auto switchPkt_dup = pktDup->removeAtFront<D2DModeSwitchNotification>();
978-
switchPkt_dup->setOldConnection(true);
979-
pktDup->insertAtFront(switchPkt_dup);
980-
*(pktDup->addTagIfAbsent<FlowControlInfo>()) = *lteInfo;
981-
sendUpperPackets(pktDup);
994+
// Clear mirror H-ARQ buffers
995+
enb_->deleteHarqBuffersMirrorD2D(peerId, nodeId_);
996+
997+
// Notify that this UE is switching during this TTI
998+
resetHarq_[peerId] = NOW;
982999
}
1000+
1001+
auto pktDup = pkt->dup();
1002+
auto switchPkt_dup = pktDup->removeAtFront<D2DModeSwitchNotification>();
1003+
switchPkt_dup->setOldConnection(true);
1004+
pktDup->insertAtFront(switchPkt_dup);
1005+
*(pktDup->addTagIfAbsent<FlowControlInfo>()) = lteInfo;
1006+
sendUpperPackets(pktDup);
9831007
}
984-
else if (lteInfo->getD2dTxPeerId() == peerId && (Direction)lteInfo->getDirection() == newDirection) {
985-
EV << NOW << " LteMacUeD2D::macHandleD2DModeSwitch - found new connection with cid " << cid << ", send signal to the RLC RX entity" << endl;
986-
if (oldDirection != newDirection) {
987-
988-
auto pktDup = pkt->dup();
989-
auto switchPkt_dup = pktDup->removeAtFront<D2DModeSwitchNotification>();
990-
switchPkt_dup->setOldConnection(false);
991-
pktDup->insertAtFront(switchPkt_dup);
992-
*(pktDup->addTagIfAbsent<FlowControlInfo>()) = *lteInfo;
993-
sendUpperPackets(pktDup);
994-
}
1008+
}
1009+
1010+
// Phase 3: Process new RX connections
1011+
for (const auto& [cid, lteInfo] : newRxConnections) {
1012+
EV << NOW << " LteMacUeD2D::macHandleD2DModeSwitch - found new connection with cid " << cid << ", send signal to the RLC RX entity" << endl;
1013+
if (oldDirection != newDirection) {
1014+
auto pktDup = pkt->dup();
1015+
auto switchPkt_dup = pktDup->removeAtFront<D2DModeSwitchNotification>();
1016+
switchPkt_dup->setOldConnection(false);
1017+
pktDup->insertAtFront(switchPkt_dup);
1018+
*(pktDup->addTagIfAbsent<FlowControlInfo>()) = lteInfo;
1019+
sendUpperPackets(pktDup);
9951020
}
9961021
}
9971022
}

0 commit comments

Comments
 (0)