当以艺术眼光看程序,寻找程序后面的原理,做到化而不忘
全部博文(57)
分类: Windows平台
2014-06-07 17:51:51
记得第一份工作,发动机控制器,做项目时,软件要从EEP中读取512B数据到单片机内部建立映像,这样就可以在运行过程中,只修改EEP映像值,避免对对外界的物理EEP访问,在钥匙关闭以后,再一次性将所有的512B数据写到EEP中。当时水平很菜,钥匙上电时,一次性读取所有的数据,耗时很长,大概100多个ms,读取数据时,程序是卡在那里,直到EEP数据读取完全,程序再向下运行,完全是阻塞的,写入时也是这样,程序也是阻塞的,直到写完程序才会向下走。还好这个项目只是领导玩玩,领导不当真,所以程序写得很烂,也没什么事。
现在回头想想,觉得好笑,完全阻塞式的设计,那性能是要大大地降低了,最近看Windows内核方面的资料,发现在OS中,异步机制很常见,也很有用,比如读取文件,如果文件比较大或者时序要求严格,那可不能老是停止在ReadFile那里,所以此函数提供了异步读取功能,通过填写一个Overlap结构体,写入你的回调函数就可实现异步。
说到异步,和中断有点像,但是又有区别。中断对CPU来说,完全是突然的,事先没有任何通知,所以现代CPU对中断还是比较配合的,具体体现在,当中断发生时,CPU会保存一些关键信息到栈中或寄存器中,典型地,当中断发生时,X86会向内核栈中保存当前中断的向量号,保存用户态CS,IP,SS等等寄存器以备中断后返回到用户态,这些是CPU自动保存的。而异步,则某种程序上,是软件来实现的一个机制,是为了系统的性能考虑而提供的一个功能,具体设计取决于软件。
在看Windows内核时,发现异步实现有三种方式(水平有限,只看到这三种,如果有错误,请指教):
1:APC
2:DPC
3:内核劳务线程
APC,DPC名词意义就不说了,不知道的Baidu一下。内核劳务线程比较好理解,就是内核在初始化时,就生成一个线程队列,周期性执行,它们负责一些日常工作,比如实现很有名的IO完成端口功能。说到这里,结合我的实际工作,我们完全可以在系统添加一个类似的线程或函数,来做些辅助性工作,比如实现看门狗的功能,或实现EEP的读写,这样,在上层只要发现读写EEP的请求,并将相应的数据及地址 以参数的形式传递给辅助线程或函数,这样就可以实现异步机制了。
再说说APC,它分为用户APC和内核APC,用户APC的执行时机是系统调用返回时,为什么在这里?我觉得可能是基于这样考虑的,系统调用时,会执行些内核操作,比如读取文件,或从网卡上取数据,系统调用返回时,调用用户APC,给人的感觉是,系统调用完成了任务,然后调用用户APC通知用户,事件做完了,你可以继续了。
内核APC是在IRQL降低时调用的,为什么在这里调用呢?可能原因是这样,IRQL上升是中断发生,IRQL下降可以认为是中断完成,中断完成后调用APC也是起到通知及后事处理作用,当然了IRQL下降也不全是中断完成引起的,它现在也作为线程调度的一个手段了,IRQL下降时,会检测APC和DPC,调用其例程。这样看来,IRQL可以当成一个栈,IRQL的下降时,比如从CLOCK_LVEVL下降到APC_LEVEL,经过DPC_LEVEL和APC_LEVEL时,调用其例程可以当成路过时的回调函数。
CUTianrui0072014-06-09 21:15:34
irp:不管是user/kernel APC, 主要都是为一个目的,asynchronous I/O. user APC => completion user of part, kernel APC => completion of kernel part, kernel APC 后来衍生其他的用处,需要在process context下完成不是很紧急的任务,比如suspend thread etc.
多谢指导!
回复 | 举报