1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2025-06-07 16:55:23 +02:00

DCCQueue memory leak fix

This commit is contained in:
Asbelos 2025-05-28 20:40:57 +01:00
parent 4cb09e11a5
commit f163e171e4
3 changed files with 29 additions and 31 deletions

View File

@ -62,6 +62,21 @@ uint16_t DCCQueue::lastSentPacketLocoId=0; // used to prevent two packets to the
recycleList=p; recycleList=p;
} }
void DCCQueue::remove(PendingSlot* premove) {
PendingSlot* previous=nullptr;
for (auto p=head;p;previous=p,p=p->next) {
if (p==premove) {
// remove this slot from the queue
if (previous) previous->next=p->next;
else head=p->next;
if (p==tail) tail=previous; // if last packet, update tail
return;
}
}
DIAG(F("DCCQueue::remove slot not found"));
}
// Packet joins end of low priority queue. // Packet joins end of low priority queue.
void DCCQueue::scheduleDCCPacket(byte* packet, byte length, byte repeats, uint16_t loco) { void DCCQueue::scheduleDCCPacket(byte* packet, byte length, byte repeats, uint16_t loco) {
lowPriorityQueue->addQueue(getSlot(NORMAL_PACKET,packet,length,repeats,loco)); lowPriorityQueue->addQueue(getSlot(NORMAL_PACKET,packet,length,repeats,loco));
@ -73,10 +88,6 @@ uint16_t DCCQueue::lastSentPacketLocoId=0; // used to prevent two packets to the
for (auto p=highPriorityQueue->head;p;p=p->next) { for (auto p=highPriorityQueue->head;p;p=p->next) {
if (p->locoId==loco) { if (p->locoId==loco) {
// replace existing packet // replace existing packet
if (length>sizeof(p->packet)) {
DIAG(F("DCC bad packet length=%d"),length);
length=sizeof(p->packet); // limit to size of packet
}
memcpy(p->packet,packet,length); memcpy(p->packet,packet,length);
p->packetLength=length; p->packetLength=length;
p->packetRepeat=repeats; p->packetRepeat=repeats;
@ -98,22 +109,13 @@ uint16_t DCCQueue::lastSentPacketLocoId=0; // used to prevent two packets to the
// kill any existing throttle packets for this loco (or all locos if broadcast) // kill any existing throttle packets for this loco (or all locos if broadcast)
// this will also remove any estop packets for this loco (or all locos if broadcast) but they will be replaced // this will also remove any estop packets for this loco (or all locos if broadcast) but they will be replaced
PendingSlot * previous=nullptr; PendingSlot * pNext;
auto p=highPriorityQueue->head; for (auto p=highPriorityQueue->head;p;p=pNext) {
while(p) { auto pNext=p->next; // save next packet in case we recycle this one
if (p->type!=ACC_OFF_PACKET && (loco==0 || p->locoId==loco)) { if (p->type!=ACC_OFF_PACKET && (loco==0 || p->locoId==loco)) {
// drop this packet from the highPriority queue // remove this slot from the queue or it will interfere with our ESTOP
if (previous) previous->next=p->next; highPriorityQueue->remove(p);
else highPriorityQueue->head=p->next;
recycle(p); // recycle this slot recycle(p); // recycle this slot
// address next packet
p=previous?previous->next : highPriorityQueue->head;
}
else {
previous=p;
p=p->next;
} }
} }
// add the estop packet to the start of the queue // add the estop packet to the start of the queue
@ -149,8 +151,8 @@ uint16_t DCCQueue::lastSentPacketLocoId=0; // used to prevent two packets to the
} }
bool DCCQueue::scheduleNextInternal() { bool DCCQueue::scheduleNextInternal() {
PendingSlot* previous=nullptr;
for (auto p=head;p;previous=p,p=p->next) { for (auto p=head;p;p=p->next) {
// skip over pending ACC_OFF packets which are still delayed // skip over pending ACC_OFF packets which are still delayed
if (p->type == ACC_OFF_PACKET && millis()<p->startTime) continue; if (p->type == ACC_OFF_PACKET && millis()<p->startTime) continue;
if (p->locoId) { if (p->locoId) {
@ -171,9 +173,7 @@ uint16_t DCCQueue::lastSentPacketLocoId=0; // used to prevent two packets to the
} }
// remove this slot from the queue // remove this slot from the queue
if (previous) previous->next=p->next; remove(p);
else head=p->next;
if (!head) tail=nullptr;
// special cases handling // special cases handling
if (p->type == ACC_ON_PACKET) { if (p->type == ACC_ON_PACKET) {
@ -182,11 +182,8 @@ uint16_t DCCQueue::lastSentPacketLocoId=0; // used to prevent two packets to the
p->packet[1] &= ~0x08; // set C to 0 (gate off) p->packet[1] &= ~0x08; // set C to 0 (gate off)
p->startTime=millis()+p->delayOff; p->startTime=millis()+p->delayOff;
highPriorityQueue->jumpQueue(p); highPriorityQueue->jumpQueue(p);
return true;
} }
else recycle(p);
// Recycle packet just consumed
recycle(p);
return true; return true;
} }
@ -209,7 +206,7 @@ uint16_t DCCQueue::lastSentPacketLocoId=0; // used to prevent two packets to the
for (auto p=lowPriorityQueue->head;p;p=p->next) q2++; for (auto p=lowPriorityQueue->head;p;p=p->next) q2++;
bool leak=(q1+q2)!=created; bool leak=(q1+q2)!=created;
DIAG(F("New DCC queue slot type=%d length=%d loco=%d q1=%d q2=%d created=%d"), DIAG(F("New DCC queue slot type=%d length=%d loco=%d q1=%d q2=%d created=%d"),
type,length,loco,q1,q2, created); (int16_t)type,length,loco,q1,q2, created);
if (leak) { if (leak) {
for (auto p=highPriorityQueue->head;p;p=p->next) DIAG(F("q1 %d %d"),p->type,p->locoId); for (auto p=highPriorityQueue->head;p;p=p->next) DIAG(F("q1 %d %d"),p->type,p->locoId);
for (auto p=lowPriorityQueue->head;p;p=p->next) DIAG(F("q2 %d %d"),p->type,p->locoId); for (auto p=lowPriorityQueue->head;p;p=p->next) DIAG(F("q2 %d %d"),p->type,p->locoId);

View File

@ -78,6 +78,6 @@ class DCCQueue {
static void recycle(PendingSlot* p); static void recycle(PendingSlot* p);
void addQueue(PendingSlot * p); void addQueue(PendingSlot * p);
void jumpQueue(PendingSlot * p); void jumpQueue(PendingSlot * p);
void remove(PendingSlot * p);
}; };
#endif #endif // DCCQueue_h

View File

@ -3,7 +3,8 @@
#include "StringFormatter.h" #include "StringFormatter.h"
#define VERSION "5.5.27" #define VERSION "5.5.28"
// 5.5.28 - DCC Queue memory leak fix
// 5.5.27 - PCF8574 output pin initialization parameter // 5.5.27 - PCF8574 output pin initialization parameter
// 5.5.26 - PCA9554 and TCA9554/9534 I2C 8-bit GPIO expander drivers // 5.5.26 - PCA9554 and TCA9554/9534 I2C 8-bit GPIO expander drivers
// 5.2.25 - IO_Bitmap and assicated Exrail macros // 5.2.25 - IO_Bitmap and assicated Exrail macros