深入浅出:Linux设备驱动中的阻塞和非阻塞I/O

今天写的是Linux设备驱动中的阻塞和非阻塞I/0,何谓阻塞与非阻塞I/O?简单来说就是对I/O操作的两种不同的方式,驱动程序可以灵活的支持用户空间对设备的这两种访问方式。

一、基本概念:

  • 阻塞操作 : 是指在执行设备操作时,若不能获得资源,则挂起进程直到满足操作条件后再进行操作。被挂起的进程进入休眠, 被从调度器移走,直到条件满足。
  • 非阻塞操作 :在不能进行设备操作时,并不挂起,它或者放弃,或者不停地查询,直到可以进行操作。非阻塞应用程序通常使用select系统调用查询是否可以对设备进行无阻塞的访问最终会引发设备驱动中 poll函数执行。

二、轮询操作

阻塞的读取一个字符:

非阻塞的读一个字符:

阻塞操作常常用等待队列来实现,而非阻塞操作用轮询的方式来实现。非阻塞I/O的操作在应用层通常会用到select()和poll()系统调用查询是否可对设备进行无阻塞访问。select()和poll()系统调用最终会引发设备驱动中的poll()函数被调用。这里对队列就不多介绍了,大家可以看看数据结构里面的知识点。

应用层的select()原型为:

应用程序为:

下面说说设备驱动中的poll()函数,函数原型如下:

  • 对可能引起设备文件状态变化的等待队列调用poll_wait()函数,将对应的等待队列头添加到poll_table
  • 返回表示是否能对设备进行无阻塞读,写访问的掩码

这里还要提到poll_wait()函数,很多人会以为是和wait_event()一样的函数,会阻塞的等待某件事情的发生,其实这个函数并不会引起阻塞,它的工作是把当前的进程增添到wait参数指定的等待列表poll_table中去,poll_wait()函数原型如下:

驱动函数中的poll()函数典型模板如下:

三、支持轮询操作的globalfifo驱动

在globalfifo的poll()函数中,首先将设备结构体重的r_wait和w_wait等待队列头加到等待队列表,globalfifo设备驱动的poll()函数如下:

四、总结

阻塞与非阻塞操作:

  • 定义并初始化等待对列头;
  • 定义并初始化等待队列;
  • 把等待队列添加到等待队列头
  • 设置进程状态(TASK_INTERRUPTIBLE(可以被信号打断)和TASK_UNINTERRUPTIBLE(不能被信号打断))
  • 调用其它进程

poll机制:

  • 把等待队列头加到poll_table
  • 返回表示是否能对设备进行无阻塞读,写访问的掩码
2 收藏 评论

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部