Module: xenomai-3 Branch: next Commit: f111afaa7b2e210bc53323ac75e56b8f48231c1e URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=f111afaa7b2e210bc53323ac75e56b8f48231c1e
Author: Gilles Chanteperdrix <gilles.chanteperd...@xenomai.org> Date: Sat Nov 28 08:18:38 2015 +0100 cobalt/timer: avoid early tick in case of overrun There is a race condition in the current timer code when a timer period is close to the maximum jitter. It may happen that the next timer interrupt is already pending while xntimer_get_overruns computes the count of overruns. In that case, the count of overruns returned to user-space is one too much, and the application ends up expecting the next tick one period later than when it will actually happens. Avoid that problem by advancing the timer in xntimer_get_overruns. --- kernel/cobalt/timer.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/kernel/cobalt/timer.c b/kernel/cobalt/timer.c index ee0bb87..31a431b 100644 --- a/kernel/cobalt/timer.c +++ b/kernel/cobalt/timer.c @@ -63,6 +63,19 @@ int xntimer_heading_p(struct xntimer *timer) return 0; } +void xntimer_enqueue_and_program(struct xntimer *timer, xntimerq_t *q) +{ + xntimer_enqueue(timer, q); + if (xntimer_heading_p(timer)) { + struct xnsched *sched = xntimer_sched(timer); + struct xnclock *clock = xntimer_clock(timer); + if (sched != xnsched_current()) + xnclock_remote_shot(clock, sched); + else + xnclock_program_shot(clock, sched); + } +} + /** * Arm a timer. * @@ -105,7 +118,6 @@ int xntimer_start(struct xntimer *timer, xntimerq_t *q = xntimer_percpu_queue(timer); xnticks_t date, now, delay, period; unsigned long gravity; - struct xnsched *sched; int ret = 0; trace_cobalt_timer_start(timer, value, interval, mode); @@ -168,15 +180,8 @@ int xntimer_start(struct xntimer *timer, timer->status |= XNTIMER_PERIODIC; } - xntimer_enqueue(timer, q); timer->status |= XNTIMER_RUNNING; - if (xntimer_heading_p(timer)) { - sched = xntimer_sched(timer); - if (sched != xnsched_current()) - xnclock_remote_shot(clock, sched); - else - xnclock_program_shot(clock, sched); - } + xntimer_enqueue_and_program(timer, q); return ret; } @@ -591,10 +596,20 @@ unsigned long long xntimer_get_overruns(struct xntimer *timer, xnticks_t now) delta = now - xntimer_pexpect(timer); if (unlikely(delta >= (xnsticks_t) period)) { + xntimerq_t *q; + period = timer->interval_ns; delta = xnclock_ticks_to_ns(xntimer_clock(timer), delta); overruns = xnarch_div64(delta, period); timer->pexpect_ticks += overruns; + + q = xntimer_percpu_queue(timer); + xntimer_dequeue(timer, q); + while (xntimerh_date(&timer->aplink) < now) { + timer->periodic_ticks++; + xntimer_update_date(timer); + } + xntimer_enqueue_and_program(timer, q); } timer->pexpect_ticks++; _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org http://xenomai.org/mailman/listinfo/xenomai-git