Linux中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;
 fds[0].events = POLLIN;
 while (1)
 {
  ret = poll(fds, 1, 5000); ///本处的应用程序在while(1)中持续的调用poll函数
  if (ret == 0)
  {
   printf("time out\n");
  }
  else
  {
   read(fd, &key_val, 1);
   printf("key_val = 0x%x\n", 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的思路!



      

猜你喜欢

转载自blog.csdn.net/moxiaoxuan123/article/details/61622531
今日推荐