epoll分析

来源:互联网 发布:淘宝优惠软件是真的吗 编辑:程序博客网 时间:2024/05/16 09:17

ep_insert这个函数开始分析 里面调用了

init_poll_funcptr(&epq.pt,ep_ptable_queue_proc);

init_poll_funcptr这个函数就一句

static inline voidinit_poll_funcptr(poll_table *pt, poll_queue_proc qproc)

{

         pt->qproc= qproc;

}

也就是将ep_ptable_queue_proc这个函数指针赋值给(&epq.pt)->qproc

revents = tfile->f_op->poll(tfile,&epq.pt);将调用pipe_poll(以pipe为例)

pipe_poll(struct file *filp, poll_table*wait)里面有poll_wait(filp, &pipe->wait, wait);这一句

poll_wait里面

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

}

参数p就是之前epoll里的&epq.pt,p->qproc也就是ep_ptable_queue_proc

第二个参数wait_address就是&pipe->wait,这个pipe的wait是什么呢我们可以看一下

struct pipe_inode_info *alloc_pipe_info(struct inode *inode)

{

         structpipe_inode_info *pipe;

 

         pipe= kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL);

         if(pipe) {

                   init_waitqueue_head(&pipe->wait);

                   pipe->r_counter= pipe->w_counter = 1;

                   pipe->inode= inode;

         }

 

         returnpipe;

}

init_waitqueue_head该函数初始化一个已经存在的等待队列头,它将整个队列设置为"未上锁"状态,并将链表指针prev和next指向它自身。也就是初始化&pipe->wait这个等待队列头的指针。

我们再回过头来看#1这个地方,也就变成了ep_ptable_queue_proc(filp, &pipe->wait, &epq.pt)

 

static void ep_ptable_queue_proc(structfile *file, wait_queue_head_t *whead,

                                      poll_table *pt)

{

         structepitem *epi = ep_item_from_epqueue(pt);

         structeppoll_entry *pwq;

 

         if(epi->nwait >= 0 && (pwq = kmem_cache_alloc(pwq_cache,GFP_KERNEL))) {

                   init_waitqueue_func_entry(&pwq->wait,ep_poll_callback);

                   pwq->whead= whead;

                   pwq->base= epi;

                   add_wait_queue(whead,&pwq->wait);

                   list_add_tail(&pwq->llink,&epi->pwqlist);

                   epi->nwait++;

         }else {

                   /*We have to signal that an error occurred */

                   epi->nwait= -1;

         }

}

struct epitem *epi =ep_item_from_epqueue(pt);是通过&epq.pt找到其从属的epitem对象。

pwq = kmem_cache_alloc(pwq_cache,GFP_KERNEL)); alloc一个

/* Wait structure used by the poll hooks */

struct eppoll_entry {

         /*List header used to link this structure to the "struct epitem" */

         structlist_head llink;

 

         /*The "base" pointer is set to the container "struct epitem"*/

         void*base;

 

         /*

          * Wait queue item that will be linked to thetarget file wait

          * queue head.

          */

         wait_queue_twait;

 

         /*The wait queue head that linked the "wait" wait queue item */

         wait_queue_head_t*whead;

};

init_waitqueue_func_entry(&pwq->wait, ep_poll_callback);将回调函数ep_poll_callback注册给了&pwq->wait(等待项,这个等待项会被连入到pipe等待队列中)的func项,当

&pipe->wait 被赋值给了pwq->whead

add_wait_queue(whead, &pwq->wait);将等待项连接到&pipe->wait等待队列头中

 

至此pipe_poll完成了

pipe_write的时候会wake_up_interruptible_sync(&pipe->wait);调用关系如下

wake_up_interruptible_sync(&pipe->wait);

->__wake_up_sync((x),TASK_INTERRUPTIBLE,1)

         ->__wake_up_sync(wait_queue_head_t*q, unsigned int mode, int nr_exclusive)

                   ->__wake_up_common(q,mode, nr_exclusive, sync, NULL);

static void__wake_up_common(wait_queue_head_t *q, unsigned int mode,

                                 int nr_exclusive, int sync, void *key)

{

         wait_queue_t *curr, *next;

         list_for_each_entry_safe(curr, next,&q->task_list, task_list) {

                   unsigned flags =curr->flags;

 

                   if (curr->func(curr, mode,sync, key) &&

                                     (flags& WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)

                            break;

         }

}

这个curr->func就是之前的&pwq->wait 的func也就是ep_poll_callback,他依次调用pipe等待队列上的各个等待项对应的callback函数

回调函数在调用时会再执行pipe_poll函数,来明确是不是指定的关注事件发生,若成立则将 epitem插入到eventpoll中的rdlist,并激活在epoll fdwait的进程,并将事件回传至用户态.这样就能实现对目标fd的事件监听.to be continued…

原创粉丝点击