使用libevent strace 结果分析2 epoll 间的相互监听

 epoll作为一个文件既可以监视其他文件,也可以被其他epoll监视。这样就产生了一个监视的有向图

  ep_eventpoll_poll 文件的poll操作,也就是file->f_op->poll(). 调用该函数可以获取就绪文件的事件掩码,但是 epoll 文件只提供读就绪事件,并且读就绪事件是由非epoll文件的就绪事件决定的。也就是说当一个epoll文件被 select(2)/poll(2)/epoll(2) 监听时,必须该epoll已经监听了其他的非epoll文件(如eventfd), 在调用 该epoll file->f_op->poll() 时才可能返回可读的就绪事件。

static int ep_poll_readyevents_proc(void *priv, void *cookie, int call_nests)
{
    struct readyevents_arg *arg = priv;
        // 判断当前有没有事件触发
    return ep_scan_ready_list(arg->ep, ep_read_events_proc, NULL,
                  call_nests + 1, arg->locked);
}

static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait)
{
    int pollflags;
    struct eventpoll *ep = file->private_data;// 被监听的epoll
    struct readyevents_arg arg;

    /*
     * During ep_insert() we already hold the ep->mtx for the tfile.
     * Prevent re-aquisition.
     */
    arg.locked = wait && (wait->_qproc == ep_ptable_queue_proc);
    arg.ep = ep;

    /* Insert inside our poll wait queue */
    poll_wait(file, &ep->poll_wait, wait);//// 插入到wait_queue
    /*
     * Proceed to find out if wanted events are really available inside
     * the ready list. This need to be done under ep_call_nested()
     * supervision, since the call to f_op->poll() done on listed files
     * could re-enter here.、
// 扫描就绪的文件列表, 调用每个文件上的poll 检测是否真的就绪, // 然后复制到用户空间 // 文件列表中有可能有epoll文件, 调用poll的时候有可能会产生递归,
// 调用所以用ep_call_nested 包装一下, 防止死循环和过深的调用
*/// 判断是否有事件触发 pollflags = ep_call_nested(&poll_readywalk_ncalls, EP_MAX_NESTS, ep_poll_readyevents_proc, &arg, ep, current); return pollflags != -1 ? pollflags : 0; }

 ep_scan_ready_list以前分析过了,主要逻辑是在里面执行函数,ep_read_events_proc,我们看一下ep_read_events_proc是如何判断被监听的epoll中是否有事件触发的。

static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head,
                   void *priv)
{
    struct epitem *epi, *tmp;
    poll_table pt;

    init_poll_funcptr(&pt, NULL);
    // 遍历就绪队列
    list_for_each_entry_safe(epi, tmp, head, rdllink) {
        if (ep_item_poll(epi, &pt)) // ep_item_poll判断epitem中实现有事件触发
            return POLLIN | POLLRDNORM;
        else {
            /*
             * Item has been dropped into the ready list by the poll
             * callback, but it's not actually ready, as far as
             * caller requested events goes. We can remove it here.
             */// 这个事件虽然在就绪列表中, 
  // 但是实际上并没有就绪, 将他移除 
  // 这有可能是水平触发模式中没有将文件从就绪列表中移除 
// 也可能是事件插入到就绪列表后有其他的线程对文件进行了操作 
            __pm_relax(ep_wakeup_source(epi));
            list_del_init(&epi->rdllink);
        }
    }

    return 0;
}

这个传入的参数head 是啥呢? 就是 ep->rdllist 也就是被监听的epoll中的rdlist 也就是被监听的epoll 中监听其他的tcp fd的就绪rdlist

 

 

 

以下是epoll 先关数据结构以及相互调用:

 

 

2、

 

posted @ 2022-09-28 14:13  codestacklinuxer  阅读(21)  评论(0)    收藏  举报