什么是 eventfd ?
eventfd 是 Linux 的一個系統調用,創建一個文件描述符用于事件通知,自 Linux 2.6.22 以后開始支持。
接口及參數介紹
#include <sys/eventfd.h>
int eventfd(unsigned int initval, int flags);
eventfd() 創建一個 eventfd 對象,可以由用戶空間應用程序實現事件等待/通知機制,或由內核通知用戶空間應用程序事件。
該對象包含了由內核維護的無符號64位整數計數器 count 。使用參數 initval 初始化此計數器。
struct eventfd_ctx {
struct kref kref;
wait_queue_head_t wqh;
/*
* Every time that a write(2) is performed on an eventfd, the
* value of the __u64 being written is added to "count" and a
* wakeup is performed on "wqh". A read(2) will return the "count"
* value to userspace, and will reset "count" to zero. The kernel
* side eventfd_signal() also, adds to the "count" counter and
* issue a wakeup.
*/
__u64 count;
unsigned int flags;
};
flags 可以是以下值的 OR 運算結果,用以改變 eventfd 的行為。
- EFD_CLOEXEC (since Linux 2.6.27)
文件被設置成 O_CLOEXEC,創建子進程 (fork) 時不繼承父進程的文件描述符。 - EFD_NONBLOCK (since Linux 2.6.27)
文件被設置成 O_NONBLOCK,執行 read / write 操作時,不會阻塞。 - EFD_SEMAPHORE (since Linux 2.6.30)
提供類似信號量語義的 read 操作,簡單說就是計數值 count 遞減 1。
在 Linux 2.6.26 版本之前,沒有使用參數 flags,必須指定為 0。
操作方法
一切皆為文件是 Linux 內核設計的一種高度抽象,eventfd 的實現也不例外,我們可以使用操作文件的方法操作 eventfd。
- read(): 讀取 count 值后置 0。如果設置 EFD_SEMAPHORE,讀到的值為 1,同時 count 值遞減 1。
- write(): 其實是執行 add 操作,累加 count 值。
- epoll()/poll()/select(): 支持 IO 多路復用操作。
- close(): 關閉文件描述符,eventfd 對象引用計數減 1,若減為 0,則釋放 eventfd 對象資源。
使用場景
在 pipe 僅用于發出事件信號的所有情況下,都可以使用 eventfd 取而代之。