Skip to content

Commit 7505fd9

Browse files
committed
Guard the deferred local queue and depth counter
1 parent 9c260ad commit 7505fd9

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
@@ -1227,6 +1227,7 @@ NodeNum Router::getNodeNum()
12271227

12281228
bool Router::enqueueDeferredLocal(meshtastic_MeshPacket *p, RxSource src)
12291229
{
1230+
concurrency::LockGuard g(&deferredLock);
12301231
if (deferredLocalCount >= deferredLocalCapacity)
12311232
return false;
12321233
uint8_t tail = (deferredLocalHead + deferredLocalCount) % deferredLocalCapacity;
@@ -1238,6 +1239,7 @@ bool Router::enqueueDeferredLocal(meshtastic_MeshPacket *p, RxSource src)
12381239

12391240
bool Router::dequeueDeferredLocal(DeferredLocal &out)
12401241
{
1242+
concurrency::LockGuard g(&deferredLock);
12411243
if (deferredLocalCount == 0)
12421244
return false;
12431245
out = deferredLocalQueue[deferredLocalHead];
@@ -1249,7 +1251,12 @@ bool Router::dequeueDeferredLocal(DeferredLocal &out)
12491251
void Router::deliverLocal(meshtastic_MeshPacket *p, RxSource src)
12501252
{
12511253
// Top level: handle synchronously, exactly as before the depth guard existed.
1252-
if (handleDepth == 0) {
1254+
bool nested;
1255+
{
1256+
concurrency::LockGuard g(&deferredLock);
1257+
nested = handleDepth > 0;
1258+
}
1259+
if (!nested) {
12531260
handleReceived(p, src);
12541261
return;
12551262
}
@@ -1278,29 +1285,36 @@ void Router::deliverLocal(meshtastic_MeshPacket *p, RxSource src)
12781285
*/
12791286
void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
12801287
{
1281-
handleDepth++;
1288+
{
1289+
concurrency::LockGuard g(&deferredLock);
1290+
handleDepth++;
12821291
#ifdef PIO_UNIT_TESTING
1283-
if (handleDepth > maxHandleDepthObserved)
1284-
maxHandleDepthObserved = handleDepth;
1292+
if (handleDepth > maxHandleDepthObserved)
1293+
maxHandleDepthObserved = handleDepth;
12851294
#endif
1295+
}
12861296

12871297
dispatchReceived(p, src);
12881298

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

1303-
handleDepth--;
1314+
{
1315+
concurrency::LockGuard g(&deferredLock);
1316+
handleDepth--;
1317+
}
13041318
}
13051319

13061320
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)