Linux时间子系统之二:Alarm Timer

时间:2023-03-09 01:49:49
Linux时间子系统之二:Alarm Timer

一、前言

严格来讲Alarm Timer也算POSIX Timer一部分,包含两种类型CLOCK_REALTIME_ALARM和CLOCK_BOOTTIME_ALARM。分别是在CLOCK_REALTIME和CLOCK_BOOTTIME后面加上_ALARM。Alarm Timer之外的POSIX Timer在内核进入cpuidle或者suspend之后,都会因为省电关闭ClockEvent设备而停止计时。而Alarm Timer恰恰借助RTC设备的长供电且具备唤醒功能,在系统进入suspend过程中,将最近一次超时expires写入RTC设备,超时后会将系统从suspend状态唤醒,执行timer超市函数。

这样在程序执行过程中,就不需要一直持有wakelock。

二、背景介绍

Alarm Timer可以说工作在两种状态下,一种是和其他Timer一样的基于hrtimer;另一种是在系统进入suspend后基于RTC设备。

RTC设备在系统外独立供电,RTC具备Alarm功能。在Alarm触发后,通过中断唤醒suspend的系统。

在device_initcall-->alarmtimer_init时,注册一个alarmtimer的platform_device,驱动为alarmtimer_driver。将alarmtimer_suspend作为钩子函数插入系统suspend流程,这样就将suspend和Alarm Timer功能挂钩了。

三、重要数据结构

struct alarm_base作为AlarmTimer时钟类型结构体,包含ALARM_REALTIME和ALARM_BOOTTIME两种。

static struct alarm_base {
  spinlock_t lock;---------------------------------互斥访问锁
  struct timerqueue_head timerqueue;-------AlarmTimer自己维护了expires红黑树。
  struct hrtimer timer;--------------------------将其加入到hrtimer_bases对应的红黑树中。
  ktime_t (*gettime)(void);--------------------获取对应类型时钟的时间函数
  clockid_t base_clockid;------------------------时钟类型ID,CLOCK_REALTIME和CLOCK_BOOTTIME
} alarm_bases[ALARM_NUMTYPE];

CLOCK_REALTIME_ALARM和CLOCK_REALTIME、CLOCK_BOOTTIME_ALARM和CLOCK_BOOTTIME都是用同样的base_clockid,但是_ALARM维护的alarm_bases[ALARM_NUMTYPE].timerqueue将他们与其他hrtimer区分开了。

struct k_clock alarm_clock作为两种类型共用的时钟/Timer函数:

    struct k_clock alarm_clock = {
.clock_getres = alarm_clock_getres,
.clock_get = alarm_clock_get,
.timer_create = alarm_timer_create,
.timer_set = alarm_timer_set,
.timer_del = alarm_timer_del,
.timer_get = alarm_timer_get,
.nsleep = alarm_timer_nsleep,
};

static struct rtc_timer rtctimer;--------------------RTC Timer

static struct rtc_device *rtcdev;-------------------RTC设备对应的结构体

struct rtc_time是RTC设备表示的时间格式:

 struct rtc_time {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};

struct ktime_t是内核时间格式。

这两种时间格式的转换,rtc_time到ktime_t通过rtc_tm_to_ktime;ktime_t到rtc_time通过rtc_ktime_to_tm。

四、AlarmTimer正常工作状态下运行

