您的位置:首页 > 运维架构 > Linux

linux poll机制

2015-11-09 11:34 483 查看
poll的是一种查询的方式,英文解释 :民意调查

poll提供的功能与select类似,不过在处理流设备时,它能够提供额外的信息。

函数原型:

  #include <poll.h>

  int poll(struct pollfd fd[], nfds_t nfds, int timeout);

参数:

fds为指向待查询的设备文件数组;

nfds描述第一个参数fds中有多少个设备;

timeout为查询不到我们期望的结果进程睡眠的时间;
返回值:查询到期望状态的设备文件个数

   1)第一个参数:一个结构数组,struct pollfd结构如下:

  

struct pollfd 

{     

                         int fd;            
 /* 文件描述符 */ (待查询的设备)

                   short events;   /* 等待的事件 */(待查询的设备的状态)

                   short revents;  /* 实际发生了的事件 */

              }

events和revents是通过对代表各种事件的标志进行逻辑或运算构建而成的。events包括要监视的事件,poll用已经发生的事件填充revents。poll函数通过在revents中设置标志肌肤POLLHUP、POLLERR和POLLNVAL来反映相关条件的存在。不需要在events中对于这些标志符相关的比特位进行设置。如果fd小于0, 则events字段被忽略,而revents被置为0.标准中没有说明如何处理文件结束。文件结束可以通过revents的标识符POLLHUN或返回0字节的常规读操作来传达。即使POLLIN或POLLRDNORM指出还有数据要读,POLLHUP也可能会被设置。因此,应该在错误检验之前处理正常的读操作。

poll函数的事件标志符值
常量说明
POLLIN普通或优先级带数据可读
POLLRDNORM4000
普通数据可读
POLLRDBAND优先级带数据可读
POLLPRI高优先级数据可读
POLLOUT普通数据可写
POLLWRNORM普通数据可写
POLLWRBAND优先级带数据可写
POLLERR发生错误
POLLHUP发生挂起
POLLNVAL描述字不是一个打开的文件
 

  注意:后三个只能作为描述字的返回结果存储在revents中,而不能作为测试条件用于events中。

2)第二个参数nfds:要监视的描述符的数目。

  3)最后一个参数timeout:是一个用毫秒表示的时间,是指定poll在返回前没有接收事件时应该等待的时间。如果  它的值为-1,poll就永远都不会超时。如果整数值为32个比特,那么最大的超时周期大约是30分钟。

 
timeout值说明
INFTIM永远等待
0立即返回,不阻塞进程
>0等待指定数目的毫秒数

例子程序: 

在/root/pro/fd1 /root/pro/fd2中分别有内容,

1234

5678



1122

3344

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <errno.h>

#include <sys/types.h>

#include <stropts.h>

#include <sys/poll.h>

#include <sys/stropts.h>

#include <string.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <poll.h>

#define BUFSIZE 1024

int main(int argc, char *argv[])

{

    char buf[BUFSIZE];

    int bytes;

    struct pollfd *pollfd;

    int i=0;

    int nummonitor=0;

    int numready;

    int errno;

    char *str;

    if(argc != 3)

    {

        fprintf(stderr,"Usage:the argc num error\n");

        exit(1);

    }

    if((pollfd = (struct pollfd*)calloc(2, sizeof(struct pollfd))) == NULL) //为struct pollfd分配空间

           exit(1);

         for(i; i<2; i++) //初始化化struct pollfd结构

    {

        str = (char*)malloc(14*sizeof(char));        

        memcpy(str,"/root/pro/",14); 

        strcat(str,argv[i+1]);//注意,需要把路劲信息放到str中,否则opne("/root/pro/argv[i]",O_RDONLY)会出错

        printf("str=%s\n",str);//原因在于,在” “之中的argv[i]是字符串,不会用变量代替argv[i].

        (pollfd+i)->fd = open(str,O_RDONLY);

        if((pollfd+i)->fd >= 0)

        fprintf(stderr, "open (pollfd+%d)->fd:%s\n", i, argv[i+1]); 

        nummonitor++;

        (pollfd+i)->events = POLLIN;

    }

    printf("nummonitor=%d\n",nummonitor);

      

    while(nummonitor > 0)

    {

        numready = poll(pollfd, 2, -1);

        if ((numready == -1) && (errno == EINTR))

            continue;        //被信号中断,继续等待

        else if (numready == -1)

            break; //poll真正错误,推出

        printf("numready=%d\n",numready);

        for (i=0;nummonitor>0 && numready>0; i++)

        {

            if((pollfd+i)->revents & POLLIN)

            {

                

                 bytes = read(pollfd[i].fd, buf, BUFSIZE);

                numready--;

                printf("pollfd[%d]->fd read buf:\n%s \n", i, buf);

                nummonitor--;

            }

        }

    }

    for(i=0; i<nummonitor; i++)

        close(pollfd[i].fd);

    free(pollfd);

    return 0;

}

输出结果:



二、poll应用举例
int main(int argc, char **argv){      int fd;      unsigned char key_val;      int ret;      struct pollfd fds[1];//查询数组的大小,这里我们仅查询一个设备文件      fd = open("/dev/buttons", O_RDWR);      if (fd < 0)          printf("can't open!\n");      fds[0].fd     = fd;//查询的设备文件描述符为fd,也就是查询的设备是/dev/buttons      fds[0].events = POLLIN;//查询事件是POLLIN,也就是/dev/buttons是否按下      while (1)      {                ret = poll(fds, 1, 5000);//查询的设备队列是fds,里面有1个设备,查询不到就睡眠5s,在睡眠中如果有期望状态出现也是可以返回           if (ret == 0)                  printf("time out\n"); //没有查询到按键按下,睡眠中也没有按键按下           else              {                      read(fd, &key_val, 1);           //查询到按键按下,读取这个按键的值                  printf("key_val = 0x%x\n", key_val);              }      }          return 0;}

三、poll内核实现过程(kernel-2.6.30.4)

(应用程序)poll->sys_poll->do_sys_poll->do_poll->do_pollfd->f_op->poll(驱动)

在do_poll中:

for (;;) 

{       //逐个取出待查询数组中的每个文件描述符来查询

        for
(; pfd != pfd_end; pfd++) 

         {

         
  if (do_pollfd(pfd, pt)) 

             {

              count++;

              pt
= NULL;

         
  }

        }    

        pt
= NULL;

        if
(!count)//如果没有一个设备文件发生可读

         {

         
 count = wait->error;

         
 if (signal_pending(current))

              count
= -EINTR;

        }

       if (count
|| timed_out)//超时或者有设备文件可读,程序直接返回

         
 break;

       if (end_time
&& !to) 

        {

         
 expire = timespec_to_ktime(*end_time);

         
 to = &expire;

       }

       //程序睡眠

       if (!poll_schedule_timeout(wait,
TASK_INTERRUPTIBLE, to, slack))

         
  timed_out = 1;

}

在do_pollfd中:

  if
(file->f_op && file->f_op->poll)

     mask = file->f_op->poll(file, pwait);//调用设备的poll函数,返回是否发生期望的设备状态   

在f_op->poll中(针对按键驱动举例):

 unsigned int
mask = 0;

  poll_wait(file, &button_waitq, wait); //将当前的设备加入到等待队列中,当它不是马上就休眠

  if (ev_press)

     mask |= POLLIN | POLLRDNORM;//返回设备文件现在的状态

  return mask;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: