From 54b3573761524e264ca24ae8bde9ad33855af188 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Sat, 7 Feb 2026 20:36:06 -0800 Subject: [PATCH] [coap] optimize retransmission timer scheduling (#12366) This commit optimizes the CoAP retransmission timer logic by removing the `ScheduleRetransmissionTimer()` method, which iterated over all pending requests to determine the next fire time. The logic is updated as follows: - `HandleRetransmissionTimer()` now determines the next fire time while iterating over the `mPendingRequests` list to process retransmissions. This avoids a redundant second pass over the list. - `NextFireTime` is used to track the earliest fire time. - `CopyAndEnqueueMessage()` uses `Timer::FireAtIfEarlier()` to update the timer only if the new message's fire time is earlier than the current schedule. - `DequeueMessage()` no longer triggers a schedule update. If the dequeued message was the next to expire, the timer will fire, perform no actions, and then reschedule itself. --- src/core/coap/coap.cpp | 57 +++++++++++++----------------------------- src/core/coap/coap.hpp | 1 - 2 files changed, 17 insertions(+), 41 deletions(-) diff --git a/src/core/coap/coap.cpp b/src/core/coap/coap.cpp index 77fc841c0..fb0ce6195 100644 --- a/src/core/coap/coap.cpp +++ b/src/core/coap/coap.cpp @@ -483,31 +483,6 @@ exit: return error; } -void CoapBase::ScheduleRetransmissionTimer(void) -{ - NextFireTime nextTime; - Metadata metadata; - - for (const Message &message : mPendingRequests) - { - metadata.ReadFrom(message); - -#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE - if (metadata.IsObserveSubscription()) - { - // This is an RFC7641 subscription which is already acknowledged. - // We do not time it out, so skip it when determining the next - // fire time. - continue; - } -#endif - - nextTime.UpdateIfEarlier(metadata.mTimerFireTime); - } - - mRetransmissionTimer.FireAt(nextTime); -} - void CoapBase::HandleRetransmissionTimer(Timer &aTimer) { static_cast(static_cast(aTimer).GetContext())->HandleRetransmissionTimer(); @@ -515,7 +490,7 @@ void CoapBase::HandleRetransmissionTimer(Timer &aTimer) void CoapBase::HandleRetransmissionTimer(void) { - TimeMilli now = TimerMilli::GetNow(); + NextFireTime nextTime; Metadata metadata; Ip6::MessageInfo messageInfo; @@ -523,22 +498,25 @@ void CoapBase::HandleRetransmissionTimer(void) { metadata.ReadFrom(message); - if (now >= metadata.mTimerFireTime) - { #if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE - if (metadata.IsObserveSubscription()) - { - continue; - } + if (metadata.IsObserveSubscription()) + { + // This is an RFC7641 subscription which is already + // acknowledged. We do not time it out, so skip it when + // determining the next fire time. + continue; + } #endif + if (nextTime.GetNow() >= metadata.mTimerFireTime) + { if (!metadata.ShouldRetransmit()) { FinalizeCoapTransaction(message, metadata, nullptr, kErrorResponseTimeout); continue; } - metadata.UpdateRetxCounterAndTimeout(now); + metadata.UpdateRetxCounterAndTimeout(nextTime.GetNow()); metadata.UpdateIn(message); if (!metadata.mAcknowledged) @@ -547,9 +525,11 @@ void CoapBase::HandleRetransmissionTimer(void) SendCopy(message, messageInfo); } } + + nextTime.UpdateIfEarlier(metadata.mTimerFireTime); } - ScheduleRetransmissionTimer(); + mRetransmissionTimer.FireAt(nextTime); } void CoapBase::FinalizeCoapTransaction(Message &aRequest, const Metadata &aMetadata, Msg *aResponse, Error aResult) @@ -597,18 +577,15 @@ Message *CoapBase::CopyAndEnqueueMessage(const Message &aMessage, uint16_t aCopy SuccessOrExit(error = aMetadata.AppendTo(*messageCopy)); mPendingRequests.Enqueue(*messageCopy); - ScheduleRetransmissionTimer(); + + mRetransmissionTimer.FireAtIfEarlier(aMetadata.mTimerFireTime); exit: FreeAndNullMessageOnError(messageCopy, error); return messageCopy; } -void CoapBase::DequeueMessage(Message &aMessage) -{ - mPendingRequests.DequeueAndFree(aMessage); - ScheduleRetransmissionTimer(); -} +void CoapBase::DequeueMessage(Message &aMessage) { mPendingRequests.DequeueAndFree(aMessage); } void CoapBase::SendCopy(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { diff --git a/src/core/coap/coap.hpp b/src/core/coap/coap.hpp index de3f72ece..25370806a 100644 --- a/src/core/coap/coap.hpp +++ b/src/core/coap/coap.hpp @@ -847,7 +847,6 @@ private: Message *InitMessage(Message *aMessage, Type aType, Uri aUri); Message *InitResponse(Message *aMessage, const Message &aRequest); - void ScheduleRetransmissionTimer(void); static void HandleRetransmissionTimer(Timer &aTimer); void HandleRetransmissionTimer(void); void ClearRequests(const Ip6::Address *aAddress);