linux驱动之内核空间几种长延时的实现策略的优劣评估
本文转载自http://blog.chinaunix.net/uid-23769728-id-3084737.html
这里所谓的长延时,是指其实现时间延时的粒度可以在HZ这一水准上。《深入Linux设备驱动程序内核机制》第8章"时间管理"中提到了好几种实现延时功能的机制,包括长延时短延时等,对每一种延时机制的优劣都有理论上的分析。
本帖旨在从另一个角度探讨一下其中所提到的“长延时”的三个实现方式,这些延时方式都试图让出处理器,换句话说都是基于非忙等待的实现(因为长延时若是忙等待,将极大浪费处理器的资源)与书中的原理分析不同之处在于,我希望在本帖中以实际的代码验证的方式来使那种理论上的分析更加直观化:我们在一个内核模块,比如demodev.ko的初始化函数中调用这些延时函数,然后通过ps命令来查看延时期间insmod进程的状态。
首先我们看第一种实现(为了有足够的时间让我们去查看进程的状态,我将这种“长延时”延时间隔设定30S,这样足够我们在此延时的窗口期间观察insmod进程的状态):
void delay_30s(void){
unsigned long j = jiffies + * HZ;
while(time_before(jiffies, j))
schedule();
}
这种实现采用了schedule的方式,貌似会重新调度一个新进程。其实因为当前进程状态没有改变,所以调用delay_30s的当前进程仍然处在CPU的运行队列中,进程状态为TASK_RUNNING.30s延时的目的肯定能达到了,但是该进程随时可能被调度器所调度,若是处理器的运行队列中只有这一个进程,CPU无法进入idle状态,而后者可以被电源管理模块所利用。如果我们insmod demodev.ko,那么通过ps命令来查看该进程状态时,会发现如下的输出信息:
root@build-server:/home/dennis/book_2nd_edition/book_sourcecode# ps aux | grep insmod
root 6491 100 0.0 4420 576 pts/2 R+ 21:55 0:28 insmod demodev.ko
root 6514 0.0 0.0 13448 872 pts/3 S+ 21:56 0:00 grep --color=auto insmod
insmod进程的R+状态意味着当前进程处在后台一个运行的状态下。
再来看一个改进版:
void delay_30s(void){
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout( * HZ);
}
这次在schedule_timeout调用之前,先把进程状态改成TASK_INTERRUPTIBLE。schedule_timeout()函数内部会启用一个内核timer,同时会调用schedule()。一旦schedule()函数被调用,当前进程将从处理器的运行队列中移走,移走的current进程会被放到内核定时队列的一个结点中。当30S的时间到期时,定时器上的函数会唤醒current,delay_30s函数将从schedule_timeout函数中返回。如果我们insmod demodev.ko,那么通过ps命令来查看该进程状态时,会发现如下的输出信息:
root@build-server:/home/dennis/book_2nd_edition/book_sourcecode# ps aux | grep insmod
root 6300 0.0 0.0 4420 580 pts/2 S+ 21:53 0:00 insmod demodev.ko
root 6306 0.0 0.0 13448 868 pts/3 S+ 21:53 0:00 grep --color=auto insmod
insmod进程的S+状态意味着当前进程处在后台一个睡眠的状态下。如果你的调用上下文允许当前进程进入睡眠,那么这是一个非常完美的实现:睡眠的进程不占用处理器资源,同时延时的目的也达到了。
最后,我们来试图改进第一种的那个方案,代码如下:
void delay_30s(void){
unsigned long j = jiffies + * HZ;
while(time_before(jiffies, j)){
set_current_state(TASK_UNINTERRUPTIBLE);
schedule();
}
如果你在demodev.ko的初始化函数中调用了上面这个函数,insmod demodev.ko将回不到shell状态下了,ctrl+c也不行,如果换成TASK_INTERRUPTIBLE的话还可以用CTRL+C来杀死当前进程。这里的问题在于在schedule()前调用set_current_state(TASK_UNINTERRUPTIBLE),将导致当前进程从处理器运行队列中移开,一旦移开,current进程将处于流浪状态,谁会去收留它呢?它将永远失去被处理器调度的机会,不过此时若用ps aux来看一下insmod进程状态的话,会发现它处于S+状态,因为在schedule函数之前那个set_current_state的调用。
最后我想提一下那个schedule_timeout函数,如果调用该函数前没有用改变进程的状态,那么这个函数基本上是瞬间返回(其实取决于当前处理器运行队列及调度器行为),虽然它初始化并提交了一个定时器结点,但是它调用schedule时基本上是很快会被调度器再次调度,然后它有个del_singleshot_timer_sync(&timer)调用,后者将把之前提交的定时器结点从定时器管理队列中摘除,因为如果当前进程一旦结束,放到此前提交的定时器结点中的current将指向无意义的空间。
linux驱动之内核空间几种长延时的实现策略的优劣评估的更多相关文章
- Linux驱动的两种加载方式过程分析
一.概念简述 在Linux下可以通过两种方式加载驱动程序:静态加载和动态加载. 静态加载就是把驱动程序直接编译进内核,系统启动后可以直接调用.静态加载的缺点是调试起来比较麻烦,每次修改一个地方都要重新 ...
- Linux驱动的两种载入方式过程分析
一.概念简述 在Linux下能够通过两种方式载入驱动程序:静态载入和动态载入. 静态载入就是把驱动程序直接编译进内核.系统启动后能够直接调用.静态载入的缺点是调试起来比較麻烦,每次改动一个地方都要又一 ...
- Linux 网络编程的5种IO模型:信号驱动IO模型
Linux 网络编程的5种IO模型:信号驱动IO模型 背景 上一讲 Linux 网络编程的5种IO模型:多路复用(select/poll/epoll) 我们讲解了多路复用等方面的知识,以及有关例程. ...
- Linux驱动实践:你知道【字符设备驱动程序】的两种写法吗?
作 者:道哥,10+年嵌入式开发老兵,专注于:C/C++.嵌入式.Linux. 关注下方公众号,回复[书籍],获取 Linux.嵌入式领域经典书籍:回复[PDF],获取所有原创文章( PDF 格式). ...
- Linux 驱动开发
linux驱动开发总结(一) 基础性总结 1, linux驱动一般分为3大类: * 字符设备 * 块设备 * 网络设备 2, 开发环境构建: * 交叉工具链构建 * NFS和tftp服务器安装 3, ...
- Linux驱动开发必看详解神秘内核(完全转载)
Linux驱动开发必看详解神秘内核 完全转载-链接:http://blog.chinaunix.net/uid-21356596-id-1827434.html IT168 技术文档]在开始步入L ...
- LINUX驱动、系统底层
就业模拟测试题-LINUX驱动.系统底层工程师职位 本试卷从考试酷examcoo网站导出,文件格式为mht,请用WORD/WPS打开,并另存为doc/docx格式后再使用 试卷编号:143921试卷录 ...
- Linux驱动设计—— 中断与时钟
中断和时钟技术可以提升驱动程序的效率 中断 中断在Linux中的实现 通常情况下,一个驱动程序只需要申请中断,并添加中断处理函数就可以了,中断的到达和中断函数的调用都是内核实现框架完成的.所以程序员只 ...
- linux驱动面试题整理
1.字符型驱动设备你是怎么创建设备文件的,就是/dev/下面的设备文件,供上层应用程序打开使用的文件? 答:mknod命令结合设备的主设备号和次设备号,可创建一个设备文件. 评:这只是其中一种方式,也 ...
随机推荐
- 1.pandas打开和读取文件
最近在公司在弄数据分析相关的项目,数据分析就免不了要先对数据进行处理,也就自然避不开关于excel文档的初始化操作了. 一段时间之后,发现pandas更加符合我的项目要求,所以,将一些常规操作记录下来 ...
- CMD运行JAVA出现“错误:编码GBK的不可映射字符”
问题: 原因: 字符编码问题.由于java文件中有中文字符,而cmd在编译时解码默认使用GBK,所以导致无法解码出正确的中文字符. 解决办法: 使用-encoding指令指定运行编码为UTF-8.
- 【接单】找我付费定制Python工具软件或网站开发、Chrome浏览器插件、油猴脚本
各位可付费找我定制Python工具软件或网站开发.Chrome插件.油猴脚本.自动化软件,可通过我做的软件来评判我的实力,一定要先和我沟通你的需求,做不了的我也不会接. 费用50元起,通过淘宝APP或 ...
- vuex多多,怎么当好一个奶妈
前言 vue 本身更偏向于 view 层的框架,尤大大并没有一开始就给他一个完整的 mvvm 架构. 在 vue 的世界里 vuex 是用来实现 mvvm 中关键的 vm 层(视图模型层),你甚至可以 ...
- Spring Cloud系列之使用Feign进行服务调用
在上一章的学习中,我们知道了微服务的基本概念,知道怎么基于Ribbon+restTemplate的方式实现服务调用,接着上篇博客,我们学习怎么基于Feign实现服务调用,请先学习上篇博客,然后再学习本 ...
- Java锁_读写锁
独占锁:是指锁一次只能被一个线程持有,ReentrantLock和Synchronized都是独占锁. 共享锁:是指锁可以被多个线程持有. 对于ReentrantReadWriteLock,其读锁是共 ...
- PHP debug_print_backtrace() 函数
定义和用法 debug_print_backtrace() 函数打印 backtrace. 该函数显示由 debug_print_backtrace() 函数代码生成的数据. 语法 debug_pri ...
- 5.22 noip模拟赛
本来我是不想写的,无奈不会写.蒟蒻 考场就是想不出来 今天得到了100分额外水过了100分我是真的失败.还有一个根本不会check 感觉自己非常之菜. 这道题是这样的 还行吧比较有意思 首先确立一个真 ...
- day4. 运算符
运算符包括算数运算符.比较运算符.赋值运算符.成员运算符.身份运算符.逻辑运算符.位运算符 python运算符 注意点 算数运算符 % 取余 , //地板除 , ** 幂运算 比较运算符 == 比较两 ...
- Python接口自动化测试框架: pytest+allure+jsonpath+requests+excel实现的接口自动化测试框架(学习成果)
废话 最近在自己学习接口自动化测试,这里也算是完成一个小的成果,欢迎大家交流指出不合适的地方,源码在文末 问题 整体代码结构优化未实现,导致最终测试时间变长,其他工具单接口测试只需要39ms,该框架中 ...