Skip to content

Commit 5d1af36

Browse files
rx_session_scan()
1 parent 208c11f commit 5d1af36

File tree

1 file changed

+28
-15
lines changed

1 file changed

+28
-15
lines changed

libcanard/canard.c

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1289,24 +1289,35 @@ static void rx_session_destroy(rx_session_t* const ses)
12891289
mem_free(sub->owner->mem.rx_session, sizeof(rx_session_t), ses);
12901290
}
12911291

1292-
// Returns the most recently updated slot timestamp. At the same time purges stale slots to reclaim memory early.
1292+
typedef struct
1293+
{
1294+
canard_us_t latest_sof_at;
1295+
byte_t in_progress_slots;
1296+
} rx_session_state_t;
1297+
1298+
// Checks the state and purges stale slots to reclaim memory early.
12931299
// A slot is stale if it's been idle for a very long time that is usually much larger than the transfer-ID timeout.
1294-
static canard_us_t rx_session_scan(rx_session_t* const ses, const canard_us_t now)
1300+
static rx_session_state_t rx_session_scan(rx_session_t* const ses, const canard_us_t now)
12951301
{
1296-
const canard_us_t deadline = now - later(RX_SESSION_TIMEOUT, ses->owner->transfer_id_timeout);
1297-
canard_us_t latest = BIG_BANG;
1302+
const canard_us_t deadline = now - later(RX_SESSION_TIMEOUT, ses->owner->transfer_id_timeout);
1303+
rx_session_state_t out = { .latest_sof_at = BIG_BANG, .in_progress_slots = 0 };
12981304
FOREACH_SLOT (i) {
12991305
const rx_slot_t* const slot = ses->slots[i];
1300-
if (slot != NULL) {
1301-
if (slot->timestamp < deadline) {
1302-
rx_slot_destroy(ses->owner, ses->slots[i]);
1303-
ses->slots[i] = NULL;
1304-
} else {
1305-
latest = later(latest, slot->timestamp);
1306+
if (slot == NULL) {
1307+
continue;
1308+
}
1309+
CANARD_ASSERT(slot->timestamp >= 0);
1310+
if (slot->timestamp < deadline) { // Too old, destroy even if in progress -- unlikely to complete anyway.
1311+
rx_slot_destroy(ses->owner, ses->slots[i]);
1312+
ses->slots[i] = NULL;
1313+
} else {
1314+
out.latest_sof_at = later(out.latest_sof_at, slot->timestamp);
1315+
if (slot->total_payload_size > 0) {
1316+
out.in_progress_slots++;
13061317
}
13071318
}
13081319
}
1309-
return latest;
1320+
return out;
13101321
}
13111322

13121323
// Returns false on OOM, no other failure modes. Stores at most extent bytes.
@@ -1431,16 +1442,18 @@ void canard_poll(canard_t* const self, const uint_least8_t tx_ready_iface_bitmap
14311442

14321443
// Drop stale sessions to reclaim memory. This happens when remote peers cease sending data.
14331444
// The oldest is held alive until its session timeout has expired, but notice that it may be different
1434-
// depending on the subscription instance if very large transfer-ID values are used (which is not expected).
1445+
// depending on the subscription instance if large transfer-ID values are used.
14351446
// This means that a stale session that belongs to a subscription with a long timeout may keep other sessions
14361447
// with a shorter timeout alive beyond their expiration time.
14371448
// We accept this because it does not affect correctness (the transfer-ID timeout is checked on reception
14381449
// always); the only downside is that memory reclamation time is bounded in the worst case by the longest
14391450
// transfer-ID timeout among all subscriptions, but this is a reasonable tradeoff for the reduced complexity.
14401451
rx_session_t* const ses = LIST_HEAD(self->rx.list_session_by_animation, rx_session_t, list_animation);
1441-
if ((ses != NULL) &&
1442-
(rx_session_scan(ses, now) < (now - later(RX_SESSION_TIMEOUT, ses->owner->transfer_id_timeout)))) {
1443-
rx_session_destroy(ses);
1452+
if (ses != NULL) {
1453+
const rx_session_state_t state = rx_session_scan(ses, now);
1454+
if ((state.in_progress_slots == 0) && (state.latest_sof_at < (now - ses->owner->transfer_id_timeout))) {
1455+
rx_session_destroy(ses);
1456+
}
14441457
}
14451458

14461459
// Process the TX pipeline.

0 commit comments

Comments
 (0)