Module: xenomai-forge
Branch: next
Commit: 4c95f1187f447a132be872195e389bcc039fe668
URL:    
http://git.xenomai.org/?p=xenomai-forge.git;a=commit;h=4c95f1187f447a132be872195e389bcc039fe668

Author: Philippe Gerum <r...@xenomai.org>
Date:   Thu Jul 17 15:54:43 2014 +0200

cobalt/timer: allow periodic timers to be stopped from a handler

This fixes a nasty, ancient bug causing xntimer_stop() to lead to a
nop when called from a timer handler, for a periodic timer. The timer
would keep ticking unexpectedly.

---

 include/cobalt/kernel/timer.h |   18 ++++++------------
 kernel/cobalt/clock.c         |   11 ++++++-----
 kernel/cobalt/timer.c         |   18 ++++++++++--------
 3 files changed, 22 insertions(+), 25 deletions(-)

diff --git a/include/cobalt/kernel/timer.h b/include/cobalt/kernel/timer.h
index 3eaca4c..83fd16a 100644
--- a/include/cobalt/kernel/timer.h
+++ b/include/cobalt/kernel/timer.h
@@ -45,9 +45,10 @@ typedef enum xntmode {
 #define XNTIMER_PERIODIC  0x00000004
 #define XNTIMER_REALTIME  0x00000008
 #define XNTIMER_FIRED     0x00000010
-#define XNTIMER_NOBLCK   0x00000020
-#define XNTIMER_KGRAVITY  0x00000040
-#define XNTIMER_UGRAVITY  0x00000080
+#define XNTIMER_NOBLCK    0x00000020
+#define XNTIMER_RUNNING   0x00000040
+#define XNTIMER_KGRAVITY  0x00000080
+#define XNTIMER_UGRAVITY  0x00000100
 #define XNTIMER_IGRAVITY  0    /* most conservative */
 
 #define XNTIMER_GRAVITY_MASK   (XNTIMER_KGRAVITY|XNTIMER_UGRAVITY)
@@ -295,7 +296,7 @@ static inline int xntimer_active_p(struct xntimer *timer)
 
 static inline int xntimer_running_p(struct xntimer *timer)
 {
-       return (timer->status & XNTIMER_DEQUEUED) == 0;
+       return (timer->status & XNTIMER_RUNNING) != 0;
 }
 
 static inline int xntimer_fired_p(struct xntimer *timer)
@@ -308,13 +309,6 @@ static inline int xntimer_periodic_p(struct xntimer *timer)
        return (timer->status & XNTIMER_PERIODIC) != 0;
 }
 
-static inline int xntimer_reload_p(struct xntimer *timer)
-{
-       return (timer->status &
-               (XNTIMER_PERIODIC|XNTIMER_DEQUEUED|XNTIMER_KILLED)) ==
-               (XNTIMER_PERIODIC|XNTIMER_DEQUEUED);
-}
-
 void __xntimer_init(struct xntimer *timer,
                    struct xnclock *clock,
                    void (*handler)(struct xntimer *timer),
@@ -415,7 +409,7 @@ int xntimer_heading_p(struct xntimer *timer);
 
 static inline void xntimer_stop(struct xntimer *timer)
 {
-       if ((timer->status & XNTIMER_DEQUEUED) == 0)
+       if (timer->status & XNTIMER_RUNNING)
                __xntimer_stop(timer);
 }
 
diff --git a/kernel/cobalt/clock.c b/kernel/cobalt/clock.c
index 1284d66..847ca9f 100644
--- a/kernel/cobalt/clock.c
+++ b/kernel/cobalt/clock.c
@@ -415,7 +415,7 @@ static int timerlist_show(struct xnvfile_snapshot_iterator 
*it, void *data)
                               "CPU", "SCHED/SHOT", "TIMEOUT",
                               "INTERVAL", "NAME");
        else {
-               if ((p->status & XNTIMER_DEQUEUED) == 0)
+               if (p->status & XNTIMER_RUNNING)
                        xntimer_format_time(p->timeout, timeout_buf,
                                            sizeof(timeout_buf));
                if (p->status & XNTIMER_PERIODIC)
@@ -762,11 +762,12 @@ void xnclock_tick(struct xnclock *clock)
                now = xnclock_read_raw(clock);
                timer->status |= XNTIMER_FIRED;
                /*
-                * If the elapsed timer has no reload value, or was
-                * re-queued or killed by the timeout handler: do not
-                * re-queue it for the next shot.
+                * Only requeue periodic timers which have not been
+                * requeued, stopped or killed.
                 */
-               if (!xntimer_reload_p(timer))
+               if ((timer->status &
+                    
(XNTIMER_PERIODIC|XNTIMER_DEQUEUED|XNTIMER_KILLED|XNTIMER_RUNNING)) !=
+                   (XNTIMER_PERIODIC|XNTIMER_DEQUEUED|XNTIMER_RUNNING))
                        continue;
        advance:
                interval_ticks = 1;
diff --git a/kernel/cobalt/timer.c b/kernel/cobalt/timer.c
index f312a88..ba4bf63 100644
--- a/kernel/cobalt/timer.c
+++ b/kernel/cobalt/timer.c
@@ -158,6 +158,7 @@ int xntimer_start(struct xntimer *timer,
        }
 
        xntimer_enqueue(timer, q);
+       timer->status |= XNTIMER_RUNNING;
        if (xntimer_heading_p(timer)) {
                sched = xntimer_sched(timer);
                if (sched != xnsched_current())
@@ -188,13 +189,15 @@ void __xntimer_stop(struct xntimer *timer)
        struct xnclock *clock = xntimer_clock(timer);
        xntimerq_t *q = xntimer_percpu_queue(timer);
        struct xnsched *sched;
-       int heading;
+       int heading = 1;
 
        trace_cobalt_timer_stop(timer);
 
-       heading = xntimer_heading_p(timer);
-       xntimer_dequeue(timer, q);
-       timer->status &= ~XNTIMER_FIRED;
+       if ((timer->status & XNTIMER_DEQUEUED) == 0) {
+               heading = xntimer_heading_p(timer);
+               xntimer_dequeue(timer, q);
+       }
+       timer->status &= ~(XNTIMER_FIRED|XNTIMER_RUNNING);
        sched = xntimer_sched(timer);
 
        /*
@@ -458,9 +461,7 @@ void __xntimer_migrate(struct xntimer *timer, struct 
xnsched *sched)
 
        trace_cobalt_timer_migrate(timer, xnsched_cpu(sched));
 
-       if (timer->status & XNTIMER_DEQUEUED)
-               timer->sched = sched;
-       else {
+       if (timer->status & XNTIMER_RUNNING) {
                xntimer_stop(timer);
                timer->sched = sched;
                clock = xntimer_clock(timer);
@@ -468,7 +469,8 @@ void __xntimer_migrate(struct xntimer *timer, struct 
xnsched *sched)
                xntimer_enqueue(timer, q);
                if (xntimer_heading_p(timer))
                        xnclock_remote_shot(clock, sched);
-       }
+       } else
+               timer->sched = sched;
 }
 EXPORT_SYMBOL_GPL(__xntimer_migrate);
 


_______________________________________________
Xenomai-git mailing list
Xenomai-git@xenomai.org
http://www.xenomai.org/mailman/listinfo/xenomai-git

Reply via email to