Module: xenomai-gch
Branch: next
Commit: 1147eb31262e4fbc106fcdf7c7e9ef6f1d51cc33
URL:
http://git.xenomai.org/?p=xenomai-gch.git;a=commit;h=1147eb31262e4fbc106fcdf7c7e9ef6f1d51cc33
Author: Gilles Chanteperdrix
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