static int __init alarmtimer_init(void)
{
struct platform_device *pdev;
int error = ;
int i;
struct k_clock alarm_clock = {--------------------------------------AlarmTimer的Clock/Timer/Sleep函数。
.clock_getres = alarm_clock_getres,
.clock_get = alarm_clock_get,
.timer_create = alarm_timer_create,
.timer_set = alarm_timer_set,
.timer_del = alarm_timer_del,
.timer_get = alarm_timer_get,
.nsleep = alarm_timer_nsleep,
}; alarmtimer_rtc_timer_init();---------------------------------------初始化一个struct rtc_timer,将其加入struct rtc_device的timerqueue红黑树里面。 posix_timers_register_clock(CLOCK_REALTIME_ALARM, &alarm_clock);---填充posix_clocks[MAX_CLOCKS]的_ALARM部分
posix_timers_register_clock(CLOCK_BOOTTIME_ALARM, &alarm_clock); /* Initialize alarm bases */
alarm_bases[ALARM_REALTIME].base_clockid = CLOCK_REALTIME;---------初始化alarm_bases[ALARM_NUMTYPE]
alarm_bases[ALARM_REALTIME].gettime = &ktime_get_real;
alarm_bases[ALARM_BOOTTIME].base_clockid = CLOCK_BOOTTIME;
alarm_bases[ALARM_BOOTTIME].gettime = &ktime_get_boottime;
for (i = ; i < ALARM_NUMTYPE; i++) {
timerqueue_init_head(&alarm_bases[i].timerqueue);
spin_lock_init(&alarm_bases[i].lock);
hrtimer_init(&alarm_bases[i].timer,
alarm_bases[i].base_clockid,
HRTIMER_MODE_ABS);
alarm_bases[i].timer.function = alarmtimer_fired;
} error = alarmtimer_rtc_interface_setup();-------------------------获取系统的struct rtc_device设备,给rtcdev。
if (error)
return error; error = platform_driver_register(&alarmtimer_driver);-------------注册alarmtimer_driver,主要就是suspend钩子函数。
if (error)
goto out_if; pdev = platform_device_register_simple("alarmtimer", -, NULL, );-注册alarmtimer设备。
if (IS_ERR(pdev)) {
error = PTR_ERR(pdev);
goto out_drv;
}
ws = wakeup_source_register("alarmtimer");------------------------返回注册的Wakeup Source,alarmtimer_suspend使用。
return ; out_drv:
platform_driver_unregister(&alarmtimer_driver);
out_if:
alarmtimer_rtc_interface_remove();
return error;
}

AlarmTimer是struct k_itimer中的alarmtimer成员:

struct k_itimer {
...
union {
...
struct {
struct alarm alarmtimer;
ktime_t interval;
} alarm;
struct rcu_head rcu;
} it;
};

struct alarm如下:

struct alarm {
struct timerqueue_node node;----------------------------------------红黑树节点
enum alarmtimer_restart (*function)(struct alarm *, ktime_t now);---Alarm超时函数
enum alarmtimer_type type;------------------------------------------ALARM_REALTIME、ALARM_BOOTTIME
int state;--------------------------------------------------#define ALARMTIMER_STATE_INACTIVE 0x00、#define ALARMTIMER_STATE_ENQUEUED 0x01、#define ALARMTIMER_STATE_CALLBACK 0x02
void *data;
};

在了解了AlarmTimer初始化和基本数据结构之后,和其他POSIX Timer一样,重点在struct k_clock提供的函数。

1. AlarmTimer定时器

alarm_timer_create主要填充当前timer的struct alarm结构体:

static int alarm_timer_create(struct k_itimer *new_timer)
{
enum alarmtimer_type type;
struct alarm_base *base; if (!alarmtimer_get_rtcdev())--------------------------是否有可用RTC设备
return -ENOTSUPP;
if (!capable(CAP_WAKE_ALARM))--------------------------当前进程是否具有CAP_WAKE_ALARM能力,需要root权限。
return -EPERM; type = clock2alarm(new_timer->it_clock);---------------从Timer类型到alarm_base进行转换。
base = &alarm_bases[type];
alarm_init(&new_timer->it.alarm.alarmtimer, type, alarm_handle_timer);-----初始化当前timer的struct alarm结构
return ;
}

在填充好结构体之后,设置expires,并且启动一个hrtimer。

static int alarm_timer_set(struct k_itimer *timr, int flags,
struct itimerspec *new_setting,
struct itimerspec *old_setting)
{
ktime_t exp; if (!rtcdev)
return -ENOTSUPP;
if (flags & ~TIMER_ABSTIME)
return -EINVAL; if (old_setting)
alarm_timer_get(timr, old_setting); /* If the timer was already set, cancel it */
if (alarm_try_to_cancel(&timr->it.alarm.alarmtimer) < )
return TIMER_RETRY; /* start the timer */
timr->it.alarm.interval = timespec_to_ktime(new_setting->it_interval);---------间隔定时
exp = timespec_to_ktime(new_setting->it_value);--------------------------------首次超时值
/* Convert (if necessary) to absolute time */
if (flags != TIMER_ABSTIME) {--------------------------------------------------如果不是绝对时间,需要转换成绝对时间
ktime_t now; now = alarm_bases[timr->it.alarm.alarmtimer.type].gettime();
exp = ktime_add(now, exp);
} alarm_start(&timr->it.alarm.alarmtimer, exp);--------------------------------启动AlarmTimer,插入当前alarm_base的timerqueue,如有需要设置一个hrtimer。
return ;
}

