epoll之一:epoll的原理

之前 我寫過一篇博客IO複用之select poll epoll 函數,大概介紹了一下epoll和select,poll的一些區別,接下來要 從原理剖析epoll的強大的原因

select和poll的工作機制

在某一時刻,進程收集有事件連接時,大部分的連接是沒有發生事件,但是 select和poll的工作機制,在 每次收集事件 的 時候,都把全部 的 連接的 套接字傳給操作系統(這首先就是用戶態內存到內核態內存的大量複製),同時由操作系統內核尋找這些連接上有沒有事件發生,將是一個很耗時的事情,所以 select和epoll只能處理幾千個併發連接(也受到操作系統文件描述符的限制)。

epoll的工作機制

首先epoll在Linux內核中申請了一個 簡易的文件系統,將一個 poll或select調用分成了3個部分:

  • 調用epoll_create建立1個epoll對象(在epoll文件系統中 給這個 句柄 分配資源)
  • 調用epoll_ctlepoll添加大量的連接套接字
  • 調用epoll_wait收集發生事件 的連接。

這樣,只需要在進程啓動的時候建立 1個epoll對象,並在需要的 時候向他添加或刪除連接 就可以,在實際收集事件時,epoll_wait的效率會非常的高,調用epoll_wait時並沒有向它傳遞全部的 連接,內核也不需要遍歷全部的 連接

詳解epoll_create方法

當一個進程調用epoll_create方法時,Linux內核會創建 一個eventpoll結構體,這個 結構體中有兩個 成員與epoll使用 的 方式密切相關

struct eventpoll{
 /*紅黑樹的根節點,這顆樹存儲着所有添加到epoll的事件,也就是這個epoll監控 的事件*/
 struct rb_root rbr;

 // 雙向鏈表rallist保存着將要 通過 epoll_wait返回給用戶的、滿足條件的事件 
 struct list_head rdllist;
 ...
}

每一個epoll對象都有一個獨立的eventpoll結構體,這個 結構體會在內核 空間創造獨立 的內存,用於存儲使用epoll_ctl方法向epoll對象添加 進來的事件。這些事件都會 掛在rbr紅黑樹中,這樣重複添加的事件就 可以通過紅黑樹而高效地識別出來。所有添加到epoll的事件都會與設備(如網卡)驅動程序建立 回調關係,也就是說,相應的事件發生時會調用這裏的回調方法。這個 回調的方法 在內核叫做ep_poll_callback,它會把這樣的事件放在上面的rdllist雙向鏈表中。

在 epoll中,對於每個 事件 都會 建立一個epitem結構體

struct epitem
{
    //紅黑樹節點
    struct rb_node rbn;
    //雙鏈 表節點
    struct list_head rdllink;
    //事件 句柄信息 
    struct epoll_filefd ffd;
    //指向其所屬的eventpoll對象
    struct  eventpoll *ep;
    // 期待 的事件類型
    struct epoll_event  event;
}

這裏 包含 每一個事件對應着的信息,當 調用epoll_wait檢查是否有 發生事件的連接時,只是檢查eventpoll對象中的rdllist雙向鏈表是否有epitem元素而已,如果rdllist鏈表不爲空,則把這裏的事件複製到用戶態 的 內存中,同時將事件數量返回給用戶。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章