Linux设备驱动开发详解-Note(17)---Linux 设备驱动中的阻塞与非阻塞 I/O(2)

Linux 设备驱动中的阻塞与非阻塞 I/O(2)

成于坚持,败于止步

轮询操作 

轮询的概念与作用 

在用户程序中,select()和 poll()也是与设备阻塞与非阻塞访问息息相关的论题。使用非阻塞 I/O 的应用程序通常会使用 select()和 poll()系统调用查询是否可对设备进行无阻塞的访问。select()和 poll()系统调用最终会引发设备驱动中的 poll()函数被执行,在 2.5.45 内核中还引入了 epoll(),即扩展的 poll()。 select()和 poll()系统调用的本质一样,前者在 BSD UNIX 中引入的,后者在 System V中引入的。

应用程序中的轮询编程 

应用程序中最广泛用到的是 BSD UNIX 中引入的 select()系统调用,其原型如下: 

int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
其中 readfds、writefds、exceptfds 分别是被 select()监视的读、写和异常处理的文件描述符集合,numfds 的值是需要检查的号码最高的文件描述符加 1。timeout 参数是一个指向 struct timeval 类型的指针,它可以使 select()在等待 timeout 时间后若没有文件描述符准备好则返回。struct timeval 数据结构的定义如代码清单 8.10 所示。 结构体定义 如下:

struct timeval 
{ 
	int tv_sec; /* 秒 */ 
	int tv_usec; /* 微妙 */ 
}; 
下列操作用来设置、清除、判断文件描述符集合。 

FD_ZERO(fd_set *set) 清除一个文件描述符集。 

FD_SET(int fd,fd_set *set) 将一个文件描述符加入文件描述符集中。 

FD_CLR(int fd,fd_set *set) 将一个文件描述符从文件描述符集中清除。 

FD_ISSET(int fd,fd_set *set) 判断文件描述符是否被置位。 

设备驱动中的轮询编程 

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

unsigned int(*poll)(struct file * filp, struct poll_table* wait); 

第一个参数为 file 结构体指针,第二个参数为轮询表指针。这个函数应该进行以下两项工作。 

对可能引起设备文件状态变化的等待队列调用 poll_wait()函数,将对应的等待队列头添加到 poll_table。 

返回表示是否能对设备进行无阻塞读、写访问的掩码。 关键的用于向 poll_table 注册等待队列的 poll_wait()函数的原型如下:

void poll_wait(struct file *filp, wait_queue_heat_t *queue, poll_table * wait); 

poll_wait()函数的名称非常容易让人产生误会,以为它和 wait_event()等一样,会阻塞地等待某事件的发生,其实这个函数并不会引起阻塞。poll_wait()函数所做的工作是把当前进程添加到 wait 参数指定的等待列表(poll_table)中。 

驱动程序 poll()函数应该返回设备资源的可获取状态,即 POLLIN、POLLOUT、POLLPRI、POLLERR、POLLNVAL 等宏的位“或”结果。每个宏的含义都表明设备的一种状态,如 POLLIN(定义为 0x0001)意味着设备可以无阻塞地读,POLLOUT(定义为 0x0004)意味着设备可以无阻塞地写。 

通过以上分析,可得出设备驱动中 poll()函数的典型模板,如代码清单所示

1  static unsigned int xxx_poll(struct file *filp, poll_table *wait) 
2  { 
3      unsigned int mask = 0; 
4      struct xxx_dev *dev = filp->private_data; /*获得设备结构体指针*/ 
5     
6      ...   
7      poll_wait(filp, &dev->r_wait, wait);//加读等待队列头 
8      poll_wait(filp, &dev->w_wait, wait);//加写等待队列头  
9   
10     if (...)//可读 
11     { 
12         mask |= POLLIN | POLLRDNORM; /*标示数据可获得*/ 
13     } 
14    
15     if (...)//可写 
16     { 
17         mask |= POLLOUT | POLLWRNORM; /*标示数据可写入*/ 
18     } 
19       
20     ... 
21     return mask; 
22 } 

就到这里了,O(∩_∩)O~

我的专栏地址:http://blog.csdn.net/column/details/linux-driver-note.html

待续。。。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值