eventepoll2


다음 에 보 겠 습 니 다. epoll 조작 함수  epoll_ctl 
 
SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
struct epoll_event __user *, event)
{
int error;
struct file *file, *tfile;
struct eventpoll *ep;
struct epitem *epi;
struct epoll_event epds;

error = -EFAULT;
   /*             ,           struct epoll_event         */
if (ep_op_has_event(op) &&
    copy_from_user(&epds, event, sizeof(struct epoll_event)))
goto error_return;

/* Get the "struct file *" for the eventpoll file */
error = -EBADF;
/*      epfd    epoll          fdtable       : rcu          */
file = fget(epfd);
if (!file)
goto error_return;
/*  ,             file fd      */

tfile = fget(fd);
if (!tfile)
goto error_fput;

/* The target file descriptor must support poll */
error = -EPERM;
/*            poll  ,    epoll    EnhancePoll 。。 */
if (!tfile->f_op || !tfile->f_op->poll)
goto error_tgt_fput;

/*
 * We have to check that the file structure underneath the file descriptor
 * the user passed to us _is_ an eventpoll file. And also we do not permit
 * adding an epoll file descriptor inside itself.
 */
/*        ,         。      , 11  3   kernel              bug ,       */
error = -EINVAL;
if (file == tfile || !is_file_epoll(file))
goto error_tgt_fput;

/*
 *   ,          epoll_event
 */
ep = file->private_data;

    /*      ,     !*/
mutex_lock(&ep->mtx);

/*            (  ep->rbr.rb_node        )  RBTree          fd           struct epitem. 
 */
epi = ep_find(ep, tfile, fd);

error = -EINVAL;
switch (op) {
case EPOLL_CTL_ADD:
if (!epi) {
/*      ,                  POLLERR | POLLHUP  */

epds.events |= POLLERR | POLLHUP;/
/*       : struct epitem. ,      。            */
error = ep_insert(ep, &epds, tfile, fd);
} else
error = -EEXIST;
break;
case EPOLL_CTL_DEL:
if (epi)
error = ep_remove(ep, epi);
else
error = -ENOENT;
break;
case EPOLL_CTL_MOD:
if (epi) {
epds.events |= POLLERR | POLLHUP;
error = ep_modify(ep, epi, &epds);
} else
error = -ENOENT;
break;
}
mutex_unlock(&ep->mtx);
/*     poll               struct file    2 */
error_tgt_fput:
fput(tfile);
/*       eventpoll , fput                  struct file      ,   file_table        ,          
error_fput:dany
fput(file);
error_return:

return error;
}
 
자, 다음은 재 미 있 는 것 을 보 겠 습 니 다. ep_insert
 
 
보고 있다 epinert 이전 ,저희 가 일단 추억 을 떠 올 려 보도 록 하 겠 습 니 다. poll 
 
우 리 는 모두 Liux 에 있다 는 것 을 안다. VFS 모델 struct file_operations 하나 있다 위대 하 다 poll 함수 포인터
unsigned int (*poll) (struct file *, struct poll_table_struct *);
 
예 를 들다 , 그냥 흔 한 걸 로.  scsi 그래.
 
 
static unsigned int tgt_poll(struct file * file, struct poll_table_struct *wait)
{
//....
/*tgt_poll_wait 이 장치 의 대기 열 입 니 다.  일단 알 아야 돼. poll_wait 막 히 지 않 습 니 다. , 
* 그리고 사실은 호출 하 러 가 는 거 예요. struct poll_table  등록 qproc 함수 포인터 * /
 
poll_wait(file, &tgt_poll_wait, wait);
 
spin_lock_irqsave(&ring->tr_lock, flags);
 
idx = ring->tr_idx ? ring->tr_idx - 1 : TGT_MAX_EVENTS - 1;
ev = tgt_head_event(ring, idx);
if (ev - > hdr. status) / * 상부 에 사용 할 표지 위 치 를 설정 합 니 다 * /
mask |= POLLIN | POLLRDNORM;
 
spin_unlock_irqrestore(&ring->tr_lock, flags);
 
return mask;
}
사실 poll 딱 한 가지 일 을 했다. ,현재 file 로 돌아 가기 fd 상태 .  select 비교적 멍청 하 다. 그 는 집합 안의 모든 자 리 를 한 번 옮 겨 다 녔 다. __FD SETSIZE 개) ACE 몇 가지 해결 방법 을 제 공 했 는데 그 중에서 가장 좋 은 것 은 ACE Select Reactor 입 니 다.  이 이후 의 분석 은 논문 한 편 을 인용 한 것 같 습 니 다. (ACE 사실은 많은 논문 의 실현 이다.)
 
좋다 다음은 재 미 있 는 ep insert 를 시작 하 겠 습 니 다. 
static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
     struct file *tfile, int fd)
{
int error, revents, pwake = 0;
unsigned long flags;
struct epitem *epi;
struct ep_pqueue epq;
    /*     epoll fd                   */
if (unlikely(atomic_read(&ep->user->epoll_watches) >=
     max_user_watches))
return -ENOSPC;
   /*       struct epitem       ,       file fd*/
if (!(epi = kmem_cache_alloc(epi_cache, GFP_KERNEL)))
return -ENOMEM;

/*           ;    struct file    epoll     ;        */
INIT_LIST_HEAD(&epi->rdllink);
INIT_LIST_HEAD(&epi->fllink);
INIT_LIST_HEAD(&epi->pwqlist);
epi->ep = ep;/*      */
    /*    struct epoll_filefd       RBTree   */
ep_set_ffd(&epi->ffd, tfile, fd);
    /*        epoll_event     */
epi->event = *event;
epi->nwait = 0;
epi->next = EP_UNACTIVE_PTR;

/* Initialize the poll table using the queue callback */
epq.epi = epi;

/*    poll        ,        poll_wait            ,
*ep_ptable_queue_proc        ,       */
init_poll_funcptr(&epq.pt, ep_ptable_queue_proc);

/*
 * Attach the item to the poll hooks and get current event bits.
 * We can safely use the file* here because its usage count has
 * been increased by the caller of this function. Note that after
 * this operation completes, the poll callback can start hitting
 * the new item.
 */
/*             :                  ,  poll_wait         ,          , */
revents = tfile->f_op->poll(tfile, &epq.pt);

/*      poll_wait             ,        */
error = -ENOMEM;
if (epi->nwait < 0)
goto error_unregister;

/*    file fd    ,   struct epitm     file    epoll       */
spin_lock(&tfile->f_lock);
list_add_tail(&epi->fllink, &tfile->f_ep_links);
spin_unlock(&tfile->f_lock);

/*   RBTree */
ep_rbtree_insert(ep, epi);

/* We have to drop the new item inside our item list to keep track of it */
spin_lock_irqsave(&ep->lock, flags);
/*     stuct file              ,   epi        ready   */
/* If the file is already "ready" we drop it inside the ready list */
if ((revents & event->events) && !ep_is_linked(&epi->rdllink)) {
/*     "  "  eventpoll   ->   file fd  */
list_add_tail(&epi->rdllink, &ep->rdllist);
/*   eventpoll (  )   poll (  )                  
*                        ,   ep_insert ep_modify scan_ready_list */

if (waitqueue_active(&ep->wq))
wake_up_locked(&ep->wq);
if (waitqueue_active(&ep->poll_wait))
pwake++;
}

spin_unlock_irqrestore(&ep->lock, flags);

atomic_inc(&ep->user->epoll_watches);

/*    (       )     poll    */
if (pwake)
ep_poll_safewake(&ep->poll_wait);

return 0;
/*        */

error_unregister:
ep_unregister_pollwait(ep, epi);
spin_lock_irqsave(&ep->lock, flags);
if (ep_is_linked(&epi->rdllink))
list_del_init(&epi->rdllink);
spin_unlock_irqrestore(&ep->lock, flags);

kmem_cache_free(epi_cache, epi);

return error;
}



    ,     