alarm_timer_del是alarm_timer_set的逆操作,用于删除一个AlarmTimer。将其从alarm_base的timerqueue移除,如果已经被插入hrtimer,则取消。

static int alarm_timer_del(struct k_itimer *timr)
{
if (!rtcdev)
return -ENOTSUPP; if (alarm_try_to_cancel(&timr->it.alarm.alarmtimer) < )
return TIMER_RETRY; return ;
}

alarm_timer_get获取timr的超时itimerspec。

/**
* alarm_timer_get - posix timer_get interface
* @new_timer: k_itimer pointer
* @cur_setting: itimerspec data to fill
*
* Copies out the current itimerspec data
*/
static void alarm_timer_get(struct k_itimer *timr,
struct itimerspec *cur_setting)
{
ktime_t relative_expiry_time =
alarm_expires_remaining(&(timr->it.alarm.alarmtimer)); if (ktime_to_ns(relative_expiry_time) > ) {
cur_setting->it_value = ktime_to_timespec(relative_expiry_time);
} else {
cur_setting->it_value.tv_sec = ;
cur_setting->it_value.tv_nsec = ;
} cur_setting->it_interval = ktime_to_timespec(timr->it.alarm.interval);
}

新增的struct alarm的note作为一个节点插入到alarm_base的timerqueue中。

struct timerqueue_node {
struct rb_node node;
ktime_t expires;---------------红黑树按照expires大小排列
};

节点的插入、删除的典型路径是,

alarm_timer_set-->alarm_start-->alarmtimer_enqueue-->timerqueue_add

alarm_timer_del-->alarm_try_to_cancel-->alarmtimer_remove-->timerqueue_del

操作alarm_base的timerqueue有如下几个地方,这样保证无论是删除、插入、超时都是最新的alarm_base->timerqueue插入到hrtimer中。

alarmtimer_init---------初始化红黑树头
alarmtimer_enqueue------将timer加入timerqueue。如果当前timer是最新timer,则创建hrtimer
alarmtimer_remove-------将timer移除timerqueue。如果当前timer是最新timer,删除hrtimer。取最近timer重新设置hrtimer。
alarmtimer_fired--------将超时timer移除出timerqueue,如果是restart类型,则重新插入。如果timerqueue不为空,则设置下一次expires,返回HRTIMER_RESTART。
static int __init alarmtimer_init(void)
{
...
for (i = ; i < ALARM_NUMTYPE; i++) {
timerqueue_init_head(&alarm_bases[i].timerqueue);
spin_lock_init(&alarm_bases[i].lock);
hrtimer_init(&alarm_bases[i].timer,------------------------------在alarmtimer_init中初始化hrtimer,ALARM_REALTIME和ALARM_BOOTTIME共两个hrtimer。这两个timer的主要区别在于不同的base_clockid。
alarm_bases[i].base_clockid,
HRTIMER_MODE_ABS);
alarm_bases[i].timer.function = alarmtimer_fired;
}
...
} static void alarmtimer_enqueue(struct alarm_base *base, struct alarm *alarm)
{
... if (&alarm->node == timerqueue_getnext(&base->timerqueue)) {
hrtimer_try_to_cancel(&base->timer);-----------------------------努力取消alarm_base->timer,0:timer不在hrtimer_clock_base->active里面,1:将timer从hrtimer_clock_base->active里面移除,-1:timer的callback函数正在被执行,不能被停止。
hrtimer_start(&base->timer, alarm->node.expires,-----------------将最近expires赋给alarm_base->timer,注意这里不同base的区别。alarm_base的timerqueue红黑树和hrtimer_clock_base的active红黑树区别。
HRTIMER_MODE_ABS);
}
} static void alarmtimer_remove(struct alarm_base *base, struct alarm *alarm)
{
... if (next == &alarm->node) {
hrtimer_try_to_cancel(&base->timer);----------------------------取消alarm_base->timer
next = timerqueue_getnext(&base->timerqueue);-------------------取最近expires
if (!next)
return;
hrtimer_start(&base->timer, next->expires, HRTIMER_MODE_ABS);---更新alarm_base->timer的expires
}
} static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer)
{
... if (next) {
hrtimer_set_expires(&base->timer, next->expires);----------在处理完expired timer之后,设置最近一次expires的alarm_base->timer。
ret = HRTIMER_RESTART;
}
...
} static int alarm_clock_getres(const clockid_t which_clock, struct timespec *tp)
{
... return hrtimer_get_res(baseid, tp);---------------------------获取base_clockid的精度
}

