zoukankan      html  css  js  c++  java
  • Linux poll机制

    1.用户空间调用(参考 poll(2) - Linux man page

     int poll(struct pollfd *fds, nfds_t nfds, int timeout);

    it waits for one of a set of file descriptors to become ready to perform I/O.

    The set of file descriptors to be monitored is specified in the fds argument, which is an array of structures of the following form:

    struct pollfd {
        int   fd;         /* file descriptor */
        short events;     /* requested events */
        short revents;    /* returned events */
    };

    关于timeout参数的说明:

      timeout>0,设置超时时间为timeout

      timeout=0,直接返回

      timeout<0,无限长超时时间

    返回值说明:

    On success, a positive number is returned; this is the number of structures which have nonzero revents fields (in other words, those descriptors with events or errors reported).

    A value of 0 indicates that the call timed out and no file descriptors were ready. On error, -1 is returned, and errno is set appropriately.

    2.内核调用

    asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds,long timeout_msecs)
        -->ret = do_sys_poll(ufds, nfds, &timeout);
            -->struct poll_wqueues table;
            -->poll_initwait(&table);
                -->init_poll_funcptr(&pwq->pt, __pollwait);
            -->把ufds指向的用户空间数据拷贝到内核空间,由poll_list结构体保存
            -->fdcount = do_poll(nfds, head, &table, timeout);
            for (;;) {
                -->set_current_state(TASK_INTERRUPTIBLE);
                -->for (walk = list; walk != NULL; walk = walk->next) //遍历poll_list结构中的pollfd结构
                    -->do_pollfd(pfd, pt)
                        -->if (file->f_op && file->f_op->poll) //驱动中的poll函数
                            --> void __pollwait(struct file *filp, wait_queue_head_t *wait_address,poll_table *p)
                                -->struct poll_table_entry *entry = poll_get_entry(p);
                                -->entry->filp = filp;
                                -->entry->wait_address = wait_address;
                                -->init_waitqueue_entry(&entry->wait, current);
                                -->add_wait_queue(wait_address, &entry->wait);//加入等待队列头
                        -->return mask;//返回设备是否可读写状态
                -->if (count || !*timeout || signal_pending(current))
                    break;//设备可读写,超时时间到,有信号中断三种情况都返回
                -->__timeout = schedule_timeout(__timeout);//进程调度,休眠
            }
                //唤醒后返回
                -->__set_current_state(TASK_RUNNING);
                -->return count;
            -->把poll_list结构体保存的pollfd.revents返回给用户空间的ufds数组
            -->poll_freewait(&table);//释放poll_table_entry中的等待队列

    3.相关结构体都在fs/select.c,include/linux/poll.h

    poll_wqueues是最关键的一个结构体,

     1 struct poll_wqueues {
     2     poll_table pt;
     3     struct poll_table_page * table;
     4     int error;
     5     int inline_index;
     6     struct poll_table_entry inline_entries[N_INLINE_POLL_ENTRIES];
     7 };
    

    poll_table结构体只包含一个函数指针,初始化时指向

    void __pollwait(struct file *filp, wait_queue_head_t *wait_address,poll_table *p)

    1 typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, struct poll_table_struct *);
    2 
    3 typedef struct poll_table_struct {
    4     poll_queue_proc qproc;
    5 } poll_table;

    poll_table_page就是包含poll_table_entry结构的链表,作用与inline_entries[N]相同,检测文件数少的时候用不到这个结构

    1 struct poll_table_page {
    2     struct poll_table_page * next;
    3     struct poll_table_entry * entry;
    4     struct poll_table_entry entries[0];
    5 };

    poll_table_entry包含文件指针,等待队列及等待队列头

    1 struct poll_table_entry {
    2     struct file * filp;
    3     wait_queue_t wait;
    4     wait_queue_head_t * wait_address;
    5 };

    4.操作

    poll_wqueues初始化

     1 static inline void init_poll_funcptr(poll_table *pt, poll_queue_proc qproc)
     2 {
     3     pt->qproc = qproc;
     4 }
     5 void poll_initwait(struct poll_wqueues *pwq)
     6 {
     7     init_poll_funcptr(&pwq->pt, __pollwait);
     8     pwq->error = 0;
     9     pwq->table = NULL;
    10     pwq->inline_index = 0;
    11 }

    那么poll_table结构中的函数什么时候使用及干什么呢?

    我们自己在驱动中的poll函数中会调用poll_wait()函数

     1 static unsigned forth_drv_poll(struct file *file, poll_table *wait)
     2 {
     3     unsigned int mask = 0;
     4     poll_wait(file, &button_waitq, wait); // 不会立即休眠
     5 
     6     if (ev_press)
     7         mask |= POLLIN | POLLRDNORM;
     8 
     9     return mask;
    10 }

    而poll_wait()函数最终会调用__pollwait()函数

    static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
    {
        if (p && wait_address)
            p->qproc(filp, wait_address, p);
    }
     1 /* Add a new entry */
     2 static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
     3                 poll_table *p)
     4 {
     5     struct poll_table_entry *entry = poll_get_entry(p);
     6     if (!entry)
     7         return;
     8     get_file(filp);
     9     entry->filp = filp;
    10     entry->wait_address = wait_address; //即forth_drv_poll中传入的button_waitq等待队列头
    11     init_waitqueue_entry(&entry->wait, current);
    12     add_wait_queue(wait_address, &entry->wait);
    13 }
  • 相关阅读:
    Ubuntu下建立Android开发环境
    c#值类型和引用类型
    Jude Begin
    Eclipse C/C++ development environment creation
    C# var usage from MSDN
    SubSonic应用_Collection
    C#2.0中委托与匿名委托引
    sql语句的执行步骤——zhuan
    图˙谱˙马尔科夫过程·聚类结构 (转载,原始出处不详)
    Hadoop集群新增节点实现方案
  • 原文地址:https://www.cnblogs.com/yangjiguang/p/7622780.html
Copyright © 2011-2022 走看看