epoll監聽檔案 Epoll的簡介及原理

2021-10-14 12:31:27 字數 2974 閱讀 5970

epoll 全稱 eventpoll,是 linux 核心實現io多路復用(io multiplexing)的乙個實現。io多路復用的意思是在乙個操作裡同時監聽多個輸入輸出源,在其中乙個或多個輸入輸出源可用的時候返回,然後對其的進行讀寫操作。

在 linux 中,和 epoll 類似的有 select 和 poll。網上很多文章著重關注 epoll 與 select 的區別,或者關注 epoll 中 level-triggered 和 edge-triggered 的行為。

有不少文章裡列出的 epoll 和 select 的區別不夠準確,甚至中文維基百科裡 select 複雜度 o(n),epoll 複雜度 o(log n) 的說法是錯的。epoll 和 select 的主要區別是:

epoll 監聽的 fd(file descriptor)集合是常駐核心的,它有 3 個系統呼叫 (epoll_create, epoll_wait, epoll_ctl),通過 epoll_wait 可以多次監聽同乙個 fd 集合,只返回可讀寫那部分

select 只有乙個系統呼叫,每次要監聽都要將其從使用者態傳到核心,有事件時返回整個集合。

從效能上看,如果 fd 集合很大,使用者態和核心態之間資料複製的花銷是很大的,所以 select 一般限制 fd 集合最大1024。

從使用上看,epoll 返回的是可用的 fd 子集,select 返回的是全部,哪些可用需要使用者遍歷判斷。

儘管如此,epoll 的效能並不必然比 select 高,對於 fd 數量較少並且 fd io 都非常繁忙的情況 select 在效能上有優勢。

關於 level-triggered 和 edge-triggered,linux man page (epoll(7): i/o event notification facility) 已經講得很明白了。

pollable

首先,linux 的 file 有個 pollable 的概念,只有 pollable 的 file 才可以加入到 epoll 和 select 中。乙個 file 是 pollable 的當且僅當其定義了file->f_op->poll。file->f_op->poll 的形式如下

__poll_t poll(struct file *fp, poll_table *wait)

不同型別的 file 實現不同,但做的事情都差不多:

通過 fp 拿到其對應的 waitqueue

通過 wait 拿到外部設定的 callback[[1]]

執行 callback(fp, waitqueue, wait),在 callback 中會將另外乙個 callback2[[2]] 註冊到 waitqueue[[3]]中,此後 fp 有觸發事件就會呼叫 callback2

waitqueue 是事件驅動的,與驅動程式密切相關,簡單來說 poll 函式在 file 的觸發佇列中註冊了個 callback, 有事件發生時就呼叫callback。感興趣可以根據文後 [[4]] 的提示看看 socket 的 poll 實現

了解了 pollable 我們看看 epoll 的三個系統呼叫 epoll_create, epoll_ctl, epoll_wait

epoll_create只是在核心初始化一下資料結構然後返回個 fd

epoll_ctl支援新增移除 fd,我們只看新增的情況。epoll_ctl 的主要操作在 ep_insert, 它做了以下事情:

初始化乙個 epitem,裡面包含 fd,監聽的事件,就緒鍊錶,關聯的 epoll_fd 等資訊

呼叫 ep_item_poll(epitem, ep_ptable_queue_proc[[1]])。ep_item_poll 會呼叫 vfs_poll, vfs_poll 會呼叫上面說的 file->f_op->poll 將 ep_poll_callback[[2]] 註冊到 waitqueue

呼叫 ep_rbtree_insert(eventpoll, epitem) 將 epitem 插入 evenpoll 物件的紅黑樹,方便後續查詢

ep_poll_callback

在了解 epoll_wait 之前我們還需要知道 ep_poll_callback 做了哪些操作

ep_poll_callback 被呼叫,說明 epoll 中某個 file 有了新事件

eventpoll 物件有乙個 rdllist 字段,用鍊錶存著當前就緒的所有 epitem

ep_poll_callback 被呼叫的時候將 file 對應的 epitem 加到 rdllist 裡(不重複)

如果當前使用者正在 epoll_wait 阻塞狀態 ep_poll_callback 還會通過 wake_up_locked 將 epoll_wait 喚醒

epoll_wait主要做了以下操作:

檢查 rdllist,如果不為空則去到7,如果為空則去到2設定 timeout

開始無限迴圈

設定執行緒狀態為 task_interruptible [參看 sleeping in the kernal](kernel korner - sleeping in the kernel)

檢查 rdllist 如果不為空去到7, 否則去到6呼叫 schedule_hrtimeout_range 睡到 timeout,中途有可能被 ep_poll_callback 喚醒回到4,如果真的 timeout 則 break 去到7設定執行緒狀態為 task_running,rdllist如果不為空時退出迴圈,否則繼續迴圈

呼叫 ep_send_events 將 rdllist 返回給使用者態

epoll 的原理基本上就這些,還有很多細節如紅黑樹在**用,怎樣實現 level-triggered 和 edge-triggered... 我還沒看。

ps.普通檔案不是 pollable 的,詳情請看 epoll_does_not_work_with_file

附錄,以下列出的目錄都是 linux 原始碼目錄

epoll監聽檔案 epoll的使用

epoll i o event notification facility 在linux的網路程式設計中,很長的時間都在使用select來做事件觸發。在linux新的核心中,有了一種替換它的機制,就是epoll。相比於select,epoll最大的好處在於它不會隨著監聽fd數目的增長而降低效率。因為...

epoll監聽檔案 Go 檔案監控怎麼實現

檔案監控linux下inotify特性 inotify是核心乙個特性,可以用來監控目錄,檔案的讀寫等事件.當監控目標是目錄時,inotify除了會監控目錄本身,還會監控目錄中的檔案.inotify 的監控功能由如下幾個系統呼叫組成 inotify init1,inotify add watch,in...

epoll之二 epoll實戰

int epoll create int size epoll create返回 乙個控制代碼,之後epoll的 使用都將依靠這個 控制代碼 來 標識,引數 size是告訴epoll所要處理的大致事件數目,不再使用epoll時,必須呼叫close 關閉這個控制代碼。size這個引數只是 告訴核心這個...