linux 内核中断与时钟的冲突 问题 del_timer,Linux内核开发之中断与时钟(三)
晚上7点10分..
“小涛哥,这章不是叫Linux设备驱动程序之中断与时钟,前边你讲了中断,还给了我很多模版,我都看懂了,这次是不是要开始讲时钟了..”
“真聪明,越来越喜欢你这聪明的样子了,说的不错,今天就要开始一个新的模块--内核时钟”我很少夸人,为啥今天夸她呢了,呵呵.
定时器,意思大家都明白,我就不说了,要是不明白,把它想成个闹钟总可以吧..
定时器分为硬件和软件定时器,软件定时器最终还是要依靠硬件定时器来完成。内核在时钟中断发生后检测各定时器是否到期,到期后的定时器处理函数将作为软中断在底半部执行。实质上,时钟中断处理程序执行update_process_timers函数,该函数调用run_local_timers函数,这个函数处理TIMER_SOFTIRQ软中断,运行当前处理上到期的所有定时器。
Linux内核中定义提供了一些用于操作定时器的数据结构和函数如下:
1)timer_list:说定时器,当然要来个定时器的结构体struct timer_list{
struct list_head entry; //定时器列表
unsigned long expires; //定时器到期时间
void (*function)(unsigned long) ;//定时器处理函数
unsigned long data; //作为参数被传入定时器处理函数
struct timer_base_s *base;
}2)初始化定时器:void init_timer(struct timer_list *timer);经过这个初始化后,entry的next为NULL,并给base赋值
3)增加定时器:void add_timer(struct timer_list *timer); 该函数用于注册内核定时器,并将定时器加入到内核动态定时器链表中。4)删除定时器:int del_timer(struct timer_list *timer);说明:del_timer_sync是del_timer的同步版,主要在多处理器系统中使用,如果编译内核时不支持SMP,del_timer_sync和del_timer等价.5)修改定时器:int mod_timer(struct timer_list *timer, unsigned long expires);下边是一个使用定时器的模版:
struct xxx_dev /*second设备结构体*/
{
struct cdev cdev; /*cdev结构体*/
...
struct timer_list xxx_timer; /*设备要使用的定时器*/
};
int xxx_func1(...) //xxx驱动中某函数
{
struct xxx_dev *dev = filp->private_data;
...
/*初始化定时器*/
init_timer(&dev->xxx_timer);
dev->xxx_timer.function = &xxx_do_handle;
dev->xxx_timer.data = (unsigned long)dev;
dev->xxx_timer.expires = jiffies + delay;
add_timer(&dev->xxx_timer); /*添加(注册)定时器*/
...
return 0;
}
int xxx_func2(...) //驱动中某函数
{
...
del_timer(&second_devp->s_timer);
...
}
static void xxx_do_timer(unsigned long arg) //定时器处理函数
{
struct xxx_device *dev = (struct xxx_device *)(arg);
...
//调度定时器再执行
dev->xxx_timer.expires = jiffies + delay;
add_timer(&dev->xxx_timer);
}
在定时器函数中往往会在做完具体工作后,延迟expires并将定时器再次添加到内核定时器链表中,以便定时器能被再次触发(这句话我也是从别处抄来的,别告诉小王哈)。
在内核定时器中,常常少不了要说下内核延迟的事,请接着往下看:
1)短延迟:在linux内核中提供了三个函数来分别实现纳秒,微秒,毫秒延迟,原理上是忙等待,它根据CPU频率进行一定次数的循环
void ndelay(unsigned long nsecs); void udelay(unsigned long usecs); void mdelay(unsigned long msecs);
毫秒延迟已经相当大了,当然更秒延迟当然要小一些,在内核中,为了性能,最好不要用mdelay,这会耗费大量cpu资源,那么咋办呢,凉拌..
void msleep(unsigned int millisecs); unsigned long msleep_interruptible(unsigned int millisecs); void ssleep(unsigned int seconds);
这三个是内核专门提供该我们用来处理毫秒以上的延迟。上述函数将使得调用它的进程睡眠参数指定的秒数,其中第二个是可以被打断的,其余的两个是不可以的。
2)长延迟:内核中进行延迟最常用的方法就是比较当前的jiffies和目标jiffies(当前的加上时间间隔的jiffies),直到未来的jiffies达到目标jiffies。比如:
unsigned long delay = jiffies + 100; //延迟100个jiffies
while(time_before(jiffies, delay));
与time_before对应的还有一个time_after().其实就是#define time_before(a,b) time_after(b,a);
另外两个是time_after_eq(a,b)和time_before_eq(a,b)
3)睡着延迟:这显然是比忙等待好的方法,因为在未到来之前,进程会处于睡眠状态,把CPU空出来,让CPU可以做别的事情,等时间到了,调用schedule_timeout()就可以唤醒它并重新调度执行。msleep和msleep_interruptible本质上都是依靠包含了schedule_timeout的schedule_timeout_uninterruptible()和schedule_
timeout_interruptible()实现。就像下边这样:void msleep(unsigned int msecs){
unsigned long timeout = msecs_to_jiffies(msecs) + 1;
while(timeout)
timeout = schedule_timeout_uninterruptible(timeout);
}
unsigned long msleep_interruptible(unsigned int msecs)
{
unsigned long timeout = msecs_to_jiffies(msecs) + 1;
while(timeout && !signal_pending(current))
timeout = schedule_timeout_interruptible(timeout);
return jiffies_to_msecs(timeout);
}
signed long __sched schedule_timeout_interruptible()signed long timeout)
{
__set_current_state(TASK_INTERRUPTIBLE);
return schedule_timeout(timeout);
}
signed long __sched schedule_timeout_uninterruptible()signed long timeout)
{
__set_current_state(TASK_UNINTERRUPTIBLE);
return schedule_timeout(timeout);
}
另外还有如下:
time_on_timeout(wait_queue_head_t *q, unsigned long timeout);
interruptible_sleep_on_timeout(wait_queue_head_t *q, unsigned long timeout);
这两个将当前进程添加到等待队列,从而在等待队列上睡眠,当超时发生时,进程将被唤醒。
“小王,有关中断和系统时钟的咱们也讲完了,下次就给你来一个有关系统时钟的设备驱动例子,巩固一下吧,你可要抓紧哦..“
linux 内核中断与时钟的冲突 问题 del_timer,Linux内核开发之中断与时钟(三)相关推荐
- 嵌入式linux驱动之路07:裸机开发之蜂鸣器,时钟,中断
蜂鸣器简介 有源蜂鸣器只要通电就会叫,所以我们可以做一个供电电路,这个供电电路可以由一个 IO来控制其通断,一般使用三极管来搭建这个电路.为什么我们不能像控制 LED 灯一样,直接将GPIO 接到蜂鸣 ...
- linux kernel 配置(部分) 部分内容翻译自内核帮助文档
linux kernel 2.6.13 在配置内核前,你应当对详细的了解运行内核的系统,根据自己的需要配置内核. 下面,我将解释内核的各个选项,并根据本人的机器作相应的配置. 在此之前,我把机器硬件参 ...
- 嵌入式系统Linux内核开发工程师必须掌握的三十道题
嵌入式系统Linux内核开发工程师必须掌握的三十道题 如果你能正确回答以下问题并理解相关知识点原理,那么你就可以算得上是基本合格的Linux内核开发工程师,试试看! 1) Linux中主要有哪几种内核 ...
- linux中断共享程序实现,如何在非实时linux上实现实时应用程序与内核模块之间共享存储器...
linux并不是严格意义上的实时操作系统,为了实际需要,工程师们必须想尽办法来祢补这一不足,于是出现了rtlinux和rtai等并不强调商业性的软件.免费的rtlinux显然庞大而并不兼容大部分的嵌入 ...
- 【Linux开发】linux设备驱动归纳总结(七):2.内核定时器
linux设备驱动归纳总结(七):2.内核定时器 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...
- tipi 深入理解php内核 pdf_大牛的学习笔记-深入理解Linux内核(完整版)
第一章.绪论 1.Unix文件可以是下列类型之一: a.正规文件(regular file) b.目录(directroy) c.符号链(symbolic link) d.块设备文件(block-or ...
- linux内核调用( )为进程创建虚存区_Linux内核分析-总结篇(九)
本次内容作为Linux内核的总结内容,主要涉及对Linux系统的总体的一些理解,同时将之前的一些总结贴出来作为大家的一个索引,希望笔者一样的菜鸟有一些帮助和入门的作用.从一个初学者的角度对Linux有 ...
- Linux内核网络协议栈2-socket从库函数到内核
一.socket()库函数到系统调用,再到内核 1.Linux运行的C库是glibc: 2.socket()调用如下: 1) socket()->__socket():glibc-2.3.6/s ...
- 嵌入式Linux内核开发工程师必须掌握的三十道题
如果你能正确回答以下问题并理解相关知识点原理,那么你就可以算得上是基本合格的Linux内核开发工程师. 1. Linux中主要有哪几种内核锁?(进程同步与互斥) (1)自旋锁:非睡眠锁 (2)信号量: ...
最新文章
- easyexcel生成excel_阿里JAVA解析Excel工具easyexcel
- 利用Arduino IDE对ATMEGA8等单片机编程
- 设计模式学习笔记——命令模式(Command)
- 在Linux系统安装Nodejs 最简单步骤
- 快速mysql导入sql文件_mysql肿么快速从sql文件导入数据库
- when is this.oModel in sap-ui-core.js initialized for navigation working
- 安卓案例:绑定和解绑服务
- 大数据之-Hadoop3.x_MapReduce_HashPartitioner分区---大数据之hadoop3.x工作笔记0111
- Struts2之异常处理
- 林锐的《高质量编程》学习笔记——内存分配方式
- 通过cmd进行文件格式的转换
- 一度智信:拼多多平台推广有哪些
- 伴儿行“四村点面融入,文化牵线搭桥”项目结项
- IDEA新建项目配置tomcat
- 团宝网员工再次被休假 合作商家欲联合起诉
- 东偶已逝,桑榆非晚。
- 解决Google翻译不能使用的问题
- 《Kafka权威指南(第二版)》内容摘要
- 光盘刻录全能助手Alcohol 120%轻松体验
- 好看又好用的彩色口罩,舒适佩戴安全可靠
热门文章
- python爬虫获取方法_小白学python爬虫:2.获得数据
- linux选择最短路径sdn,基于网络流量的SDN最短路径转发应用
- linux系统模块管理
- python查看文件夹文件的所有权限,Python判断某个用户对某个文件的权限
- 基于HTML在线考试系统开题报告,基于JSP的在线考试系统 开题报告.doc
- java什么是最终类型_golang和java,谁才是最终答案?
- page rank算法
- np.reshape带给我的内存错误
- centos yum php apc,centos – PECL APC安装 – 错误:’make’失败
- Python环境下的数据库编程