2012-10-15 68 views
1

的epoll的手冊頁:epoll的與邊沿觸發事件

http://linux.die.net/man/7/epoll

有邊緣的樣本代碼觸發像follwoing:

for (;;) { 
    nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1); 
    if (nfds == -1) { 
     perror("epoll_pwait"); 
     exit(EXIT_FAILURE); 
    } 

    for (n = 0; n < nfds; ++n) { 
     if (events[n].data.fd == listen_sock) { 
      conn_sock = accept(listen_sock, 
         (struct sockaddr *) &local, &addrlen); 
      if (conn_sock == -1) { 
       perror("accept"); 
       exit(EXIT_FAILURE); 
      } 
      setnonblocking(conn_sock); 
      ev.events = EPOLLIN | EPOLLET; 
      ev.data.fd = conn_sock; 
      if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, 
        &ev) == -1) { 
       perror("epoll_ctl: conn_sock"); 
       exit(EXIT_FAILURE); 
      } 
     } else { 
      do_use_fd(events[n].data.fd); 
     } 
    } 
} 

在功能do_use_fd,我呼籲在未封閉的recv while循環直到EAGAIN,示例代碼工作正常 , 我有一個關於這個示例代碼的問題,現在假設我有50個套接字客戶端連接,突然有10個客戶端同時寫入數據,所以epoll_wait()將返回10,然後去爲循環:

for (n = 0; n < nfds; ++n) 

它會調用do_use_fd(事件[N] .data.fd);對於這10個客戶端,假設n = 5完成,並且n = 6尚未完成,突然事件n = 3的文件描述已經接收到新數據,在所有10個事件完成並返回到epoll_wait後,I得到事件告訴我有一個客戶有新的數據要讀?或者我會錯過它,因爲事件發生時,代碼不在epoll_wait!

回答

5

只要您閱讀,直到您收到EAGAIN錯誤,您將在下次打電話epoll_wait時收到活動。

只有在空和非空(或全部和非全部爲EPOLLOUT)之間發生變化時纔會觸發事件,但該狀態會一直保留到事件通過epoll_wait發送。

在一個有點相關的注意事項:如果您註冊了EPOLLINEPOLLOUT事件,並假設你從來沒有填滿發送緩衝區,你仍然可以獲得EPOLLOUT標誌由epoll_wait每個EPOLLIN觸發時返回的事件設置 - 見https://lkml.org/lkml/2011/11/17/234爲更詳細的解釋。

最後,邊緣觸發模式的確切行爲實際上取決於所使用的套接字類型,並沒有真正記錄在任何地方。我前一段時間做了一些測試,並在這裏記錄了我的發現:http://cmeerw.org/blog/753.html#753 - 簡而言之,對於數據報套接字,您可能會獲得比您預期的更多事件。

+0

...和'eventfd's和'超出你的想象timerfd's你少。 – Damon

+0

謝謝cmeerw,你幫了很多忙! – barfatchen

1

當您使用邊緣下epoll的觸發,看了一些東西,可以喜歡這個

int n = -1; 
while (1) 
{ 
    n = recv(fd, iobuf, init_buff_size, MSG_DONTWAIT); 
    if (n > 0) 
    { 
     LOG(glogfd, LOG_TRACE, "fd[%d] recv len %d\n", fd, n); 
     mybuff_setdata(&(curcon->recv_buff), iobuf, n); // this is my func 
     if (n == init_buff_size) 
     { 
      LOG(glogfd, LOG_DEBUG, "fd[%d] need recv nextloop %d\n", fd, n); 
      continue; 
     } 
     break; 
    } 
    if (n == 0) 
    { 
     LOG(glogfd, LOG_ERROR, "fd[%d] close %s:%d!\n", fd, ID, LN); 
     return do_close(fd); 
    } 
    if (errno == EINTR) 
    { 
     LOG(glogfd, LOG_TRACE, "fd[%d] need recv again!\n", fd); 
     continue; 
    } 
    else if (errno == EAGAIN) 
    { 
     LOG(glogfd, LOG_TRACE, "fd[%d] need recv next!\n", fd); 
     modify_fd_event(fd, EPOLLIN); // this is the KEY, add read again 
     break; 
    } 
    else 
    { 
     LOG(glogfd, LOG_ERROR, "fd[%d] close %s:%d!\n", fd, ID, LN); 
     return do_close(fd); 
    } 
}