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
4 changed files with 43 additions and 32 deletions
|
@ -58,7 +58,9 @@ struct posix_timer_s
|
||||||
uint8_t pt_flags; /* See PT_FLAGS_* definitions */
|
uint8_t pt_flags; /* See PT_FLAGS_* definitions */
|
||||||
uint8_t pt_crefs; /* Reference count */
|
uint8_t pt_crefs; /* Reference count */
|
||||||
pid_t pt_owner; /* Creator of timer */
|
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 wdog_s pt_wdog; /* The watchdog that provides the timing */
|
||||||
struct sigevent pt_event; /* Notification information */
|
struct sigevent pt_event; /* Notification information */
|
||||||
struct sigwork_s pt_work;
|
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_crefs = 1;
|
||||||
ret->pt_owner = nxsched_getpid();
|
ret->pt_owner = nxsched_getpid();
|
||||||
ret->pt_delay = 0;
|
ret->pt_delay = 0;
|
||||||
|
ret->pt_expected = 0;
|
||||||
|
|
||||||
/* Was a struct sigevent provided? */
|
/* Was a struct sigevent provided? */
|
||||||
|
|
||||||
|
|
|
@ -77,9 +77,18 @@
|
||||||
|
|
||||||
int timer_getoverrun(timer_t timerid)
|
int timer_getoverrun(timer_t timerid)
|
||||||
{
|
{
|
||||||
UNUSED(timerid);
|
FAR struct posix_timer_s *timer = timer_gethandle(timerid);
|
||||||
set_errno(EINVAL);
|
int ret;
|
||||||
return ERROR;
|
|
||||||
|
if (!timer)
|
||||||
|
{
|
||||||
|
set_errno(EINVAL);
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = timer->pt_overrun;
|
||||||
|
|
||||||
|
return ret > DELAYTIMER_MAX ? DELAYTIMER_MAX : ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_DISABLE_POSIX_TIMERS */
|
#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,
|
static inline void timer_restart(FAR struct posix_timer_s *timer,
|
||||||
wdparm_t itimer)
|
wdparm_t itimer)
|
||||||
{
|
{
|
||||||
|
clock_t ticks;
|
||||||
|
sclock_t delay;
|
||||||
|
|
||||||
/* If this is a repetitive timer, then restart the watchdog */
|
/* If this is a repetitive timer, then restart the watchdog */
|
||||||
|
|
||||||
if (timer->pt_delay)
|
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 itimerspec *ovalue)
|
||||||
{
|
{
|
||||||
FAR struct posix_timer_s *timer = timer_gethandle(timerid);
|
FAR struct posix_timer_s *timer = timer_gethandle(timerid);
|
||||||
irqstate_t intflags;
|
|
||||||
sclock_t delay;
|
sclock_t delay;
|
||||||
int ret = OK;
|
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)
|
if (value->it_interval.tv_sec > 0 || value->it_interval.tv_nsec > 0)
|
||||||
{
|
{
|
||||||
delay = clock_time2ticks(&value->it_interval);
|
delay = clock_time2ticks(&value->it_interval);
|
||||||
|
timer->pt_delay = delay;
|
||||||
/* REVISIT: Should pt_delay be sclock_t? */
|
|
||||||
|
|
||||||
timer->pt_delay = (int)delay;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
timer->pt_delay = 0;
|
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 */
|
/* Check if abstime is selected */
|
||||||
|
|
||||||
if ((flags & TIMER_ABSTIME) != 0)
|
if ((flags & TIMER_ABSTIME) != 0)
|
||||||
{
|
{
|
||||||
/* Calculate a delay corresponding to the absolute time in 'value' */
|
/* 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
|
else
|
||||||
{
|
{
|
||||||
|
@ -304,25 +315,13 @@ int timer_settime(timer_t timerid, int flags,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
delay = clock_time2ticks(&value->it_value);
|
delay = clock_time2ticks(&value->it_value);
|
||||||
}
|
timer->pt_expected = clock_systime_ticks() + delay;
|
||||||
|
|
||||||
/* If the specified time has already passed, the function shall succeed
|
|
||||||
* and the expiration notification shall be made.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (delay < 0)
|
|
||||||
{
|
|
||||||
delay = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Then start the watchdog */
|
/* Then start the watchdog */
|
||||||
|
|
||||||
if (delay >= 0)
|
ret = wd_start_absolute(&timer->pt_wdog, timer->pt_expected,
|
||||||
{
|
timer_timeout, (wdparm_t)timer);
|
||||||
ret = wd_start(&timer->pt_wdog, delay, timer_timeout, (wdparm_t)timer);
|
|
||||||
}
|
|
||||||
|
|
||||||
leave_critical_section(intflags);
|
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue