Skip to content

Pump link resource watchdogs outside the Transport jobs section - #103

Merged
attermann merged 1 commit into
attermann:masterfrom
tostolaza:fix/link-resource-tick-deadlock
Nov 10, 2026
Merged

attermann merged 1 commit into
attermann:masterfrom
tostolaza:fix/link-resource-tick-deadlock

Conversation

@tostolaza

Copy link
Copy Markdown
Contributor

Problem

Transport::jobs() sets _jobs_running = true and then calls Link::tick_resources() for every active link. A resource watchdog can send a packet, for example Resource::advertise_job re-sending an advertisement that got no part request. That packet goes through Transport::outbound(), which spins while _jobs_running is set. On single-threaded targets nothing clears the flag, so the loop never returns and the hardware watchdog resets the device.

Reproduce: nRF52840 node in transport mode serving a NomadNet page. A remote client opens a Link and requests the page over a lossy LoRa path. The log ends with:

[DBG] No part requests received, retrying resource advertisement...
[---] Resource::advertise_job: Re-sending resource advertisement packet
...
[DBG] Transport::outbound: jobs still running!

and the device resets after the 60 s watchdog.

Solution

Collect the active, non-closed links during jobs() and call tick_resources() after _jobs_running is cleared. This is the same pattern already used for announce retransmissions in outgoing.

Testing

  • MASN V1.2 (nRF52840) on hardware: 31 minutes in transport mode with remote Links and resource transfers, no resets (before the fix, a reset at the first resource retry).
  • Builds through microReticulum_Firmware: nRF52 (wiscore_rak4631, masn-ht-ra62) and ESP32-S3 (heltec_wifi_lora_32_V3).
  • Native: not tested.

🤖 Generated with Claude Code

Transport::jobs() sets _jobs_running and then calls Link::tick_resources().
A resource watchdog can send a packet (e.g. a Resource advertisement retry),
which ends up in Transport::outbound(). outbound() spins while
_jobs_running is set, so on single-threaded targets the loop never returns
and the hardware watchdog resets the device.

Collect the active links during jobs() and tick them after _jobs_running
is cleared, the same way announce retransmissions in `outgoing` are sent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@attermann

Copy link
Copy Markdown
Owner

Thanks @tostolaza, nice find, and thanks for the clear repro and the hardware soak test. Collecting the links and ticking them after _jobs_running is cleared matches how outgoing is already handled, so this looks right to me.

One small thing I'll check before merging: the new tick loop now sits outside the try/catch in jobs(), so an exception from a resource watchdog would no longer be caught and logged there. If you'd like to wrap that loop in the same kind of try/catch, feel free; otherwise I may add it when I merge.

@attermann
attermann merged commit 7aae4e6 into attermann:master Nov 10, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants