eventfd 入门
1 eventfd 是什么
eventfd 是linux内核一个计数器,主要用于进程间或者线程间,高效的事件通知。
它也是一个系统调用,在内核空间进行计数,用于事件通知 (since linux 2.6.22
)。
eventfd 也是一个fd,同样可以使用read/write进行读写操作,本质上是eventfd实现了read/write接口(里氏替换)。
更详细的可以查看 man eventfd
|
|
eventfd() 创建一个 eventfd 对象
,可以由用户空间应用程序实现事件等待/通知机制,
或由内核发送事件通知, 到用户空间的应用程序。
该对象包含了一个无符号64位整型计数器,计数器由内核维护。 此计数器,使用参数 initval 进行初始化。
eventfd_ctx 内部数据结构:
|
|
翻译一下:
每次对eventfd执行write(2)时,将要写入的__u64的值添加到"count",并在"wqh"上执行唤醒。
read(2)将"count" 值返回到用户空间,并将"count"重置为零。
内核端eventfd_signal()也添加到"count"计数器中并发出唤醒。
2 使用方法
一切皆为文件是 Linux 内核设计的一种高度抽象,eventfd 的实现也不例外,我们可以使用操作文件的方法操作 eventfd。
- read(): 读取 count 值后置 0。(如果设置 EFD_SEMAPHORE,读到的值为 1,同时 count 值递减 1。)
- write(): 其实是执行 add 操作,累加 count 值。
- epoll()/poll()/select(): 支持 IO 多路复用操作。
- close(): 关闭文件描述符,eventfd 对象引用计数减 1,若减为 0,则释放 eventfd 对象资源。
3 应用场景
(1) 比如 libuv 线程间通知,优先采用 eventfd, 如果平台不支持,则采用pipe.
当 pipe 仅用于发出事件信号的所有情况下,都可以使用 eventfd 取而代之。
(2) 作为桥梁,使得epoll可以集成libaio,aio的事件采用eventfd进行通知,而epoll只需要wait这个eventfd即可。
Reference
其他
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。