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 { |
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设备表示的时间格式:
1 struct rtc_time { 2 int tm_sec; 3 int tm_min; 4 int tm_hour; 5 int tm_mday; 6 int tm_mon; 7 int tm_year; 8 int tm_wday; 9 int tm_yday; 10 int tm_isdst; 11 };
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 = 0; 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 = 0; 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", -1, NULL, 0);-注册alarmtimer设备。 if (IS_ERR(pdev)) { error = PTR_ERR(pdev); goto out_drv; } ws = wakeup_source_register("alarmtimer");------------------------返回注册的Wakeup Source,alarmtimer_suspend使用。 return 0; 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 0; }
在填充好结构体之后,设置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) < 0) 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 0; }
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) < 0) return TIMER_RETRY; return 0; }
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) > 0) { cur_setting->it_value = ktime_to_timespec(relative_expiry_time); } else { cur_setting->it_value.tv_sec = 0; cur_setting->it_value.tv_nsec = 0; } 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 = 0; 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", -1, NULL, 0); ... } /* 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 0; /* Find the soonest timer to expire*/ for (i = 0; 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 == 0) return 0; if (ktime_to_ns(min) < 2 * NSEC_PER_SEC) {-----------------------如果expires小于2秒,保持系统唤醒2秒,并中断suspend流程。 __pm_wakeup_event(ws, 2 * 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(0, 0));---设置rtctimer if (ret < 0) __pm_wakeup_event(ws, 1 * 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 -1; if (!device_may_wakeup(rtc->dev.parent)) return -1; 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 0; } 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, 0, 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 != 0) 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 == 0) 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 == 0) { 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 == 23 && old.tm_min == 59) || (new.tm_hour == 23 && new.tm_min == 59))) 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, 0, 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硬件时钟都被关闭之后,能唤醒系统,执行超时动作。