alarmtimers: Add more refined alarm state tracking
authorJohn Stultz <john.stultz@linaro.org>
Wed, 10 Aug 2011 19:30:21 +0000 (12:30 -0700)
committerJohn Stultz <john.stultz@linaro.org>
Wed, 10 Aug 2011 21:55:27 +0000 (14:55 -0700)
In order to allow for functionality like try_to_cancel, add
more refined  state tracking (similar to hrtimers).

CC: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: John Stultz <john.stultz@linaro.org>
include/linux/alarmtimer.h
kernel/time/alarmtimer.c

index c854a8e..304124a 100644 (file)
@@ -18,6 +18,11 @@ enum alarmtimer_restart {
        ALARMTIMER_RESTART,
 };
 
+
+#define ALARMTIMER_STATE_INACTIVE      0x00
+#define ALARMTIMER_STATE_ENQUEUED      0x01
+#define ALARMTIMER_STATE_CALLBACK      0x02
+
 /**
  * struct alarm - Alarm timer structure
  * @node:      timerqueue node for adding to the event list this value
@@ -32,7 +37,7 @@ struct alarm {
        struct timerqueue_node  node;
        enum alarmtimer_restart (*function)(struct alarm *, ktime_t now);
        enum alarmtimer_type    type;
-       bool                    enabled;
+       int                     state;
        void                    *data;
 };
 
@@ -43,4 +48,31 @@ void alarm_cancel(struct alarm *alarm);
 
 u64 alarm_forward(struct alarm *alarm, ktime_t now, ktime_t interval);
 
+/*
+ * A alarmtimer is active, when it is enqueued into timerqueue or the
+ * callback function is running.
+ */
+static inline int alarmtimer_active(const struct alarm *timer)
+{
+       return timer->state != ALARMTIMER_STATE_INACTIVE;
+}
+
+/*
+ * Helper function to check, whether the timer is on one of the queues
+ */
+static inline int alarmtimer_is_queued(struct alarm *timer)
+{
+       return timer->state & ALARMTIMER_STATE_ENQUEUED;
+}
+
+/*
+ * Helper function to check, whether the timer is running the callback
+ * function
+ */
+static inline int alarmtimer_callback_running(struct alarm *timer)
+{
+       return timer->state & ALARMTIMER_STATE_CALLBACK;
+}
+
+
 #endif
index 9093559..5b14cc2 100644 (file)
@@ -126,6 +126,8 @@ static struct rtc_device *alarmtimer_get_rtcdev(void)
 static void alarmtimer_enqueue(struct alarm_base *base, struct alarm *alarm)
 {
        timerqueue_add(&base->timerqueue, &alarm->node);
+       alarm->state |= ALARMTIMER_STATE_ENQUEUED;
+
        if (&alarm->node == timerqueue_getnext(&base->timerqueue)) {
                hrtimer_try_to_cancel(&base->timer);
                hrtimer_start(&base->timer, alarm->node.expires,
@@ -147,7 +149,12 @@ static void alarmtimer_remove(struct alarm_base *base, struct alarm *alarm)
 {
        struct timerqueue_node *next = timerqueue_getnext(&base->timerqueue);
 
+       if (!(alarm->state & ALARMTIMER_STATE_ENQUEUED))
+               return;
+
        timerqueue_del(&base->timerqueue, &alarm->node);
+       alarm->state &= ~ALARMTIMER_STATE_ENQUEUED;
+
        if (next == &alarm->node) {
                hrtimer_try_to_cancel(&base->timer);
                next = timerqueue_getnext(&base->timerqueue);
@@ -188,16 +195,18 @@ static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer)
                alarm = container_of(next, struct alarm, node);
 
                timerqueue_del(&base->timerqueue, &alarm->node);
-               alarm->enabled = 0;
+               alarm->state &= ~ALARMTIMER_STATE_ENQUEUED;
 
+               alarm->state |= ALARMTIMER_STATE_CALLBACK;
                spin_unlock_irqrestore(&base->lock, flags);
                if (alarm->function)
                        restart = alarm->function(alarm, now);
                spin_lock_irqsave(&base->lock, flags);
+               alarm->state &= ~ALARMTIMER_STATE_CALLBACK;
 
                if (restart != ALARMTIMER_NORESTART) {
                        timerqueue_add(&base->timerqueue, &alarm->node);
-                       alarm->enabled = 1;
+                       alarm->state |= ALARMTIMER_STATE_ENQUEUED;
                }
        }
 
@@ -305,7 +314,7 @@ void alarm_init(struct alarm *alarm, enum alarmtimer_type type,
        timerqueue_init(&alarm->node);
        alarm->function = function;
        alarm->type = type;
-       alarm->enabled = 0;
+       alarm->state = ALARMTIMER_STATE_INACTIVE;
 }
 
 /**
@@ -319,11 +328,10 @@ void alarm_start(struct alarm *alarm, ktime_t start)
        unsigned long flags;
 
        spin_lock_irqsave(&base->lock, flags);
-       if (alarm->enabled)
+       if (alarmtimer_active(alarm))
                alarmtimer_remove(base, alarm);
        alarm->node.expires = start;
        alarmtimer_enqueue(base, alarm);
-       alarm->enabled = 1;
        spin_unlock_irqrestore(&base->lock, flags);
 }
 
@@ -337,9 +345,8 @@ void alarm_cancel(struct alarm *alarm)
        unsigned long flags;
 
        spin_lock_irqsave(&base->lock, flags);
-       if (alarm->enabled)
+       if (alarmtimer_is_queued(alarm))
                alarmtimer_remove(base, alarm);
-       alarm->enabled = 0;
        spin_unlock_irqrestore(&base->lock, flags);
 }