AlarmTimer中关于timerqueue的操作,一个timerqueue节点共用一个hrtimer。

timerqueue_init_head(&alarm_bases[i].timerqueue);-------初始化alarm_base->timerqueue,红黑树根节点
timerqueue_init(&alarm->node);--------------------------初始化一个timerqueue节点
next = timerqueue_getnext(&base->timerqueue);-----------获取alarm_base->timerqueue的最左侧节点
timerqueue_add(&base->timerqueue, &alarm->node);--------将节点插入alarm_base->timerqueue
timerqueue_del(&base->timerqueue, &alarm->node);--------从alarm_base->timerqueue中删除

五、AlarmTimer在进入Suspend时、Suspend中、Resume时状态分析

AlarmTimer被当做一个platform_device,主要是为了提供suspend钩子函数。在系统执行suspend流程的时候,针对AlarmTimer进行转移到RTC。

static int __init alarmtimer_init(void)
{
...
error = platform_driver_register(&alarmtimer_driver);
if (error)
goto out_if; pdev = platform_device_register_simple("alarmtimer", -, NULL, );
...
} /* Suspend hook structures */
static const struct dev_pm_ops alarmtimer_pm_ops = {
.suspend = alarmtimer_suspend,
}; static struct platform_driver alarmtimer_driver = {
.driver = {
.name = "alarmtimer",
.pm = &alarmtimer_pm_ops,
}
};

alarmtimer_suspend函数的核心功能是在进入睡眠之前,遍历alarm_bases->timerqueue,取最近一次timer的expires;将此expires写入RTC定时器,RTC超时后会唤醒系统。

static int alarmtimer_suspend(struct device *dev)
{
...
rtc = alarmtimer_get_rtcdev();-------------------------------------获取RTC设备
/* If we have no rtcdev, just return */
if (!rtc)
return ; /* Find the soonest timer to expire*/
for (i = ; i < ALARM_NUMTYPE; i++) {------------------------------遍历ALARM_REALTIME和ALARM_BOOTTIME两个alarm_base,取各自最近expires
struct alarm_base *base = &alarm_bases[i];
struct timerqueue_node *next;
ktime_t delta; spin_lock_irqsave(&base->lock, flags);
next = timerqueue_getnext(&base->timerqueue);
spin_unlock_irqrestore(&base->lock, flags);
if (!next)
continue;
delta = ktime_sub(next->expires, base->gettime());
if (!min.tv64 || (delta.tv64 < min.tv64))---------------------比较两次expires,取最小者
min = delta;
}
if (min.tv64 == )
return ; if (ktime_to_ns(min) < * NSEC_PER_SEC) {-----------------------如果expires小于2秒,保持系统唤醒2秒,并中断suspend流程。
__pm_wakeup_event(ws, * MSEC_PER_SEC);
return -EBUSY;
} /* Setup an rtc timer to fire that far in the future */
rtc_timer_cancel(rtc, &rtctimer);-------------------------------取消当前rtctimer
rtc_read_time(rtc, &tm);
now = rtc_tm_to_ktime(tm);
now = ktime_add(now, min);--------------------------------------获取RTC时间,将rtc_timer转换成ktimer_t,将RTC时间加上AlarmTimer超时。 /* Set alarm, if in the past reject suspend briefly to handle */
ret = rtc_timer_start(rtc, &rtctimer, now, ktime_set(, ));---设置rtctimer
if (ret < )
__pm_wakeup_event(ws, * MSEC_PER_SEC);
return ret;
}

在此之后系统继续suspend流程,然后RTC到期进行resume唤醒。

六、RTC相关

AlarmTimer区别与其他的POSIX Timer就在于其和RTC设备的关联。

AlarmTimer和RTC的关联有几处:

1. alarmtimer_init中初始化rtctimer,通过rtc_class接口获得rtcdev:alarmtimer_rtc_timer_init、alarmtimer_rtc_interface_setup

2. 使用alarmtimer_get_rtcdev获取当前rtc_device

3. RTC定时器相关操作:rtc_timer_init、rtc_timer_cancel、rtc_read_time、rtc_tm_to_ktime、rtc_timer_start、

alarmtimer_rtc_interface_setup通过rtc_class接口获取RTC设备:

