Chinaunix首页 | 论坛 | 博客
  • 博客访问: 306514
  • 博文数量: 86
  • 博客积分: 2050
  • 博客等级: 大尉
  • 技术积分: 1215
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-29 10:29
文章分类

全部博文(86)

文章存档

2011年(2)

2010年(77)

2009年(7)

我的朋友

分类: 嵌入式

2010-01-06 11:57:54

 
 
select()函数的作用
      系统调用select和poll的后端实现,用这两个系统调用来查询设备是否可读写,或是否处于某种状态。如果poll为空,则驱动设备会被认为即可读又可写,返回值是一个状态掩码
如何使用select()函数?
      select()函数的接口主要是建立在一种叫'fd_set'类型的基础上。它('fd_set') 是一组文件描述符(fd)的集合。由于fd_set类型的长度在不同平台上不同,因此应该用一组标准的宏定义来处理此类变量:

     fd_set set;
     FD_ZERO(&set);        /* 将set清零 */
     FD_SET(fd, &set);     /* 将fd加入set */
     FD_CLR(fd, &set);     /* 将fd从set中清除 */
     FD_ISSET(fd, &set);   /* 如果fd在set中则真 */
      
在 过去,一个fd_set通常只能包含少于等于32个文件描述符,因为fd_set其实只用了一个int的比特矢量来实现,在大多数情况下,检查 fd_set能包括任意值的文件描述符是系统的责任,但确定你的fd_set到底能放多少有时你应该检查/修改宏FD_SETSIZE的值。*这个值是系 统相关的*,同时检查你的系统中的select() 的man手册。有一些系统对多于1024个文件描述符的支持有问题。[译者注: Linux就是这样 的系统!你会发现sizeof(fd_set)的结果是128(*8 = FD_SETSIZE=1024) 尽管很少你会遇到这种情况。]

select的基本接口十分简单:

     int select(int nfds, fd_set *readset, fd_set *writeset,
                fd_set *exceptset, struct timeval *timeout);
      
其中:

nfds     
      需要检查的文件描述符个数,数值应该比是三组fd_set中最大数
      更大,而不是实际文件描述符的总数。
readset    
      用来检查可读性的一组文件描述符。
writeset
      用来检查可写性的一组文件描述符。
exceptset
      用来检查意外状态的文件描述符。(注:错误并不是意外状态)
timeout
      NULL指针代表无限等待,否则是指向timeval结构的指针,代表最
      长等待时间。(如果其中tv_sec和tv_usec都等于0, 则文件描述符
      的状态不被影响,但函数并不挂起)
      
函数将返回响应操作的对应操作文件描述符的总数,且三组数据均在恰当位置被修改,只有响应操作的那一些没有修改。接着应该用FD_ISSET宏来查找返回的文件描述符组。

这里是一个简单的测试单个文件描述符可读性的例子:

      int isready(int fd)
      {
          int rc;
          fd_set fds;
          struct timeval tv;
    
          FD_ZERO(&fds);
          FD_SET(fd,&fds);
         // tv.tv_sec = tv.tv_usec = 0;
    
//rc = select(fd+1, &fds, NULL, NULL, &tv);
   rc = select(fd+1, &fds, NULL, NULL, NULL);
          if (rc < 0)
            return -1;
    
          return FD_ISSET(fd,&fds) ? 1 : 0;
      }
      
当然如果我们把NULL指针作为fd_set传入的话,这就表示我们对这种操作的发生不感兴趣,但select() 还是会等待直到其发生或者超过等待时间。

[译 者注:在Linux中,timeout指的是程序在非sleep状态中度过的时间,而不是实际上过去的时间,这就会引起和非Linux平台移植上的时间不 等问题。移植问题还包括在System V风格中select()在函数退出前会把timeout设为未定义的 NULL状态,而在BSD中则不是这样, Linux在这点上遵从System V,因此在重复利用timeout指针问题上也应该注意。]
Linux下select调用的过程:
1.用户层应用程序调用select(),底层调用poll())
2.核心层调用sys_select() ------> do_select()
最终调用文件描述符fd对应的struct file类型变量的struct file_operations *f_op的poll函数。
poll指向的函数返回当前可否读写的信息。
1)如果当前可读写,返回读写信息。
2)如果当前不可读写,则阻塞进程,并等待驱动程序唤醒,重新调用poll函数,或超时返回。
3.驱动需要实现poll函数。
当驱动发现有数据可以读写时,通知核心层,核心层重新调用poll指向的函数查询信息。
poll_wait(filp,&wait_q,wait)    // 此处将当前进程加入到等待队列中,但并不阻塞
在中断中使用wake_up_interruptible(&wait_q)唤醒等待队列
阅读(1008) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~