Skip to content

Commit 69501b6

Browse files
committed
Fix #249: add reentrancy protection in engineUpdate()
1 parent ed69e67 commit 69501b6

File tree

2 files changed

+30
-3
lines changed

2 files changed

+30
-3
lines changed

src/lmic/lmic.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2453,8 +2453,9 @@ static void startRxPing (xref2osjob_t osjob) {
24532453
#endif // !DISABLE_PING
24542454

24552455

2456-
// Decide what to do next for the MAC layer of a device
2457-
static void engineUpdate (void) {
2456+
// Decide what to do next for the MAC layer of a device. Inner part.
2457+
// Only called from outer part.
2458+
static void engineUpdate_inner (void) {
24582459
#if LMIC_DEBUG_LEVEL > 0
24592460
LMIC_DEBUG_PRINTF("%"LMIC_PRId_ostime_t": engineUpdate, opmode=0x%x\n", os_getTime(), LMIC.opmode);
24602461
#endif
@@ -2637,6 +2638,24 @@ static void engineUpdate (void) {
26372638
os_setTimedCallback(&LMIC.osjob, txbeg-TX_RAMPUP, FUNC_ADDR(runEngineUpdate));
26382639
}
26392640

2641+
// Decide what to do next for the MAC layer of a device.
2642+
// Outer part. Safe to call from anywhere; defers if it
2643+
// detects a recursive call.
2644+
static void engineUpdate (void) {
2645+
lmic_engine_update_state_t state;
2646+
2647+
state = LMIC.engineUpdateState;
2648+
if (state == lmic_EngineUpdateState_idle) {
2649+
LMIC.engineUpdateState = lmic_EngineUpdateState_busy;
2650+
do {
2651+
engineUpdate_inner();
2652+
state = LMIC.engineUpdateState - 1;
2653+
LMIC.engineUpdateState = state;
2654+
} while (state != lmic_EngineUpdateState_idle);
2655+
} else {
2656+
LMIC.engineUpdateState = lmic_EngineUpdateState_again;
2657+
}
2658+
}
26402659

26412660
void LMIC_setAdrMode (bit_t enabled) {
26422661
LMIC.adrEnabled = enabled ? FCT_ADREN : 0;

src/lmic/lmic.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,14 @@ enum lmic_request_time_state_e {
360360

361361
typedef u1_t lmic_request_time_state_t;
362362

363+
enum lmic_engine_update_state_e {
364+
lmic_EngineUpdateState_idle = 0, // engineUpdate is idle.
365+
lmic_EngineUpdateState_busy = 1, // engineUpdate is busy, but has not been reentered.
366+
lmic_EngineUpdateState_again = 2, // engineUpdate is busy, and has to be evaluated again.
367+
};
368+
369+
typedef u1_t lmic_engine_update_state_t;
370+
363371
/*
364372
365373
Structure: lmic_client_data_t
@@ -480,7 +488,6 @@ struct lmic_t {
480488
#endif
481489

482490
/* (u)int16_t things */
483-
484491
rps_t rps; // radio parameter selections: SF, BW, CodingRate, NoCrc, implicit hdr
485492
u2_t opmode; // engineUpdate() operating mode flags
486493
u2_t devNonce; // last generated nonce
@@ -494,6 +501,7 @@ struct lmic_t {
494501
#endif
495502

496503
/* (u)int8_t things */
504+
lmic_engine_update_state_t engineUpdateState; // state of the engineUpdate() evaluator.
497505
s1_t rssi;
498506
s1_t snr; // LMIC.snr is SNR times 4
499507
u1_t rxsyms;

0 commit comments

Comments
 (0)