Arve Hjønnevåg reported numerous crashes from the "BUG_ON(timer->state != HRTIMER_STATE_CALLBACK)" check in __run_hrtimer after it called alarmtimer_fired. It ends up the alarmtimer code was not properly handling possible failures of hrtimer_try_to_cancel, and because these faulres occur when the underlying base hrtimer is being run, this limits the ability to properly handle modifications to any alarmtimers on that base. Because much of the logic duplicates the hrtimer logic, it seems that we might as well have a per-alarmtimer hrtimer, and avoid the extra complextity of trying to multiplex many alarmtimers off of one hrtimer. Thus this patch moves the hrtimer to the alarm structure and simplifies the management logic. Changelog: v2: * Includes a fix for double alarm_start calls found by Arve Cc: Arve Hjønnevåg <arve@android.com> Cc: Colin Cross <ccross@android.com> Cc: Thomas Gleixner <tglx@linutronix.de> Reported-by: Arve Hjønnevåg <arve@android.com> Tested-by: Arve Hjønnevåg <arve@android.com> Signed-off-by: John Stultz <john.stultz@linaro.org>
84 lines
2.1 KiB
C
84 lines
2.1 KiB
C
#ifndef _LINUX_ALARMTIMER_H
|
|
#define _LINUX_ALARMTIMER_H
|
|
|
|
#include <linux/time.h>
|
|
#include <linux/hrtimer.h>
|
|
#include <linux/timerqueue.h>
|
|
#include <linux/rtc.h>
|
|
|
|
enum alarmtimer_type {
|
|
ALARM_REALTIME,
|
|
ALARM_BOOTTIME,
|
|
|
|
ALARM_NUMTYPE,
|
|
};
|
|
|
|
enum alarmtimer_restart {
|
|
ALARMTIMER_NORESTART,
|
|
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
|
|
* also includes the expiration time.
|
|
* @period: Period for recuring alarms
|
|
* @function: Function pointer to be executed when the timer fires.
|
|
* @type: Alarm type (BOOTTIME/REALTIME)
|
|
* @enabled: Flag that represents if the alarm is set to fire or not
|
|
* @data: Internal data value.
|
|
*/
|
|
struct alarm {
|
|
struct timerqueue_node node;
|
|
struct hrtimer timer;
|
|
enum alarmtimer_restart (*function)(struct alarm *, ktime_t now);
|
|
enum alarmtimer_type type;
|
|
int state;
|
|
void *data;
|
|
};
|
|
|
|
void alarm_init(struct alarm *alarm, enum alarmtimer_type type,
|
|
enum alarmtimer_restart (*function)(struct alarm *, ktime_t));
|
|
int alarm_start(struct alarm *alarm, ktime_t start);
|
|
int alarm_try_to_cancel(struct alarm *alarm);
|
|
int 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;
|
|
}
|
|
|
|
|
|
/* Provide way to access the rtc device being used by alarmtimers */
|
|
struct rtc_device *alarmtimer_get_rtcdev(void);
|
|
|
|
#endif
|