Chinaunix首页 | 论坛 | 博客
  • 博客访问: 477520
  • 博文数量: 72
  • 博客积分: 1851
  • 博客等级: 上尉
  • 技术积分: 1464
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-16 17:50
文章分类

全部博文(72)

文章存档

2013年(1)

2012年(17)

2011年(51)

2010年(3)

分类: LINUX

2011-08-07 11:18:36

上面的原型是epollfd所维护的主结构,下面是每一个具体的fd结构.

以后每一个fd加入到epoll中,就会创建一个struct epitem结构,并插入至红黑树中。

接着是epoll_ctl函数原型:

  1. asmlinkage long sys_epoll_ctl(int epfd,int op,int fd,struct epoll_event __user *event)
  2. {
  3.     int error;
  4.     struct file *file,*tfile;
  5.     struct eventpoll *ep;
  6.     struct epoll_event epds;
  7.     
  8.     error = -FAULT;
  9.     //判断行参的合法性
  10.     if(ep_op_has_event(op) && copy_from_user(&epds,event,sizeof(struct         epoll_event)))
  11.             goto error_return;

  12.     error = -EBADF;
  13.     file = fget (epfd);
  14.     if(!file)    goto error_return;
  15.     
  16.     tfile = fget(fd);
  17.     if(!tfile)    goto error_fput;
  18.     
  19.     error = -EPERM;
  20.     //不能没有poll驱动
  21.     if(!tfile->f_op || !tfile->f_op->poll)
  22.         goto error_tgt_fput;
  23.         
  24.     error =-EINVAL;
  25.     //防止自己监听自己
  26.     if(file == tfile || !is_file_poll(file))
  27.         goto error_tgt_fput;
  28.     //在create时存入进去的,现在将其拿出来
  29.     ep = file->private->data;
  30.     
  31.     mutex_lock(&ep->mtx);
  32.     //防止重复添加
  33.     epi = epi_find(ep,tfile,fd);
  34.     error = -EINVAL;
  35.     
  36.     switch(op)
  37.     {
  38.         ….....
  39.         case EPOLL_CTL_ADD:
  40.             if(!epi)
  41.             {
  42.                 epds.events |=EPOLLERR | POLLHUP;
  43.                 error = ep_insert(ep,&epds,tfile,fd);
  44.             } else
  45.                 error = -EEXIST;
  46.             break;
  47.         …....
  48.     }
  49.     return error;    
  50. }

下面就是插入代码:

  1. static int ep_insert(struct eventpoll *ep,struct epoll_event *event,
  2.                 struct file *tfile,int fd)
  3. {
  4.     int error ,revents,pwake = 0;
  5.     unsigned long flags ;
  6.     struct epitem *epi;
  7.     /*
  8.     struct ep_queue{
  9.         poll_table pt;
  10.         struct epitem *epi;
  11.     }
  12.     */
  13.     struct ep_pqueue epq;
  14.     
  15.     //分配一个epitem结构体来保存每个加入的fd
  16.     error = -ENOMEM;
  17.     if(!(epi = kmem_cache_alloc(epi_cache,GFP_KERNEL)))
  18.         goto error_return;
  19.     //初始化该结构体
  20.     ep_rb_initnode(&epi->rbn);
  21.     INIT_LIST_HEAD(&epi->rdllink);
  22.     INIT_LIST_HEAD(&epi->fllink);
  23.     INIT_LIST_HEAD(&epi->pwqlist);
  24.     epi->ep = ep;
  25.     ep_set_ffd(&epi->ffd,tfile,fd);
  26.     epi->event = *event;
  27.     epi->nwait = 0;
  28.     epi->next = EP_UNACTIVE_PTR;
  29.     
  30.     epq.epi = epi;
  31.     //安装poll回调函数
  32.     init_poll_funcptr(&epq.pt,ep_ptable_queue_proc);
  33.     //调用poll函数来获取当前事件位,其实是利用它来调用注册函数ep_ptable_queue_proc
  34.     revents = tfile->f_op->poll(tfile,&epq.pt);

  35.     if(epi->nwait < 0)
  36.         goto error_unregister;

  37.     spin_lock(&tfile->f_ep_lock);
  38.     list_add_tail(&epi->fllink,&tfile->f_ep_lilnks);
  39.     spin_unlock(&tfile->f_ep_lock);
  40.     
  41.     ep_rbtree_insert(ep,epi);
  42.     spin_lock_irqsave(&ep->lock,flags);

  43.     if((revents & event->events) && !ep_is_linked(&epi->rdllink))
  44.     {
  45.         list_add_tail(&epi->rdllink,&ep->rdllist);
  46.     if(waitqueue_active(&ep->wq))
  47.         __wake_up_locked(&ep->wq,TAKS_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE);

  48.     if(waitqueue_active(&ep->poll_wait))
  49.         pwake++;
  50.     }
  51.     
  52.     spin_unlock_irqrestore(&ep->lock,flags);
  53.     if(pwake)
  54.         ep_poll_safewake(&psw,&ep->poll_wait);
  55.         …....
  56.     
  57.     return 0;
  58.     
  59.     …...
  60.     
  61. }


  1. //当poll醒来时就回调用该函数
  2. static void ep_ptable_queue_proc(struct file *file,wait_queue_head_t *whead,
  3.                 poll_table *pt)
  4. {
  5.     //从注册时的结构中struct ep_pqueue中获取项epi
  6.     struct epitem *epi = ep_item_from_epqueue(pt);
  7.     /*//epitem的私有项,通过pwqlist来进行链接
  8.      *struct eppoll_entry
  9.      {
  10.         struct list_head llink;
  11.         void *base;
  12.         wait_queue_t wait;
  13.         wait_queue_head_t *whead;
  14.      }
  15.     */
  16.     struct eppoll_entry *pwq;//struct epitem的私有项,为每一个fd保存内核poll

  17.     //为每一个等待的结构分配一项
  18.     if(epi->nwait >= 0 && (pwq = kmem_cache_alloc(pwq_cache,
  19.             GFP_KERNEL)))
  20.     {
  21.         //醒来就调用ep_poll_callback,这里才是真正意义上的poll醒来时的回调函数
  22.         init_waitqueue_func_entry(&pwq->wait,ep_poll_callback);
  23.         pwq->whead = whead;
  24.         pwq->base = epi;
  25.         //加入到该驱动的等待队列
  26.         add_wait_queue(whead,&pwq->wait);
  27.         //将等待链接也放入到epitem链表中去
  28.         list_add_tail(&pwq->llink,&epi->pwqlist);
  29.         epi->nwait ++;        
  30.     } else {
  31.         epi->nwait = -1;
  32.     }
  33. }
  34. //当poll监听的事件到达时,就会调用下面的函数
  35. static int ep_poll_callback(wait_queue_t *wait,unsigned mode,int sync,void *key)
  36. {
  37.     int pwake = 0;
  38.     unsigned long flags;
  39.     struct epitem *epi = ep_item_from_wait(wait);
  40.     struct eventpoll *ep = epi->ep;
  41.     
  42.     spin_lock_irqsave(&ep->lock,flags);
  43.     //判断注册的感兴趣事件
  44.     //#define EP_PRIVATE_BITS      (EPOLLONESHOT | EPOLLET)
  45.     //有非EPOLLONESHONT或EPOLLET事件
  46.     if(!(epi->event.events & ~EP_PRIVATE_BITS))
  47.             goto out_unlock;
  48.     
  49.     if(unlikely(ep->ovflist != EP_UNACTIVE_PTR))
  50.     {
  51.         if(epi->next == EP_UNACTIVE_PTR) {
  52.             epi->next = ep->ovflist;
  53.             ep->ovflist = epi;
  54.         }
  55.         goto out_unlock;
  56.     }

  57.     if(ep_is_linked(&epi->rdllink))
  58.         goto is_linked;
  59.     //关键是这一句,将该fd加入到epoll监听的就绪链表中
  60.     list_add_tail(&epi->rdllink,&ep->rdllist);
  61. is_linked:
  62.     if(waitqueue_active(&ep->wq))
  63.         __wake_up_locked(&ep->wq,TASK_UNINTERRUPTIBLE
  64.             | TASK_INTERRUPTIBLE);    
  65.     if(waitqueue_active(&ep->poll_wait))
  66.         pwake++;
  67. out_unlock:
  68.     spin_unlock_irqrestore(&ep->lock,flags);
  69.     
  70.     if(pwake)
  71.         ep_poll_safewake(&psw,&ep->poll_wait);
  72.     return 1;
  73. }

这里采用了两级回调方式,流程如下:

目前为止,整个数据结构就可以描述如下:


阅读(3600) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~