init_poll_funcptr(&epq.pt, ep_ptable_queue_proc);
    ep_ptable_queue_proc      poll_wait      
                   
        epoll        file fd          entry   ,
         
struct eppoll_entry {
/*    struct epitem      poll       */
struct list_head llink;

/*            ... */
struct epitem *base;

/*              */
wait_queue_t wait;

/*           */
wait_queue_head_t *whead;
};

static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead,
 poll_table *pt)
{
/*       poll_table   ep_pqueue    ,           ep_pqueue                  : struct epitem *epi;*/
struct epitem *epi = ep_item_from_epqueue(pt);
/*            eppoll_entry     ,                    */
struct eppoll_entry *pwq;
/*     slab          eppoll_entry    */
if (epi->nwait >= 0 && (pwq = kmem_cache_alloc(pwq_cache, GFP_KERNEL))) {
/*   struct eppoll_entry       ,         ep_poll_callback */
init_waitqueue_func_entry(&pwq->wait, ep_poll_callback);
pwq->whead = whead;

pwq->base = epi;
/*             whead      */
add_wait_queue(whead, &pwq->wait);

/*     struct eppoll_entry  pwq       struct epitem epi  pwqlist      , 
       entry   */
list_add_tail(&pwq->llink, &epi->pwqlist);
epi->nwait++;
} else {
/* We have to signal that an error occurred */
epi->nwait = -1;
}
}
 
 

좋은 웹페이지 즐겨찾기