首先分析下应用程序的执行过程:
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的思路!