From a085fd871030f10268f39a31eb0dfdf0d19ab3a7 Mon Sep 17 00:00:00 2001 From: Lukas Zeller Date: Thu, 17 Aug 2023 22:41:34 +0200 Subject: [PATCH] SystemLayerImplSelect: libev: avoid timers firing slightly too early (#28434) This fixes a ReportEngine problem that was caused by libev based timers firing slightly (in the range of 20mS) too early, because libev by default uses the time when events started processing as the "now" reference for relative timers for efficiency reasons. To ensure timers cannot fire early, timer setup must compensate for any difference between ev_now() which is the time events started processing and ev_time(), which is the actual current time (but is a bit less efficient to obtain). # Conflicts: # src/system/SystemLayerImplSelect.cpp --- src/system/SystemLayerImplSelect.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/system/SystemLayerImplSelect.cpp b/src/system/SystemLayerImplSelect.cpp index 9eb0b2ece2864b..9b1ce3bc265dba 100644 --- a/src/system/SystemLayerImplSelect.cpp +++ b/src/system/SystemLayerImplSelect.cpp @@ -184,7 +184,12 @@ CHIP_ERROR LayerImplSelect::StartTimer(Clock::Timeout delay, TimerCompleteCallba ev_timer_init(&timer->mLibEvTimer, &LayerImplSelect::HandleLibEvTimer, 1, 0); timer->mLibEvTimer.data = timer; auto t = Clock::Milliseconds64(delay).count(); - ev_timer_set(&timer->mLibEvTimer, static_cast(t) / 1E3, 0.); + // Note: libev uses the time when events started processing as the "now" reference for relative timers, + // for efficiency reasons. This point in time is represented by ev_now(). + // The real time is represented by ev_time(). + // As some chip code relies on timers to fire NEVER even only a bit early, we must increase the + // relative value passed to ev_timer_set(). + ev_timer_set(&timer->mLibEvTimer, (static_cast(t) / 1E3) + ev_time() - ev_now(mLibEvLoopP), 0.); (void) mTimerList.Add(timer); ev_timer_start(mLibEvLoopP, &timer->mLibEvTimer); return CHIP_NO_ERROR;