This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 8e653753655a91829190c524e49aac3766336dc6 Author: ouyangxiangzhen <ouyangxiangz...@xiaomi.com> AuthorDate: Fri Mar 28 17:15:34 2025 +0800 sched: Remove unnecessary tick++ for absolute wdog timer. To improve the absolute timer accuracy, this commit move the tick++ to relative wdog timer. Signed-off-by: ouyangxiangzhen <ouyangxiangz...@xiaomi.com> --- sched/signal/sig_timedwait.c | 10 +++++++++- sched/timer/timer_settime.c | 11 ++++++++++- sched/wdog/wd_start.c | 40 ++++++++++++++++++---------------------- 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/sched/signal/sig_timedwait.c b/sched/signal/sig_timedwait.c index 219de4ee13..22cd6bd160 100644 --- a/sched/signal/sig_timedwait.c +++ b/sched/signal/sig_timedwait.c @@ -304,7 +304,15 @@ int nxsig_clockwait(int clockid, int flags, if ((flags & TIMER_ABSTIME) == 0) { - expect = clock_systime_ticks() + clock_time2ticks(rqtp); + /* delay+1 is to prevent the insufficient sleep time if we are + * currently near the boundary to the next tick. + * | current_tick | current_tick + 1 | current_tick + 2 | .... | + * | ^ Here we get the current tick + * In this case we delay 1 tick, timer will be triggered at + * current_tick + 1, which is not enough for at least 1 tick. + */ + + expect = clock_systime_ticks() + clock_time2ticks(rqtp) + 1; wd_start_abstick(&rtcb->waitdog, expect, nxsig_timeout, (uintptr_t)rtcb); } diff --git a/sched/timer/timer_settime.c b/sched/timer/timer_settime.c index 47e882ba21..9bc9578cb0 100644 --- a/sched/timer/timer_settime.c +++ b/sched/timer/timer_settime.c @@ -328,7 +328,16 @@ int timer_settime(timer_t timerid, int flags, */ delay = clock_time2ticks(&value->it_value); - timer->pt_expected = clock_systime_ticks() + delay; + + /* delay+1 is to prevent the insufficient sleep time if we are + * currently near the boundary to the next tick. + * | current_tick | current_tick + 1 | current_tick + 2 | .... | + * | ^ Here we get the current tick + * In this case we delay 1 tick, timer will be triggered at + * current_tick + 1, which is not enough for at least 1 tick. + */ + + timer->pt_expected = clock_systime_ticks() + delay + 1; } /* Then start the watchdog */ diff --git a/sched/wdog/wd_start.c b/sched/wdog/wd_start.c index 3d84dd2d3e..4741ac0a41 100644 --- a/sched/wdog/wd_start.c +++ b/sched/wdog/wd_start.c @@ -119,14 +119,10 @@ static void wdentry_period(wdparm_t arg) wdperiod->func(wdperiod->wdog.arg); - /* Since we set `ticks++` at `wd_start_abstick`, - * we need to use `expired - 1` here to avoid time drift. - */ - if (wdperiod->period != 0) { wd_start_abstick(&wdperiod->wdog, - wdperiod->wdog.expired + wdperiod->period - 1, + wdperiod->wdog.expired + wdperiod->period, wdentry_period, wdperiod->wdog.arg); } } @@ -323,23 +319,6 @@ int wd_start_abstick(FAR struct wdog_s *wdog, clock_t ticks, return -EINVAL; } - /* Calculate ticks+1, forcing the delay into a range that we can handle. - * - * NOTE that one is added to the delay. This is correct and must not be - * changed: The contract for the use wdog_start is that the wdog will - * delay FOR AT LEAST as long as requested, but may delay longer due to - * variety of factors. The wdog logic has no knowledge of the the phase - * of the system timer when it is started: The next timer interrupt may - * occur immediately or may be delayed for almost a full cycle. In order - * to meet the contract requirement, the requested time is also always - * incremented by one so that the delay is always at least as long as - * requested. - * - * There is extensive documentation about this time issue elsewhere. - */ - - ticks++; - /* NOTE: There is a race condition here... the caller may receive * the watchdog between the time that wd_start_abstick is called and * the critical section is established. @@ -437,6 +416,23 @@ int wd_start(FAR struct wdog_s *wdog, sclock_t delay, return -EINVAL; } + /* Calculate delay+1, forcing the delay into a range that we can handle. + * + * NOTE that one is added to the delay. This is correct and must not be + * changed: The contract for the use wdog_start is that the wdog will + * delay FOR AT LEAST as long as requested, but may delay longer due to + * variety of factors. The wdog logic has no knowledge of the the phase + * of the system timer when it is started: The next timer interrupt may + * occur immediately or may be delayed for almost a full cycle. In order + * to meet the contract requirement, the requested time is also always + * incremented by one so that the delay is always at least as long as + * requested. + * + * There is extensive documentation about this time issue elsewhere. + */ + + delay++; + return wd_start_abstick(wdog, clock_systime_ticks() + delay, wdentry, arg); }