驱动开发(10)直接I/O和内存描述符表

本博文由CSDN博主zuishikonghuan所作,版权归zuishikonghuan所有,转载请注明出处: http://blog.csdn.net/zuishikonghuan/article/details/50643005

在上篇博文中,我们实现了在驱动程序中处理设备收到读写I/O请求,这个请求我们是使用缓冲I/O处理的。

在上一篇中,我已经详细解释了使用缓冲I/O的原因,在这里简单重复一下,如果要看详细解释请看上一篇博文。

当我们调用ReadFile(Ex)和WriteFile(Ex)读写文件,管道或者设备时,我们需要提供一个缓冲区的指针,如果是同步读(注意是同步),那么ReadFile返回后,我们要读的数据就在缓冲区里了,如果是同步写(同样,注意是同步),则WriteFile结束后,我们要写的数据就写完了,当然都是没有出错的情况下。

API调用过程,调用的Win32子系统提供的编程接口,最终调用NT Native API,nativeAPI调用KiFastSystemCall,随后进入内核,调用内核模式下的函数,当调用内核中I/O管理器的接口后,I/O管理器构造生成IRP,并发送到相应设备所在驱动程序的派遣函数中。

产生的问题是:Windows是一个多任务抢占式调度的操作系统(上世纪的Windows1.0等不是抢占式的,是多任务协作式调度的),“进程上下文”和“线程上下文”在频繁地被切换,进程上下文的切换就意味着用户模式虚拟内存(线性地址空间)的切换,我们提供的缓冲区必定是用户模式虚拟内存的一部分,因此,进入内核模式后,如果进程上下文切换了,那么我们的缓冲区指针就变成野指针了!

当应用程序打开一个设备并发出一个 I/O 请求时,会载人到驱动程序的派遣函数中,虽然此时驱动程序的 Dispatch Function 运行在调用 I/O 函数的用户模式线程上下文中,此时访问用户模式虚拟内存并不会带来影响,但现实情况总是要比理想环境复杂很多,首先,驱动程序可能异步处理 I/O 请求(异步完成 IRP 会在以后说)驱动程序会立即返回 Dispatch Function ,将 IRP 加入一个处理队列,并在之后在其他线程中完成他,此时线程上下文可能会随时被切换,从而使用户模式的虚拟内存地址变成野指针;另一种常见的情况是处理 I/O 请求的设备并非只有一个,比如文件系统驱动程序会将 IRP 发送到磁盘设备驱动程序中,而对于之后的设备的派遣函数而言,并不能确定运行在原来用户模式线程上下文中,这会带来同样的问题,即此时线程上下文可能会随时被切换,从而使用户模式的虚拟内存地址变成野指针。

为解决这个问题,因此出现了缓冲I/O设备,直接I/O设备等概念。缓冲I/O设备,就是进入内核后,操作系统分配一块内核空间虚拟内存作为缓冲区,并把用户模式虚拟内存的缓冲区中的数据复制进来,复制完成后,传给驱动程序的地址就是内核模式的地址了,内核模式虚拟内存不会因进程上下文切换而改变映射关系,这个问题就解决了。

我们的驱动程序显然是没有具体的存储硬件的,因此我们不得不寻找一些其他方法,本例中分配了一些内核虚拟内存(非页内存)当做是存储空间。

这些其实是上一篇博文中前面讲的原因的精简版本,如果你读起来感觉不清晰,建议看看我的上一篇博文。

既然缓冲I/O已经看起来很完美的解决了这个问题了,为何还要有直接I/O?

OK,正戏开始了:

我在上一篇博文中已经说过了缓冲I/O的原理,简单说,就是进入内核后,操作系统分配内核模式虚拟内存,将应用程序提供的在用户模式虚拟内存的缓冲区中数据复制到在内核模式虚拟内存的缓冲区中。内核模式虚拟内存不会因为进程上下文的切换而改变映射关系,从而驱动程序处理I/O请求时访问内核模式下的缓冲区,就解决了这个问题了。

这样做的确很简单方便,但是有一个问题:性能比较低,因为缓冲区的复制会消耗CPU时间。

因此,人们找到了优化的方案:直接I/O。

注意;除了缓冲I/O和直接I/O以外,还有一种方法叫“两者都不”(其他I/O)但是这种方法很不安全,因此不推荐使用,本文中也不打算涉及。

我们知道(不知道建议看看我上一篇博文中对虚拟内存的介绍),虚拟内存其实就是将一个“线性”的地址空间按照“页面”的形式映射到物理内存,从而实现了内存页面访问规则和进程内存空间的分离。虚拟内存是非常灵活的,于是,我们可以将用户模式虚拟内存所映射到的物理内存在内核模式重新映射一遍!我们不再需要缓冲区的复制,这极大地节省了不必要的开销,提升了驱动程序的性能。这就是直接I/O。

但事情没有想象的那么好,首先,使用直接I/O会使驱动代码更复杂,另外,在某些时候直接I/O并不能使用,比如在Windows嵌入式系统(比如Windows CE)开发时,驱动程序只能用缓冲I/O。但是我觉得,代码复杂一点无关紧要,因为就稍微复杂了一点,并不是复杂到没法阅读,W

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值