eventepoll3


지금부터 이 걸 보 겠 습 니 다. 여러분 이 가장 막 아야 한다 고 생각 하 는 함수.  , 지금부터 시작 하 겠 습 니 다. 소스 코드 를 통 해 분석 해 보 겠 습 니 다.
모두 epoll 흐릿 한 곳
 
SYSCALL_DEFINE4(epoll_wait, int, epfd, struct epoll_event __user *, events,
int, maxevents, int, timeout)
{
int error;
struct file *file;
struct eventpoll *ep;
 
/* 이것 괜찮아요? 걱정 하지 마. , 너 는 영원히 이런 다 중 접속 이 없 을 것 이다. , 그때 까지 는 epoll 붕괴 가 아니 었 어 요. 니 시스템 이 야. 다른 데 가 먼저 무 너 져. */
if (maxevents <= 0 || maxevents > EP_MAX_EVENTS)
return -EINVAL;
 
/* 입력 주소 공간의 유효성 검사 */
if (!access_ok(VERIFY_WRITE, events, maxevents * sizeof(struct epoll_event))) {
error = -EFAULT;
goto error_return;
}
 
/* 얻다 들 어 오 는 file fd 대응 하 는 struct file  구조 * /
error = -EBADF;
file = fget(epfd);
if (!file)
goto error_return;
 
/*
 * 검사 하 다. file fd 의 file operations 구조 가 epoll 인지 아 닌 지 라 고 말 했다.  anon inode getfd 기억 나 요. 그래?
 */
error = -EINVAL;
if (!is_file_epoll(file))
goto error_fput;
 
/* 보존했어 "전역" struct eventpoll 구조 가 짜이다 */
ep = file->private_data;
 
/* Time to fish for events ... */
error = ep_poll(ep, events, maxevents, timeout);
 
error_fput:
fput(file);
error_return:
 
return error;
}
 
자, 이제 보 자. ep_poll(ep, events, maxevents, timeout);  이 친절 한 함수 말 이 야.
 
 
 
 
static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
   int maxevents, long timeout)
{
int res, eavail;
unsigned long flags;
long jtimeout;
wait_queue_t wait;
 
/*-1 사실 영구 수면 이에 요.  */
jtimeout = (timeout < 0 || timeout >= EP_MAX_MSTIMEO) ?
MAX_SCHEDULE_TIMEOUT : (timeout * HZ + 999) / 1000;
 
retry:
/ * 여 기 는 전역 적 인 spin 을 사 용 했 습 니 다. 두루 다니다 */
spin_lock_irqsave(&ep->lock, flags);
 
res = 0;
/ * 아직 준비 되 지 않 은 이벤트 * /
if (list_empty(&ep->rdllist)) {
/*
 * We don't have any available event to return to the caller.
 * We need to sleep here, and we will be wake up by
 * ep_poll_callback() when events will become available.
 */
/ * 초기 화 * /
init_waitqueue_entry(&wait, current);
wait.flags |= WQ_FLAG_EXCLUSIVE;
__add_wait_queue(&ep->wq, &wait);
 
for (;;) {
/ * 받 아들 이 기 를 바 랍 니 다. ep_poll_callback() 단말  무슨 일이 일 어 났 는 지 알려 주세요 * /
set_current_state(TASK_INTERRUPTIBLE);
/ * 잠 자기 전에 대기 열 에 물건 이 있 는 지 확인 하고,  기다 릴 시간 이 없 거나. 바로 뛰 기 * /
if (!list_empty(&ep->rdllist) || !jtimeout)
break;
/ * 현재 스 레 드 를 연결 상태 ,등 사건 발생 * /
if (signal_pending(current)) {
res = -EINTR;
break;
}
/ * 인 터 럽 트 를 풀 고 선택 한 자 물 쇠 를 복원 합 니 다. 커 널 스케줄 을 받 아들 이 고 남 은 시간 을 계산 합 니 다 * /
spin_unlock_irqrestore(&ep->lock, flags);
jtimeout = schedule_timeout(jtimeout);
/ * 돌아 와 서 다시 잠 그 고 기 다 려 * /
spin_lock_irqsave(&ep->lock, flags);
}
/ * 드디어 상황 이 발생 했 습 니 다. ,자신 이 대기 열 에서 떼 어 내기 * /
__remove_wait_queue(&ep->wq, &wait);
 
set_current_state(TASK_RUNNING);
/ * 과연 맞 는 지 뒤 돌아 보 자 대기 열 에 이벤트 가 있 습 니 다. */
}
/* 작가 님 조심 하 시 네요. ...자 물 쇠 를 돌려 주기 전에 TMD 를 보 세 요. 도대체 준 비 된 사건 이 효과 가 있 는 지 없 는 지 */
eavail = !list_empty(&ep->rdllist) || ep->ovflist != EP_UNACTIVE_PTR;
spin_unlock_irqrestore(&ep->lock, flags);
/ * 기회 가 없어 요... * /
 
/ * 사용자 공간 으로 돌아 가 는 마지막 자체 검 측, */
if (!res && eavail &&
    !(res = ep_send_events(ep, events, maxevents)) && jtimeout)
goto retry;
 
return res;
}
 
 
 
