Commit a28cde81 authored by John Stultz's avatar John Stultz

alarmtimers: Add more refined alarm state tracking

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: default avatarJohn Stultz <john.stultz@linaro.org>
parent 9e264762
...@@ -18,6 +18,11 @@ enum alarmtimer_restart { ...@@ -18,6 +18,11 @@ enum alarmtimer_restart {
ALARMTIMER_RESTART, ALARMTIMER_RESTART,
}; };
#define ALARMTIMER_STATE_INACTIVE 0x00
#define ALARMTIMER_STATE_ENQUEUED 0x01
#define ALARMTIMER_STATE_CALLBACK 0x02
/** /**
* struct alarm - Alarm timer structure * struct alarm - Alarm timer structure
* @node: timerqueue node for adding to the event list this value * @node: timerqueue node for adding to the event list this value
...@@ -32,7 +37,7 @@ struct alarm { ...@@ -32,7 +37,7 @@ struct alarm {
struct timerqueue_node node; struct timerqueue_node node;
enum alarmtimer_restart (*function)(struct alarm *, ktime_t now); enum alarmtimer_restart (*function)(struct alarm *, ktime_t now);
enum alarmtimer_type type; enum alarmtimer_type type;
bool enabled; int state;
void *data; void *data;
}; };
...@@ -43,4 +48,31 @@ void alarm_cancel(struct alarm *alarm); ...@@ -43,4 +48,31 @@ void alarm_cancel(struct alarm *alarm);
u64 alarm_forward(struct alarm *alarm, ktime_t now, ktime_t interval); 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 #endif
...@@ -126,6 +126,8 @@ static struct rtc_device *alarmtimer_get_rtcdev(void) ...@@ -126,6 +126,8 @@ static struct rtc_device *alarmtimer_get_rtcdev(void)
static void alarmtimer_enqueue(struct alarm_base *base, struct alarm *alarm) static void alarmtimer_enqueue(struct alarm_base *base, struct alarm *alarm)
{ {
timerqueue_add(&base->timerqueue, &alarm->node); timerqueue_add(&base->timerqueue, &alarm->node);
alarm->state |= ALARMTIMER_STATE_ENQUEUED;
if (&alarm->node == timerqueue_getnext(&base->timerqueue)) { if (&alarm->node == timerqueue_getnext(&base->timerqueue)) {
hrtimer_try_to_cancel(&base->timer); hrtimer_try_to_cancel(&base->timer);
hrtimer_start(&base->timer, alarm->node.expires, hrtimer_start(&base->timer, alarm->node.expires,
...@@ -147,7 +149,12 @@ static void alarmtimer_remove(struct alarm_base *base, struct alarm *alarm) ...@@ -147,7 +149,12 @@ static void alarmtimer_remove(struct alarm_base *base, struct alarm *alarm)
{ {
struct timerqueue_node *next = timerqueue_getnext(&base->timerqueue); struct timerqueue_node *next = timerqueue_getnext(&base->timerqueue);
if (!(alarm->state & ALARMTIMER_STATE_ENQUEUED))
return;
timerqueue_del(&base->timerqueue, &alarm->node); timerqueue_del(&base->timerqueue, &alarm->node);
alarm->state &= ~ALARMTIMER_STATE_ENQUEUED;
if (next == &alarm->node) { if (next == &alarm->node) {
hrtimer_try_to_cancel(&base->timer); hrtimer_try_to_cancel(&base->timer);
next = timerqueue_getnext(&base->timerqueue); next = timerqueue_getnext(&base->timerqueue);
...@@ -188,16 +195,18 @@ static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer) ...@@ -188,16 +195,18 @@ static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer)
alarm = container_of(next, struct alarm, node); alarm = container_of(next, struct alarm, node);
timerqueue_del(&base->timerqueue, &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); spin_unlock_irqrestore(&base->lock, flags);
if (alarm->function) if (alarm->function)
restart = alarm->function(alarm, now); restart = alarm->function(alarm, now);
spin_lock_irqsave(&base->lock, flags); spin_lock_irqsave(&base->lock, flags);
alarm->state &= ~ALARMTIMER_STATE_CALLBACK;
if (restart != ALARMTIMER_NORESTART) { if (restart != ALARMTIMER_NORESTART) {
timerqueue_add(&base->timerqueue, &alarm->node); 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, ...@@ -305,7 +314,7 @@ void alarm_init(struct alarm *alarm, enum alarmtimer_type type,
timerqueue_init(&alarm->node); timerqueue_init(&alarm->node);
alarm->function = function; alarm->function = function;
alarm->type = type; alarm->type = type;
alarm->enabled = 0; alarm->state = ALARMTIMER_STATE_INACTIVE;
} }
/** /**
...@@ -319,11 +328,10 @@ void alarm_start(struct alarm *alarm, ktime_t start) ...@@ -319,11 +328,10 @@ void alarm_start(struct alarm *alarm, ktime_t start)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&base->lock, flags); spin_lock_irqsave(&base->lock, flags);
if (alarm->enabled) if (alarmtimer_active(alarm))
alarmtimer_remove(base, alarm); alarmtimer_remove(base, alarm);
alarm->node.expires = start; alarm->node.expires = start;
alarmtimer_enqueue(base, alarm); alarmtimer_enqueue(base, alarm);
alarm->enabled = 1;
spin_unlock_irqrestore(&base->lock, flags); spin_unlock_irqrestore(&base->lock, flags);
} }
...@@ -337,9 +345,8 @@ void alarm_cancel(struct alarm *alarm) ...@@ -337,9 +345,8 @@ void alarm_cancel(struct alarm *alarm)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&base->lock, flags); spin_lock_irqsave(&base->lock, flags);
if (alarm->enabled) if (alarmtimer_is_queued(alarm))
alarmtimer_remove(base, alarm); alarmtimer_remove(base, alarm);
alarm->enabled = 0;
spin_unlock_irqrestore(&base->lock, flags); spin_unlock_irqrestore(&base->lock, flags);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment