Chinaunix首页 | 论坛 | 博客
  • 博客访问: 66788
  • 博文数量: 21
  • 博客积分: 290
  • 博客等级: 二等列兵
  • 技术积分: 286
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-30 16:16
文章分类
文章存档

2019年(3)

2017年(1)

2012年(17)

我的朋友

分类: LINUX

2012-04-05 19:13:39

    前面讲到了阻塞I/O,它不得不让进程睡眠,若该进程就只负责一个文件操作,
 
那还好,可偏偏有时一个进程得负责好几个文件,而因为一个阻塞IO而导致了其他
 
事情也做不来,这是不可取的方法。而有时用非阻塞IO,即read没数据可读立刻返
 
回,write没内存可写立刻返回,那有时我们就想这样下来岂不想做的事情的都没做
 
啊。这时我们就想尽办法,要把我们所想做的事情给做完,我就一个一个文件判断
 
是否能满足我的要求,如果一遍不行,那我再来一遍,就这样轮流判断啊==>这引出
 
了非阻塞IO的操作方法-->轮回操作(poll)。而对应用户程序是 select 系统调
 
用。
     1、系统调用 select 使用方法
    
     (1)构造文件描述符表集
 

    (2)清除文件描述符表集

    (3)测试文件描述符是否在添加的集合中

    (4)清空描述符表集

  1. void FD_CLR(int fd, fd_set *fdset)
  2. void FD_SET(int fd, fd_set *fdset)
  3. void FD_ZERO(fd_set *fdset)
  4. int FD_ISSET(int fd, fd_set *fdset)
  5.  Return:若fd在描述符表中,则返回非0,否则返回0

    select 函数原型

  1. #include <sys/seclect.h>
  2. /*
  3.  * @brief               非阻塞IO轮询操作
  4.  * @param[in]           maxfd 需要检查的号码最高的文件描述符加 1
  5.  * @param[in] readfds   监视读的文件描述符集
  6.  * @param[in] writefds  视写的文件描述符集
  7.  * @param[in] exceptfds 监视异常的文件描述符集
  8.  * @param[in] timeout 则是一个时间上限值,超过该值后,即使仍没有描述符准备好也会返回
  9.  * struct timeval
  10.    {
  11.      int tv_sec; //
  12.      int tv_usec; //微秒
  13.    }
  14.  * @return            @li == -1 表示出错
  15.  * @li == 0 表示没有描述符准备好
  16.  * @li >> 0 表示已有几个描述符准备好了
  17.  */
  18. int select(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
  19.             struct timeval *tptr)

 

     2、poll 设备方法

     这个驱动方法被调用, 无论何时用户空间程序进行一个 poll, select, 或者

epoll 系统调用, 涉及一个和驱动相关的文件描述符. 这个设备方法负责这两

步:  

    (1)在一个或多个可指示查询状态变化的等待队列上调用 poll_wait. 如果

没有文件描述符可用作 I/O, 内核使这个进程在等待队列上等待所有的传递给系统

调用的文件描述符.  

    (2)返回一个位掩码, 描述可能不必阻塞就立刻进行的操作. 

     这 2 个操作常常是直接的, 并且趋向与各个驱动看起来类似. 但是, 它们依

赖只能由驱动提供的信息, 因此, 必须由每个驱动单独实现. 

  

  1. #include <linux/poll.h>
  2. typedef struct poll_table_struct
  3. {
  4.     poll_queue_proc qproc;
  5.     unsigned long key;
  6. } poll_table;

  7. /*
  8.  * @brief             poll 设备驱动
  9.  * @param[in]        filp 文件指针==>获取设备结构指针
  10.  * @param[in] wait poll轮询操作的等待队列
  11.  * @return            返回是位掩码
  12.  */
  13. unsigned int (*poll) (struct file *filp, poll_table *wait);

  14. 第一步:【将用户程序的要监听的描述符集<等待队列>添加到 poll_table 中】
  15. /*
  16.  * @brief            
  17.  * @param[in]        filp 文件指针==>获取设备结构指针==>从而获取要监听的描述符集
  18.  * @param[in] queue 监听的描述符集<等待队列>
  19.  * @param[in] wait poll轮询操作的等待队列
  20.  * @return            no
  21.  */
  22. void poll_wait(struct file *filp, wait_queue_head_t *queue, poll_table *wait);

  23. 第二步:位掩码
  24. POLLIN 如果设备可被不阻塞地读, 这个位必须设置.
  25. POLLRDNORM 这个位必须设置, 如果"正常"数据可用来读.
  26.      一个可读的设备返回 (POLLIN|POLLRDNORM).
  27. POLLOUT 这个位在返回值中设置, 如果设备可被写入而不阻塞.
  28. POLLWRNORM 这个位和 POLLOUT 有相同的含义, 并且有时它确实是相同的数.
  29.      一个可写的设备返回( POLLOUT|POLLWRNORM).
  30. POLLRDBAND 这个位指示带外数据可用来从设备中读取. 当前只用在 Linux 内核的一个地方
  31. (DECnet代码)并且通常对设备驱动不可用.
  32. POLLPRI 高优先级数据(带外)可不阻塞地读取. 这个位使 select 报告在文件上遇到一个异
  33.          常情况, 因为 selct 报告带外数据作为一个异常情况.
  34. POLLHUP 当读这个设备的进程见到文件尾, 驱动必须设置 POLLUP(hang-up). 一个调用
  35.          select的进程被告知设备是可读的, 如同 selcet 功能所规定的.
  36. POLLERR 一个错误情况已在设备上发生. 当调用 poll, 设备被报告位可读可写, 因为读写
  37.          都返回一个错误码而不阻塞.
  38. POLLWRBAND 如同 POLLRDBAND , 这个位意思是带有零优先级的数据可写入设备. 只有 poll 的
  39.             数据报实现使用这个位, 因为一个数据报看传送带外数据

  40. eg、
  41. static unsigned int XXX_poll(struct file *filp, poll_table *wait)
  42. {
  43.     unsigned int mask = 0;
  44.     struct XXX_dev *dev = filp->private_data; //获得设备结构指针
  45.         
  46.     poll_wait(filp, &dev->r_fds, wait); //加读等待对列头
  47.     poll_wait(filp ,&dev->w_fds, wait); //加写等待队列头
  48.     
  49.     if(...)//可读
  50.     {
  51.           mask |= POLLIN | POLLRDNORM; //标识数据可获得
  52.      }
  53.     if(...)//可写
  54.     {
  55.           mask |= POLLOUT | POLLRDNORM; //标识数据可写入
  56.      }
  57.     
  58.     return mask;
  59. }

    3、poll 实现源代码

    在头文件/include/linux/poll.h 和 跟目录下/fs/select.c 中


 
 



 



 


 

 
    
阅读(1140) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~