이제 이 걸 보 겠 습 니 다. ep_send_events 도대체 뭘 했 길 래
 
/ * 하 나 를 초기 화 하 는 것 입 니 다. 프 라이 비트 struct ep_send_events_data, 기억 epsend_events_proc 
* 이 리 셋 방법 에는 그것 이 필요 합 니 다 * /
 
static int ep_send_events(struct eventpoll *ep,
  struct epoll_event __user *events, int maxevents)
{
struct ep_send_events_data esed;
 
esed.maxevents = maxevents;
esed.events = events;
 
return ep_scan_ready_list(ep, ep_send_events_proc, &esed);
 
}
 
/ * 저자 가 덧 붙 인 주석 은 이 함수 의 목적 은
* 스캐닝 준비 링크 (rdlist)  동시에 호출 하 다. f_op - > poll () 함수,  O (n) 의 복잡 도 내 에서 * /
 
static int ep_scan_ready_list(struct eventpoll *ep,
      int (*sproc)(struct eventpoll *,
   struct list_head *, void *),
      void *priv)
{
int error, pwake = 0;
unsigned long flags;
struct epitem *epi, *nepi;
LIST_HEAD(txlist);
 
/*
 *             eventpoll_release_file() and epoll_ctl().   
 */
mutex_lock(&ep->mtx);
 
/*
 * Steal the ready list, and re-init the original one to the
 * empty list. Also, set ep->ovflist to NULL so that events
 * happening while looping w/out locks, are not lost. We cannot
 * have the poll callback to queue directly on ep->rdllist,
 * because we want the "sproc" callback to be able to do it
 * in a lockless way.
 */
spin_lock_irqsave(&ep->lock, flags);
/*  ep->rdlist     txlist */
list_splice_init(&ep->rdllist, &txlist);
/*   ep->ovflist   ,         */
ep->ovflist = NULL;
spin_unlock_irqrestore(&ep->lock, flags);
 
/*      ep_send_events_proc ,         ,                 
 */
error = (*sproc)(ep, &txlist, priv);
 
spin_lock_irqsave(&ep->lock, flags);
/*
 * During the time we spent inside the "sproc" callback, some
 * other events might have been queued by the poll callback.
 * We re-insert them inside the main ready-list here.
 */
/*                                  ovflist   */
for (nepi = ep->ovflist; (epi = nepi) != NULL;
     nepi = epi->next, epi->next = EP_UNACTIVE_PTR) {
/*          file fd  ,         */
if (!ep_is_linked(&epi->rdllink))
list_add_tail(&epi->rdllink, &ep->rdllist);
}
/*     */
ep->ovflist = EP_UNACTIVE_PTR;
 
/*     */
list_splice(&txlist, &ep->rdllist);
 
if (!list_empty(&ep->rdllist)) {
/*   eventpoll (  )   poll (  )      <   ,           >*  /
if (waitqueue_active(&ep->wq))
wake_up_locked(&ep->wq);
if (waitqueue_active(&ep->poll_wait))
pwake++;
}
spin_unlock_irqrestore(&ep->lock, flags);
 
mutex_unlock(&ep->mtx);
 
/* We have to call this outside the lock */
if (pwake)
ep_poll_safewake(&ep->poll_wait);
 
return error;
}
 

 
 
 
 
static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head,
       void *priv)

{
struct ep_send_events_data *esed = priv;
int eventcnt;
unsigned int revents;
struct epitem *epi;
struct epoll_event __user *uevent;
 

/*            ,                         */
/*uevent       epoll_wait           struct epoll_event    
*head         rdlist    txlist,      eventcnt              */
for (eventcnt = 0, uevent = esed->events;
     !list_empty(head) && eventcnt < esed->maxevents;) {
/*             struct epitem*/
epi = list_first_entry(head, struct epitem, rdllink);
/*               */
list_del_init(&epi->rdllink);
/*      file fd      poll ,         (       )*/
revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL) &
epi->event.events;
 
/*               */
if (revents) {
if (__put_user(revents, &uevent->events) ||
    __put_user(epi->event.data, &uevent->data)) {
list_add(&epi->rdllink, head);
return eventcnt ? eventcnt : -EFAULT;
}
eventcnt++;
uevent++;
/*         */

if (epi->event.events & EPOLLONESHOT)
epi->event.events &= EP_PRIVATE_BITS;
/*     :            ,     file fd                 *    */
else if (!(epi->event.events & EPOLLET)) {
list_add_tail(&epi->rdllink, &ep->rdllist);

}
}

좋은 웹페이지 즐겨찾기