poll机制

所有的系统调用,基于都可以在它的名字前加上“sys_”前缀,这就是它在内核中对应的函数。比如系统调用open、read、write、poll,与之对应的内核函数为:sys_open、sys_read、sys_write、sys_poll。

对于系统调用poll或select,它们对应的内核函数都是sys_poll。分析sys_poll,即可理解poll机制。

执行过程:

poll > sys_poll > do_sys_poll > poll_initwait

1.do_sys_poll函数位于fs/select.c文件中

do_sys_poll中有个循环for(;;){

...}

退出循环的条件是:(count非0,超时、有信号等待处理)   

      1.count非0---在do_pollfd函数中:调用驱动中的poll函数,驱动程序中的Poll函数的工作 有两个,一个就是调用poll_wait 函数,把进程挂到等待队列中去,另一个是确定相关的fd是否有内容可 读,如果可读,就返回1,否则返回0,如果返回1 ,do_poll函数中的count++。

      2.超时:让本进程休眠一段时间,注意:应用程序执行poll调用后,如果条件不满足,进程就会进入休眠。休眠到指定时间被系统唤醒。

      3.有信号等待处理:(未懂)

驱动中:

  

static unsigned 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;        //若返回0则进行休眠
}
file_operations:
       .poll    =  drv_poll,
中断内:
        ev_press = 1;                  /* 表示中断发生了 */
        wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */



测试程序中:
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);    //用poll机制定时5000ms,超时唤醒
        if (ret == 0)    //        ret==mask
        {
            printf("time out\n");    每5000ms输出一次
        }
        else
        {
            read(fd, &key_val, 1);
            printf("key_val = 0x%x\n", key_val);
        }
    }
    
    return 0;
}
int poll(struct pollfd fds[], nfds_t nfds, int timeout);
参数说明:
fds:是一个struct pollfd结构类型的数组,用于存放需要检测其状态的Socket描述符;每当调用这个函数之后,系统不会清空这个数组,操作起来比较方便;特别是对于socket连接比较多的情况下,在一定程度上可以提高处理的效率;这一点与select()函数不同,调用select()函数之后,select()函数会清空它所检测的socket描述符集合,导致每次调用select()之前都必须把socket描述符重新加入到待检测的集合中;因此,select()函数适合于只检测一个socket描述符的情况,而poll()函数适合于大量socket描述符的情况;
nfds:nfds_t类型的参数,用于标记数组fds中的结构体元素的总数量;
timeout:是poll函数调用阻塞的时间,单位:毫秒;
 
struct pollfd {
int fd; /*文件描述符*/
short events; /* 等待的需要测试事件 */
short revents; /* 实际发生了的事件,也就是返回结果 */
};
与select()十分相似,当返回正值时,代表满足响应事件的文件描述符的个数,如果返回0则代表在规定时间内没有事件发生。如发现返回为负则应该立即查看 errno,因为这代表有错误发生。
如果没有事件发生,revents会被清空,所以你不必多此一举。
poll函数可用的测试值:
常量
说明
POLLIN
普通或优先级带数据可读
POLLRDNORM
普通数据可读
POLLRDBAND
优先级带数据可读
POLLPRI
高优先级数据可读
POLLOUT
普通数据可写
POLLWRNORM
普通数据可写
POLLWRBAND
优先级带数据可写
POLLERR
发生错误
POLLHUP
发生挂起
POLLNVAL
描述字不是一个打开的文件
例如fds[0].events = POLLIN; /*将测试条件设置成普通或优先级带数据可读*/
然后 int pollresult = poll(fds,xx,xx); //这样就可以监听fds里面文件描述符了,当满足特定条件就返回,并将结果保存在revents中。
 
posted @ 2018-07-21 16:34  yellow_three_gold  阅读(694)  评论(0编辑  收藏  举报