4

eventfd 入门

 1 year ago
source link: https://forrestsu.github.io/posts/linux/eventfd-introduction/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

1 eventfd 是什么

eventfd 是linux内核一个计数器,主要用于进程间或者线程间,高效的事件通知。

它也是一个系统调用,在内核空间进行计数,用于事件通知 (since linux 2.6.22)。
eventfd 也是一个fd,同样可以使用read/write进行读写操作,本质上是eventfd实现了read/write接口(里氏替换)。

更详细的可以查看 man eventfd

#include <sys/eventfd.h>

int eventfd(unsigned int initval, int flags);

eventfd() 创建一个 eventfd 对象,可以由用户空间应用程序实现事件等待/通知机制, 或由内核发送事件通知, 到用户空间的应用程序。

该对象包含了一个无符号64位整型计数器,计数器由内核维护。 此计数器,使用参数 initval 进行初始化。

eventfd_ctx 内部数据结构:

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;
};

翻译一下:
每次对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

man eventfd

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。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK