Linux中poll机制的理解

2019-07-13 06:16发布

首先分析下应用程序的执行过程: 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! ");
 }  fds[0].fd     = fd;
 fds[0].events = POLLIN;
 while (1)
 {
  ret = poll(fds, 1, 5000); ///本处的应用程序在while(1)中持续的调用poll函数
  if (ret == 0)
  {
   printf("time out ");
  }
  else
  {
   read(fd, &key_val, 1);
   printf("key_val = 0x%x ", key_val);
  }
 }
 
 return 0;
} /**********************************************************************************************************************************/ 应用程序中在while(1)循环中持续的调用poll函数,poll函数根据file->op 结构体在其中寻找成员函数poll ->通过调用成员函数poll 由用户空间进入系统内核,内核自动调用sys_poll();函数,接下来介绍内核调用函数顺序过程,缩进代表子函数调用: app:poll kernel: sys_poll                do_sys_poll(......, timeout_jffies);                     poll_initwait(&table);  设置一个变量 table->qproc=_pollwait  以后会用到                            init_poll_funcptr(&pwq->pt,__pollwait); //就是将table->qproc=__pollwait                      do_poll(nfds,head,&table,timeout);                            for(;;)//死循环 也就是说 根本不给外层用户空间while(1)循环调用的机会,加上后面的休眠机制,所以对系统CPU资源的消耗会比较小                            {                                    if(do_pollfd(pfd,pt))// 这个地方函数分析:实际执行 mask= file->f_op->poll(file,pwait);   return mask;                                      {                                     count++;     //所以 如果 驱动程序中的 poll的返回值非零,那么可以让count++:否则count=0;                                     pt= NULL;                                    }                                       }
                       //break的条件来了                           if(count|| !*timeout||signal_pending(current))                                break;
                       //休眠                         _timeout= schedule_timeout(_timeout);
到这里 poll机制的内核调用部分框架结束;
/********************************再将内核驱动程序中的poll函数贴出来*********************************************/
static unsigned forth_drv_poll(struct file *file, poll_table *wait)
{
 unsigned int mask = 0;
 poll_wait(file, &button_waitq, wait); // 不会立即休眠  if (ev_press)
  mask |= POLLIN | POLLRDNORM;  return mask;
}

内核调用 sys_poll以后,会调用驱动中的poll函数   然后poll函数主要做两件事情:                                                   1 执行poll_wait(file,&button_waitq,wait); 函数                                                                    分析:p->qproc(filp, wait_address, p);  而这个 q->proc 就是之前设置的__pollwait                                                                   所以执行_pollwait();函数 作用是将当前进程挂载到运行队列中

                                                 2  查询一下(ev_press)这个标志位 检测是否发生了中断,如果是的,那么MASK返回非零值,                                                      内核中就可以break出这个死循环,进而处理别的

     如果当时没有发生中断 MASK值为零,那么会进入休眠状态 _timeout*****();这个函数                                                                  此时它仍然可以被唤醒 两种情况 一种计时时间到,自动跳出死循环,来到外部应用程序死循环中;第二次执行上述过程                                                                 
                                                                 第二种,发生中断情况,此时进入中断处理函数,将ev_press的值变为1. 同时唤醒进程(唤醒以后从哪里开始执行不是很了解!!!)                                                                  唤醒进程以后,驱动程序继续运行,继续判断if(ev_press)是否为真,此时poll函数返回非零值  应用程序获取到非零值,执行相应的操作           现在的理解是 _pollwait();函数就是将当前执行代码加载到可执行队列中,也就意味着一旦唤醒 从此处继续执行!!!!
    希望会对没有接触过操作系统学linux的同学一点理解poll的思路!