static int alarmtimer_rtc_add_device(struct device *dev,--------------根据rtc_class全局变量,找到其下面的RTC设备。如果有多个,取最后一个。
struct class_interface *class_intf)
{
unsigned long flags;
struct rtc_device *rtc = to_rtc_device(dev);----------------------根据struct device找到对应的rtc设备。 if (rtcdev)
return -EBUSY; if (!rtc->ops->set_alarm)
return -;
if (!device_may_wakeup(rtc->dev.parent))
return -; spin_lock_irqsave(&rtcdev_lock, flags);
if (!rtcdev) {
rtcdev = rtc;------------------------------------------------局部全局变量rtcdev
/* hold a reference so it doesn't go away */
get_device(dev);
}
spin_unlock_irqrestore(&rtcdev_lock, flags);
return ;
} static struct class_interface alarmtimer_rtc_interface = {
.add_dev = &alarmtimer_rtc_add_device,---------------------class_interface_register中会调用此函数
}; static int alarmtimer_rtc_interface_setup(void)
{
alarmtimer_rtc_interface.class = rtc_class;
return class_interface_register(&alarmtimer_rtc_interface);
} static void alarmtimer_rtc_interface_remove(void)
{
class_interface_unregister(&alarmtimer_rtc_interface);
}

alarmtimer_rtc_timer_init初始化一个rtctimer:

static inline void alarmtimer_rtc_timer_init(void)
{
rtc_timer_init(&rtctimer, NULL, NULL);
}

RTC设备对外接口主要在drivers/rtc/interface.c中,其中RTC Timer相关包括:rtc_timer_init、rtc_timer_start、rtc_timer_cancel

/* rtc_timer_init - Initializes an rtc_timer
* @timer: timer to be intiialized
* @f: function pointer to be called when timer fires
* @data: private data passed to function pointer
*
* Kernel interface to initializing an rtc_timer.
*/
void rtc_timer_init(struct rtc_timer *timer, void (*f)(void* p), void* data)----------初始化timer的node、task.func、task.private_date,node将会被插入到RTC设备的timerqueue中。
{
timerqueue_init(&timer->node);
timer->enabled = 0;
timer->task.func = f;
timer->task.private_data = data;
} /* rtc_timer_start - Sets an rtc_timer to fire in the future
* @ rtc: rtc device to be used
* @ timer: timer being set
* @ expires: time at which to expire the timer
* @ period: period that the timer will recur
*
* Kernel interface to set an rtc_timer
*/
int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer,-----------------将timer插入rtc->timerqueue,如有需要选择最近的timer设置Alarm。
ktime_t expires, ktime_t period)
{
int ret = 0;
mutex_lock(&rtc->ops_lock);
if (timer->enabled)-------------------------------------------------------------是否已经被使能?已经被使能则移除
rtc_timer_remove(rtc, timer); timer->node.expires = expires;
timer->period = period;---------------------------------------------------------expires是超时点,period是容许的宽限 ret = rtc_timer_enqueue(rtc, timer);--------------------------------------------将timer->node插入rtc->timerqueue mutex_unlock(&rtc->ops_lock);
return ret;
} /* rtc_timer_cancel - Stops an rtc_timer
* @ rtc: rtc device to be used
* @ timer: timer being set
*
* Kernel interface to cancel an rtc_timer
*/
int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer* timer)------------rtc_timer_start的反操作
{
int ret = 0;
mutex_lock(&rtc->ops_lock);
if (timer->enabled)
rtc_timer_remove(rtc, timer);
mutex_unlock(&rtc->ops_lock);
return ret;
}

rtc_timer_start和rtc_timer_cancel通过rtc_timer_enqueue和rtc_timer_remove来主动插入/删除timer节点,操作节点的还有一个地方是超时函数rtc_timer_do_work。这三个函数能保证RTC设备的timer及时更新。

rtc->timerqueue也是红黑树,基本操作也是timerqueue_add、timerqueue_del、timerqueue_getnext。

针对RTC设备的操作都是通过rtc_device->ops来执行。

读取RTC时间:

static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
{
int err;
if (!rtc->ops)
err = -ENODEV;
else if (!rtc->ops->read_time)
err = -EINVAL;
else {
memset(tm, , sizeof(struct rtc_time));
err = rtc->ops->read_time(rtc->dev.parent, tm);
}
return err;
} int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
{
int err; err = mutex_lock_interruptible(&rtc->ops_lock);
if (err)
return err; err = __rtc_read_time(rtc, tm);
mutex_unlock(&rtc->ops_lock);
return err;
}

设置RTC时间:

int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
{
int err; err = rtc_valid_tm(tm);
if (err != )
return err; err = mutex_lock_interruptible(&rtc->ops_lock);
if (err)
return err; if (!rtc->ops)
err = -ENODEV;
else if (rtc->ops->set_time)
err = rtc->ops->set_time(rtc->dev.parent, tm);
else if (rtc->ops->set_mmss) {
unsigned long secs;
err = rtc_tm_to_time(tm, &secs);
if (err == )
err = rtc->ops->set_mmss(rtc->dev.parent, secs);
} else
err = -EINVAL; mutex_unlock(&rtc->ops_lock);
/* A timer might have just expired */
schedule_work(&rtc->irqwork);
return err;
}
EXPORT_SYMBOL_GPL(rtc_set_time); int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs)
{
int err; err = mutex_lock_interruptible(&rtc->ops_lock);
if (err)
return err; if (!rtc->ops)
err = -ENODEV;
else if (rtc->ops->set_mmss)
err = rtc->ops->set_mmss(rtc->dev.parent, secs);
else if (rtc->ops->read_time && rtc->ops->set_time) {
struct rtc_time new, old; err = rtc->ops->read_time(rtc->dev.parent, &old);
if (err == ) {
rtc_time_to_tm(secs, &new); /*
* avoid writing when we're going to change the day of
* the month. We will retry in the next minute. This
* basically means that if the RTC must not drift
* by more than 1 minute in 11 minutes.
*/
if (!((old.tm_hour == && old.tm_min == ) ||
(new.tm_hour == && new.tm_min == )))
err = rtc->ops->set_time(rtc->dev.parent,
&new);
}
}
else
err = -EINVAL; mutex_unlock(&rtc->ops_lock);
/* A timer might have just expired */
schedule_work(&rtc->irqwork); return err;
}
EXPORT_SYMBOL_GPL(rtc_set_mmss);

读取Alarm时间:

static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
{
int err; err = mutex_lock_interruptible(&rtc->ops_lock);
if (err)
return err; if (rtc->ops == NULL)
err = -ENODEV;
else if (!rtc->ops->read_alarm)
err = -EINVAL;
else {
memset(alarm, , sizeof(struct rtc_wkalrm));
err = rtc->ops->read_alarm(rtc->dev.parent, alarm);
} mutex_unlock(&rtc->ops_lock);
return err;
}

设置Alarm时间:

static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
{
struct rtc_time tm;
long now, scheduled;
int err; err = rtc_valid_tm(&alarm->time);
if (err)
return err;
rtc_tm_to_time(&alarm->time, &scheduled); /* Make sure we're not setting alarms in the past */
err = __rtc_read_time(rtc, &tm);
rtc_tm_to_time(&tm, &now);
if (scheduled <= now)
return -ETIME;
/*
* XXX - We just checked to make sure the alarm time is not
* in the past, but there is still a race window where if
* the is alarm set for the next second and the second ticks
* over right here, before we set the alarm.
*/ if (!rtc->ops)
err = -ENODEV;
else if (!rtc->ops->set_alarm)
err = -EINVAL;
else
err = rtc->ops->set_alarm(rtc->dev.parent, alarm); return err;
}

打开关闭irq:

int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled)
{
int err = mutex_lock_interruptible(&rtc->ops_lock);
if (err)
return err; if (rtc->aie_timer.enabled != enabled) {
if (enabled)
err = rtc_timer_enqueue(rtc, &rtc->aie_timer);
else
rtc_timer_remove(rtc, &rtc->aie_timer);
} if (err)
/* nothing */;
else if (!rtc->ops)
err = -ENODEV;
else if (!rtc->ops->alarm_irq_enable)
err = -EINVAL;
else
err = rtc->ops->alarm_irq_enable(rtc->dev.parent, enabled); mutex_unlock(&rtc->ops_lock);
return err;
}
EXPORT_SYMBOL_GPL(rtc_alarm_irq_enable); static void rtc_alarm_disable(struct rtc_device *rtc)
{
if (!rtc->ops || !rtc->ops->alarm_irq_enable)
return; rtc->ops->alarm_irq_enable(rtc->dev.parent, false);
}

七、总结

AlarmTimer涉及到alarm_bases维护的一套数据、hrtimer、suspend流程、rtc设备、rtc timer。他的核心思想就是在系统进入睡眠,hrtimer硬件时钟都被关闭之后,能唤醒系统,执行超时动作。