poll机制

用中断来实现按键驱动程序里面,如果我们一直没有按键按下触发中断应用程序会一直的在休眠,现在我们想让它隔一段时间就返回一个值要怎么做呢,这就是POLL机制,我们可以用poll机制来实现它,下面来分析一下这个poll机制:

我们知道当我们应用程序open,write..时,驱动程序里面也会有相应的open,write等函数(其实是产生了一个软中断,swi异常处理函数指针被组织成了一个表格,swi指令机器码的位[23:0]被用来索引,这样通过不同的swi index指令就可以调用不同的swi异常处理函数,它们被称为系统调用,比如sys_open,sys_read,sys_poll等);那poll也是一样的,当我们应用程序poll时,驱动程序也会有一个poll,那我们现在就从sys_poll入手来分析poll机制是怎样的;

应用程序:poll

内核:sys_poll

          do_sys_poll(.....,struct timespec *end_time)
              poll_initwait(&table);

                   init_poll_funcptr(&pwq->pt, __pollwait);>(table->qproc = __pollwait)pt->qproc = qproc;

                do_poll(nfds, head, &table, end_time);

                    for (;;)

                     {

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

                               if (do_pollfd(pfd, pt)) {>mask = file->f_op->poll(file, pwait);

                                                                 //驱动poll

                                                       mask = poll_wait(file, &button_waitq, wait)

                                                       mask = __pollwait (filp,&button_waitq, p);

                                                     //把当前进程挂到button_waitq队列中


                                     count++;//如果返回mask非0count++
                                     pt = NULL;

                       //break条件count非0,timed_out非0

                              if (count || timed_out)
                                      break;
                               }

                               }

                              if (end_time && !to) {
                                expire = timespec_to_ktime(*end_time);
                                 to = &expire;
                                         }

                                  timed_out = 1;//表示休眠结束,就会在上面跳出这个死循环

                      }

大致流程就是这样,不同内核版本所用的处理函数不一样,下面来总结一下大体流程

(1)应用程序poll时会调用内核syy_poll,sys_poll调用do_sys_poll;

(2)do_sys_poll再调用 poll_initwait(&table);来进行一些初始化,初始化结果是pt->qproc = qproc; =table->qproc = __pollwait ,这在后面调用驱动力poll时用到;

(3)然后调用 do_poll(nfds, head, &table, end_time),进入一个死循环,在里面调用do_pollfd(pfd, pt),这个函数其实就是调用   mask = file->f_op->poll(file, pwait),也就是调用我们驱动程序的poll,驱程序会调用poll_wait(file, &button_waitq, wait),跟踪下去就知道这个函数最后会调用p->qproc(filp, wait_address, p),也就是我们第二部初始化了p->qproc(filp, wait_address, p),所以这里是调用 __pollwait (filp,&button_waitq, p),它实现功能是把当前进程挂到button_waitq队列中 还没有休眠;

(4)如果驱动poll返回一个非0的值,上面count++,这也就说明了有按键按下了,上面就会break跳出循环,返回一个非0值;

(5)如果驱动poll返回一个0,说明我们没按下按键,这是就会往下执行  if (end_time && !to),to初始化时0,我们在应用程序时回传进一个 end_time ,end_time不是0时if (end_time && !to) {
                                                   expire = timespec_to_ktime(*end_time);
                                                     to = &expire;
                                                      }

会一直在这里循环,当她数到0时跳出;

(6)然后就是 timed_out = 1,由上面if (count || timed_out)可知,这时也会跳出这个死循环,这时会返回0;

下面我们先看我们应用程序:

 #include
#include
#include
#include
#include   //要把这个头文件加进来
int main()
{
 int fd=-1;
 unsigned char key;
 int ret;//用来接收返回值
 struct pollfd fds[1]; //定义一个struct pollfd 结构体 //struct pollfd {
                                                       // int fd; 
                                                        //short events;
                                                        //short revents;
                                                         };
 fd = open("/dev/ccc",O_RDWR);
 if(fd<0)
 {
 printf("can't open /dev/ccc\n");
 return -1;
 }
 fds[0].fd = fd;//用来指定查询的驱动程序
 fds[0].events = POLLIN;//期待返回值,表示有数据等待读取,也就是说按键按下了
  while(1)
   {
    ret = poll(fds,1,5000);//查询一个文件,超时时间为5S
  if(ret == 0)
   {
   printf("time out\n");
   }
  else{
   

你可能感兴趣的:(Linux,Driver)