博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
linux应用程序使用时钟中断,Linux时钟中断(2.6.23)(三)
阅读量:6279 次
发布时间:2019-06-22

本文共 3423 字,大约阅读时间需要 11 分钟。

上一节主要讲了时钟中断的注册过程,在这一节我们主要时钟中断的处理程序。

由上一节我们知道注册的时钟中断处理程序是timer_interrupt。我们使用cscope在内核里可以搜索到如下调用关系:

timer_interrupt()

|-->do_timer_interrupt_hook();

|-->global_clock_event->event_handler(global_clock_event);

到此我们又遇到了新的问题:

1、global_clock_event是什么?

2、global_clock_event->event_handler指针最终指向的那个函数?

首先global_clock_event是一个struct

clock_event_device类型的全局指针变量,保存着系统中当前正在使用的时钟事件设备(保存了系统当前使用的硬件时钟中断发生时,要执行的中断处理函数的指针)。接下来我们使用cscope工具搜索内核就可以知道在被赋值为:

global_clock_event

= &pit_clockevent;或者global_clock_event

= &hpet_clockevent;现在的硬件大部分都支持HPET,所以在这里我们主要看hpet_clockevent。

static

struct clock_event_device hpet_clockevent = {

.name

= "hpet",

.features

= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,

.set_mode

= hpet_set_mode,

.set_next_event

= hpet_next_event,

.shift

= 32,

.irq

= 0,

};

可以看到在内核里时钟时间设备为hpet_clockevent。到此我们依然没有找到。前面提到的将global_clock_event赋值为hpet_clockevent是在hpet_enable()函数中。上一节我们提到时钟中断的注册中调用了late_time_init()函数(也即hpet_time_init函数),在这个函数中就会首先调用hpet_enable()函数,追踪之后函数的调用流程如下:

start_kernel()

|-->time_init()

|-->tsc_init();late_time_init=choose_time_init();/*choose_time_init()=hpet_time_init*/

|-->late_time_init()

|-->hpet_enable()/*如果硬件不支持hpet,则调用setup_pit_timer*/

|-->clockevents_register_device(&hpet_clockevent);

|-->clockevents_do_notify(CLOCK_EVT_NOTIFY_ADD,

&hpet_clockevent);

|-->raw_notifier_call_chain(&clockevents_chain,

CLOCK_EVT_NOTIFY_ADD,

&hpet_clockevent);

|--> __raw_notifier_call_chain(nh, val,&hpet_clockevent,

-1,

NULL);

|-->notifier_call_chain(&nh->head, CLOCK_EVT_NOTIFY_ADD,

&hpet_clockevent, nr_to_call, nr_calls);

|-->nb->notifier_call(nb, CLOCK_EVT_NOTIFY_ADD,

&hpet_clockevent);

到此我们又遇到了一个问题,那就是clockevents_chain。使用cscope工具可以找到如下信息:

static

struct notifier_block tick_notifier = {

.notifier_call

= tick_notify,

};

start_kernel()

/*early than time_init*/

|-->tick_init()

|-->clockevents_register_notifier(&tick_notifier);

|-->raw_notifier_chain_register(&clockevents_chain,

nb);/*nb=&tick_notifier*/

|-->notifier_chain_register(&nh->head,

n);/*nh=&clockevents_chain,n=nb*/

|-->rcu_assign_pointer(*nl, n);

#define

rcu_assign_pointer(p, v) ({ \

smp_wmb();

\

(p)

= (v); \

})

由此可见clockevents_chain->head->notifier_call最终被注册为tick_notify.结合前面提到的对hept_clockevent的操作的最后一个函数nb->notifier_call(nb,

CLOCK_EVT_NOTIFY_ADD, &hpet_clockevent);,我们就可以将该句写为:

tick_notify(clockevents_chain->head,

CLOCK_EVT_NOTIFY_ADD, &hpet_clockevent)。

下面我们来看看tick_notify函数:

tick_notify(clockevents_chain->head,CLOCK_EVT_NOTIFY_ADD,&hpet_clockevent)

|-->tick_check_new_device(&hpet_clockevent);

|-->tick_setup_device(td,

newdev, cpu, cpumask);/*newdev=&hpet_clockevent*/

{

if

(td->mode == TICKDEV_MODE_PERIODIC)

tick_setup_periodic(newdev,

0);

else

tick_setup_oneshot(newdev,

handler, next_event);

}

enum

tick_device_mode {

TICKDEV_MODE_PERIODIC,

TICKDEV_MODE_ONESHOT,

};

我们这里只看tick_setup_periodic(&hpet_clockevent,0)这种情况,也就是时钟中断的类型为

TICKDEV_MODE_PERIODIC这种情况。

tick_setup_periodic(&clockevents_chain,0)

|-->tick_set_periodic_handler(dev,0);

|-->void

tick_set_periodic_handler(struct clock_event_device *dev, int

broadcast)

{

if

(!broadcast)

dev->event_handler

= tick_handle_periodic;

else

dev->event_handler

= tick_handle_periodic_broadcast;

}

到此我们终于知道了hpet_clockevent->event_handler=tick_handle_periodic。结合前面讲的所有,也就是说

在时钟中断处理函数timer_interrupt()函数里调用的global_clock_event->event_handler=tick_handle_periodic。

到此我们就彻底搞清了中断的注册和调用过程,不过也都是之从代码的角度去讲解的,却不知道为何要使用这么复杂的过程?目的何在?下一次我们具体研究在没一次时钟中断到来的时候,系统都做了那些工作,也就是tick_handle_periodic()函数。

转载地址:http://lknva.baihongyu.com/

你可能感兴趣的文章
《计算广告:互联网商业变现的市场与技术》一第一部分 在线广告市场与背景...
查看>>
话说模式匹配(5) for表达式中的模式匹配
查看>>
《锋利的SQL(第2版)》——1.7 常用函数
查看>>
《Arduino家居安全系统构建实战》——1.5 介绍用于机器学习的F
查看>>
jquery中hover()的用法。简单粗暴
查看>>
线程管理(六)等待线程的终结
查看>>
spring boot集成mongodb最简单版
查看>>
DELL EqualLogic PS存储数据恢复全过程整理
查看>>
《Node.js入门经典》一2.3 安装模块
查看>>
《Java 开发从入门到精通》—— 2.5 技术解惑
查看>>
Linux 性能诊断 perf使用指南
查看>>
实操分享:看看小白我如何第一次搭建阿里云windows服务器(Tomcat+Mysql)
查看>>
Sphinx 配置文件说明
查看>>
数据结构实践——顺序表应用
查看>>
python2.7 之centos7 安装 pip, Scrapy
查看>>
机智云开源框架初始化顺序
查看>>
Spark修炼之道(进阶篇)——Spark入门到精通:第五节 Spark编程模型(二)
查看>>
一线架构师实践指南:云时代下双活零切换的七大关键点
查看>>
ART世界探险(19) - 优化编译器的编译流程
查看>>
玩转Edas应用部署
查看>>