Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a28cde81 authored by John Stultz's avatar John Stultz
Browse files

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
Loading
Loading
Loading
Loading
+33 −1
Original line number Diff line number Diff line
@@ -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
+14 −7
Original line number Diff line number Diff line
@@ -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);
}