字符驱动poll函数与select()函数的交互

字符驱动poll函数与select()函数的交互

在字符驱动中,我们经常要实现poll()的功能,具体实现在注册到file_operations 的函数中,举个例子


static unsigned int xxx_poll(struct file *file, poll_table *wait)
{
         poll_wait(file, &mp_chrdev_wait, wait);
         if (rcu_access_index(mplog.next))
                 return POLLIN | POLLRDNORM;
  
         return 0;
}

我们必须在这个函数中返回POLLIN、POLLOUT等状态,从而我们可以在用户态下使用FD_ISSET()判断数据是否到来。而其中void poll_wait(struct file *filp, wait_queue_head_t *queue, poll_table *wait);它的作用就是把当前进程添加到wait参数指定的等待列表(poll_table)中。需要注意的是这个函数是不会引起阻塞的。

__这里我们实现创建了一个mp_chrdev_wait的等待队列,它会把这个轮训进程放入一个等待队列中,然后这个进程会睡眠(表现在select()上就是阻塞)。当某个条件满足时,唤醒这个等待队列,也就是唤醒了轮训进程,也就是内核通知应用程序(应用程序的select函数会感知),这个时候mask返回值中有数据。然后就会接着select操作。__所以我们要在恰当的位置wake_up_interruptible(&mp_chrdev_wait)

在用户空间中的代码,我们需要使用select()轮训在这个设备上:


         int register_fd, ret;
         fd_set rds;
  
         register_fd = open(CONFIG_PATH, O_RDWR);
         if (register_fd less 0)
                err("opening of /dev/mplog");
 
         FD_ZERO(&rds);
         FD_SET(register_fd,&rds);
  
  
         while (1) {
                 /*
                  * Proceed with the rest of the daemon.
                 */
                memset(temp, 0, MP_LOG_LEN * sizeof(struct mp));
  
 
                 ret = select(register_fd+1,&rds,NULL,NULL,NULL);
                 if(ret less 0 )
                 {
                         close(register_fd);
                         err("select error!");
                 }
                 if(FD_ISSET(register_fd,&rds))
                        read(register_fd, temp, MP_LOG_LEN * sizeof(struct mp));
.... 
         }