• Libev源码分析07:Linux下的eventfd简介


    #include <sys/eventfd.h>
    
    int eventfd(unsigned int initval, int flags);
    

            eventfd创建一个eventfd对象,该对象可用于用户空间的程序实现事件等待、通知机制,也可用于由内核向用户空间的应用进行事件的通知。eventfd对象在内核中包含了一个计数器,该计数器是64位的无符号整数(uint64_t),该计数器由eventfd函数的initval参数进行初始化。

            在Linux2.6.26之前的版本,flags参数是无用的,必须置为0。从Linux2.6.27开始,可以在flags中指定下面的值以改变eventfd的行为:

    EFD_NONBLOCK:在新建的文件描述符上设置O_NONBLOCK文件状态标志;

    EFD_CLOEXEC:在新建的文件描述符上设置FD_CLOEXEC标志。

     

            eventfd返回的文件描述符可以执行下面的操作:

            read:如果eventfd的计数器的值非0,则read操作在一个8字节缓冲区中返回该值,并且将计数器重置为0,返回的值是主机字节序。如果计数器的值为0,若文件描述符设置为非阻塞的话,则read返回EAGAIN错误,否则,read一直阻塞,直到计数器非0。

            如果提供给read的缓冲区长度小于8字节的话,read返回EINVAL错误。

     

            write:write操作会将buffer中的8字节整数加到计数器上。计数器的最大值是64位无符号整数的最大值减1,也就是0xfffffffffffffffe。如果增加计数器的值会超过该最大值,若文件描述符设置成非阻塞的话,则write返回EAGAIN错误,否则,write操作会一直阻塞,直到在该文件描述符上执行了read操作。

            如果write缓冲区的大小小于8字节,或者直接写0xffffffffffffffff的话,write将返回EINVAL错误。也就是说,下面的代码,不管计数器的当前值是多少,write操作都会返回EINVAL错误:

    unsigned char buf[8] = {0};
    memset(buf, 0xff, 8);
    write(efd, buf, 8);
    

            poll、select、epoll等:eventfd创建的文件描述符支持poll、epoll和select等操作:

            如果计数器的值大于0,则该文件描述符可读;

            如果在该描述符上至少能非阻塞的写入1,则该描述符就是可写的;

            如果检测到计数器发生了溢出,则select会指示该文件描述符可读且可写;poll会返回POLLERR事件。上面提到的write操作不可能会使得计数器溢出。然而,KAIO子系统执行的2^64 eventfd “signal posts”操作会导致计数器溢出。这种情况,尽管理论上是可能的,但实际上却不太可能。如果确实发生了溢出,则read操作将会返回0xffffffffffffffff。

     

            close:当不再需要该文件描述符时,应该使用close关闭。与其他文件描述符一样,如果底层eventfd对象关联的所有文件描述符都关闭之后,则该对象的资源就会被内核释放掉。

     

            与其他文件描述符类似,fork之后,子进程拥有父进程的eventfd文件描述符的副本,它们指向相同的底层eventfd对象。执行execve之后,除非设置了close-on-exec标志,否则eventfd创建的描述符在子进程中依然保留。

     

            eventfd调用成功,返回新的eventfd文件描述符,失败时返回-1,并设置相应的errno。

     

            eventfd是linux特有的,自linux2.6.22才开始引入,在glibc的2.8版本中开始被支持。

     

            在应用程序使用管道处理信号事件的所有场景中,可以用eventfd替换pipe。内核使用eventfd文件描述符的负载要比pipe低很多,并且仅仅使用一个描述符即可,而不是像pipe那样使用两个。

     

            在内核中使用eventfd时,eventfd文件描述符起到了桥接内核和用户空间的作用,允许像KAIO(内核异步IO)这样的功能给一个文件描述符发送某些操作已经完成的信号。

     

            eventfd文件描述符的关键优势在于它能够用于select、poll或者epoll。这样,应用程序可以同时监听常规文件和支持eventfd接口的其他内核机制的可读性。

     

    例子:

    #define handle_error(msg) 
        do { perror(msg); exit(EXIT_FAILURE); } while (0)
    
    int main(int argc, char *argv[])
    {
        int efd, j;
        uint64_t u;
        ssize_t s;
    
        if (argc < 2) 
        {
            fprintf(stderr, "Usage: %s <num1> <num2>...
    ", argv[0]);
            exit(EXIT_FAILURE);
        }
    
        efd = eventfd(0, 0);
        if (efd == -1)
            handle_error("eventfd");
    
        switch (fork()) 
        {
            case 0:
                for (j = 1; j < argc; j++) 
                {
                    printf("Child writing %s to efd
    ", argv[j]);
                    u = strtoull(argv[j], NULL, 0);
                    s = write(efd, &u, sizeof(uint64_t));
                    if (s != sizeof(uint64_t))
                        handle_error("write");
                }
                printf("Child completed write loop
    ");
    
                exit(EXIT_SUCCESS);
    
            default:
                wait();
    
                printf("Parent about to read
    ");
                s = read(efd, &u, sizeof(uint64_t));
                if (s != sizeof(uint64_t))
                    handle_error("read");
    
                printf("Parent read %llu (0x%llx) from efd
    ",
                        (unsigned long long) u, (unsigned long long) u);
                exit(EXIT_SUCCESS);
    
            case -1:
                handle_error("fork");
        }
    }
    

    结果:

    # ./a.out 11 23 1
    Child writing 11 to efd
    Child writing 23 to efd
    Child writing 1 to efd
    Child completed write loop
    Parent about to read
    Parent read 35 (0x23) from efd
    

  • 相关阅读:
    [Leetcode] generate parentheses 生成括号
    [Leetcode] letter combinations of a phone number 电话号码的字母组合
    MySQL安装出现“不是内部或外部命令,也不是可执行程序”等一系列问题的解决方案
    [Leetcode] sudoku solver 求解数独
    [Leetcode] valid sudoku 有效数独
    jQuery使用(七):事件绑定与取消,及自定事件的实现原理
    前端交互体验核心之事件(一)
    jQuery使用(六):DOM操作之元素包裹、克隆DOM与data的综合应用
    jQuery使用(五):DOM操作之插入和删除元素
    jQuery使用(四):DOM操作之查找兄弟元素和父级元素
  • 原文地址:https://www.cnblogs.com/gqtcgq/p/7247096.html
Copyright © 2020-2023  润新知