sched/timer: Fix timer accuracy problems
This commit fixed timer accuracy problems when repetitive timer is set. Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
This commit is contained in:
parent
756faf3cc9
commit
a483c884ce
@ -58,7 +58,9 @@ struct posix_timer_s
|
||||
uint8_t pt_flags; /* See PT_FLAGS_* definitions */
|
||||
uint8_t pt_crefs; /* Reference count */
|
||||
pid_t pt_owner; /* Creator of timer */
|
||||
int pt_delay; /* If non-zero, used to reset repetitive timers */
|
||||
int pt_overrun; /* Overrun time */
|
||||
sclock_t pt_delay; /* If non-zero, used to reset repetitive timers */
|
||||
clock_t pt_expected; /* Expected absolute time */
|
||||
struct wdog_s pt_wdog; /* The watchdog that provides the timing */
|
||||
struct sigevent pt_event; /* Notification information */
|
||||
struct sigwork_s pt_work;
|
||||
|
@ -183,6 +183,7 @@ int timer_create(clockid_t clockid, FAR struct sigevent *evp,
|
||||
ret->pt_crefs = 1;
|
||||
ret->pt_owner = nxsched_getpid();
|
||||
ret->pt_delay = 0;
|
||||
ret->pt_expected = 0;
|
||||
|
||||
/* Was a struct sigevent provided? */
|
||||
|
||||
|
@ -77,9 +77,18 @@
|
||||
|
||||
int timer_getoverrun(timer_t timerid)
|
||||
{
|
||||
UNUSED(timerid);
|
||||
set_errno(EINVAL);
|
||||
return ERROR;
|
||||
FAR struct posix_timer_s *timer = timer_gethandle(timerid);
|
||||
int ret;
|
||||
|
||||
if (!timer)
|
||||
{
|
||||
set_errno(EINVAL);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
ret = timer->pt_overrun;
|
||||
|
||||
return ret > DELAYTIMER_MAX ? DELAYTIMER_MAX : ret;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DISABLE_POSIX_TIMERS */
|
||||
|
@ -96,11 +96,32 @@ static inline void timer_signotify(FAR struct posix_timer_s *timer)
|
||||
static inline void timer_restart(FAR struct posix_timer_s *timer,
|
||||
wdparm_t itimer)
|
||||
{
|
||||
clock_t ticks;
|
||||
sclock_t delay;
|
||||
|
||||
/* If this is a repetitive timer, then restart the watchdog */
|
||||
|
||||
if (timer->pt_delay)
|
||||
{
|
||||
wd_start(&timer->pt_wdog, timer->pt_delay, timer_timeout, itimer);
|
||||
/* Check whether next expected time is reached */
|
||||
|
||||
ticks = clock_systime_ticks();
|
||||
timer->pt_overrun = 0;
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
timer->pt_expected += timer->pt_delay;
|
||||
delay = timer->pt_expected - ticks;
|
||||
if (delay > 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
timer->pt_overrun++;
|
||||
}
|
||||
|
||||
wd_start_absolute(&timer->pt_wdog, timer->pt_expected,
|
||||
timer_timeout, itimer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -224,7 +245,6 @@ int timer_settime(timer_t timerid, int flags,
|
||||
FAR struct itimerspec *ovalue)
|
||||
{
|
||||
FAR struct posix_timer_s *timer = timer_gethandle(timerid);
|
||||
irqstate_t intflags;
|
||||
sclock_t delay;
|
||||
int ret = OK;
|
||||
|
||||
@ -272,29 +292,20 @@ int timer_settime(timer_t timerid, int flags,
|
||||
if (value->it_interval.tv_sec > 0 || value->it_interval.tv_nsec > 0)
|
||||
{
|
||||
delay = clock_time2ticks(&value->it_interval);
|
||||
|
||||
/* REVISIT: Should pt_delay be sclock_t? */
|
||||
|
||||
timer->pt_delay = (int)delay;
|
||||
timer->pt_delay = delay;
|
||||
}
|
||||
else
|
||||
{
|
||||
timer->pt_delay = 0;
|
||||
}
|
||||
|
||||
/* We need to disable timer interrupts through the following section so
|
||||
* that the system timer is stable.
|
||||
*/
|
||||
|
||||
intflags = enter_critical_section();
|
||||
|
||||
/* Check if abstime is selected */
|
||||
|
||||
if ((flags & TIMER_ABSTIME) != 0)
|
||||
{
|
||||
/* Calculate a delay corresponding to the absolute time in 'value' */
|
||||
|
||||
clock_abstime2ticks(timer->pt_clock, &value->it_value, &delay);
|
||||
timer->pt_expected = clock_time2ticks(&value->it_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -304,25 +315,13 @@ int timer_settime(timer_t timerid, int flags,
|
||||
*/
|
||||
|
||||
delay = clock_time2ticks(&value->it_value);
|
||||
}
|
||||
|
||||
/* If the specified time has already passed, the function shall succeed
|
||||
* and the expiration notification shall be made.
|
||||
*/
|
||||
|
||||
if (delay < 0)
|
||||
{
|
||||
delay = 0;
|
||||
timer->pt_expected = clock_systime_ticks() + delay;
|
||||
}
|
||||
|
||||
/* Then start the watchdog */
|
||||
|
||||
if (delay >= 0)
|
||||
{
|
||||
ret = wd_start(&timer->pt_wdog, delay, timer_timeout, (wdparm_t)timer);
|
||||
}
|
||||
|
||||
leave_critical_section(intflags);
|
||||
ret = wd_start_absolute(&timer->pt_wdog, timer->pt_expected,
|
||||
timer_timeout, (wdparm_t)timer);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user