Skip to content

Commit 2e87743

Browse files
committed
Guard the deferred local queue and depth counter
1 parent 9860cba commit 2e87743

2 files changed

Lines changed: 31 additions & 12 deletions

File tree

src/mesh/Router.cpp

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,6 +1224,7 @@ NodeNum Router::getNodeNum()
12241224

12251225
bool Router::enqueueDeferredLocal(meshtastic_MeshPacket *p, RxSource src)
12261226
{
1227+
concurrency::LockGuard g(&deferredLock);
12271228
if (deferredLocalCount >= deferredLocalCapacity)
12281229
return false;
12291230
uint8_t tail = (deferredLocalHead + deferredLocalCount) % deferredLocalCapacity;
@@ -1235,6 +1236,7 @@ bool Router::enqueueDeferredLocal(meshtastic_MeshPacket *p, RxSource src)
12351236

12361237
bool Router::dequeueDeferredLocal(DeferredLocal &out)
12371238
{
1239+
concurrency::LockGuard g(&deferredLock);
12381240
if (deferredLocalCount == 0)
12391241
return false;
12401242
out = deferredLocalQueue[deferredLocalHead];
@@ -1246,7 +1248,12 @@ bool Router::dequeueDeferredLocal(DeferredLocal &out)
12461248
void Router::deliverLocal(meshtastic_MeshPacket *p, RxSource src)
12471249
{
12481250
// Top level: handle synchronously, exactly as before the depth guard existed.
1249-
if (handleDepth == 0) {
1251+
bool nested;
1252+
{
1253+
concurrency::LockGuard g(&deferredLock);
1254+
nested = handleDepth > 0;
1255+
}
1256+
if (!nested) {
12501257
handleReceived(p, src);
12511258
return;
12521259
}
@@ -1275,29 +1282,36 @@ void Router::deliverLocal(meshtastic_MeshPacket *p, RxSource src)
12751282
*/
12761283
void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
12771284
{
1278-
handleDepth++;
1285+
{
1286+
concurrency::LockGuard g(&deferredLock);
1287+
handleDepth++;
12791288
#ifdef PIO_UNIT_TESTING
1280-
if (handleDepth > maxHandleDepthObserved)
1281-
maxHandleDepthObserved = handleDepth;
1289+
if (handleDepth > maxHandleDepthObserved)
1290+
maxHandleDepthObserved = handleDepth;
12821291
#endif
1292+
}
12831293

12841294
dispatchReceived(p, src);
12851295

1286-
// Only the outermost frame drains. Deferred packets were produced by modules sending from
1287-
// inside dispatchReceived()'s callModules(); process them here, after the triggering frame has
1288-
// unwound, so a second handleReceived() never sits on top of a module handler. handleDepth
1289-
// stays >= 1 through the drain, so a drained packet whose own modules send more loopback
1290-
// packets enqueues them for this same loop rather than recursing: the stack stays flat and
1291-
// processing is breadth-first.
1292-
if (handleDepth == 1) {
1296+
// Only the outermost frame drains, after the triggering frame unwound, so a second
1297+
// handleReceived() never sits on a module handler. Depth stays >=1, keeping the drain flat.
1298+
bool outermost;
1299+
{
1300+
concurrency::LockGuard g(&deferredLock);
1301+
outermost = handleDepth == 1;
1302+
}
1303+
if (outermost) {
12931304
DeferredLocal d;
12941305
while (dequeueDeferredLocal(d)) {
12951306
dispatchReceived(d.p, d.src);
12961307
packetPool.release(d.p);
12971308
}
12981309
}
12991310

1300-
handleDepth--;
1311+
{
1312+
concurrency::LockGuard g(&deferredLock);
1313+
handleDepth--;
1314+
}
13011315
}
13021316

13031317
void Router::dispatchReceived(meshtastic_MeshPacket *p, RxSource src)

src/mesh/Router.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "PacketHistory.h"
88
#include "PointerQueue.h"
99
#include "RadioInterface.h"
10+
#include "concurrency/LockGuard.h"
1011
#include "concurrency/OSThread.h"
1112
#include <memory>
1213

@@ -192,6 +193,10 @@ class Router : protected concurrency::OSThread, protected PacketHistory
192193
/// so a locally-sent loopback packet must be deferred rather than handled synchronously.
193194
uint8_t handleDepth = 0;
194195

196+
/// Guards handleDepth and the deferred ring below. nRF52 drives the router from the BLE task as
197+
/// well as the loop task, so both are read-modify-written from two tasks.
198+
concurrency::Lock deferredLock;
199+
195200
/// A local loopback packet whose handleReceived() was deferred because it was produced from
196201
/// inside callModules(). The queue owns the packet; its RxSource travels with it so the drain
197202
/// dispatches it with the origin the sender intended (RX_SRC_LOCAL stays local).

0 commit comments

Comments
 (0)