linux内核中的eventfd

转载请注明来源:https://www.cnblogs.com/hookjc/

eventfd 在内核版本,2.6.22以后有效。查看内核版本可以用命令 uname -r 。
  1.  #include<sys/eventfd.h>  
  2. int eventfd(unsigned int initval,int flags);

这个函数会创建一个 事件对象 (eventfd object), 用来实现,进程(线程)间的等待/通知(wait/notify) 机制. 内核会为这个对象维护一个64位的计数器(uint64_t)。
并且使用第一个参数(initval)初始化这个计数器。调用这个函数就会返回一个新的文件描述符(event object)。2.6.27版本开始可以按位设置第二个参数(flags)。
有如下的一些宏可以使用:

EFD_NONBLOCK , 功能同open(2) 的O_NONBLOCK,设置对象为非阻塞状态,如果没有设置这个状态的话,read(2)读eventfd,并且计数器的值为0 就一直堵塞在read调用当中,要是设置了这个标志, 就会返回一个 EAGAIN 错误(errno = EAGAIN)。效果也如同 额外调用select(2)达到的效果。

EFD_CLOEXEC 我的理解是,这个标识被设置的话,调用exec后会自动关闭文件描述符,防止泄漏。

如果是2.6.26或之前版本的内核,flags 必须设置为0。

创建这个对象后,可以对其做如下操作。

write 将缓冲区写入的8字节整形值加到内核计数器上。

read 读取8字节值, 并把计数器重设为0. 如果调用read的时候计数器为0, 要是eventfd是阻塞的, read就一直阻塞在这里,否则就得到 一个EAGAIN错误。
如果buffer的长度小于8那么read会失败, 错误代码被设置成 EINVAL。

poll select epoll

close 当不需要eventfd的时候可以调用close关闭, 当这个对象的所有句柄都被关闭的时候,内核会释放资源。 为什么不是close就直接释放呢, 如果调用fork 创建

进程的时候会复制这个句柄到新的进程,并继承所有的状态。

(ps:也就是说,在write之后没有read,但是又write新的数据,那么读取的是这两次的8个字节的和,在read之后再write,可以完成read和write之间的交互)

一个例子:

  1. #include <stdio.h>  
  2. #include <unistd.h>  
  3. #include <sys/time.h>  
  4. #include <stdint.h>  
  5. #include <pthread.h>  
  6. #include <sys/eventfd.h>  
  7. #include <sys/epoll.h>  
  8.   
  9. int efd = -1;  
  10.   
  11. void *read_thread(void *dummy)  
  12. {  
  13.     int ret = 0;  
  14.     uint64_t count = 0;  
  15.     int ep_fd = -1;  
  16.     struct epoll_event events[10];  
  17.   
  18.     if (efd < 0)  
  19.     {  
  20.         printf("efd not inited.\n");  
  21.         goto fail;  
  22.     }  
  23.   
  24.     ep_fd = epoll_create(1024);  
  25.     if (ep_fd < 0)  
  26.     {  
  27.         perror("epoll_create fail: ");  
  28.         goto fail;  
  29.     }  
  30.   
  31.     {  
  32.         struct epoll_event read_event;  
  33.   
  34.         read_event.events = EPOLLHUP | EPOLLERR | EPOLLIN;  
  35.         read_event.data.fd = efd;  
  36.   
  37.         ret = epoll_ctl(ep_fd, EPOLL_CTL_ADD, efd, &read_event);  
  38.         if (ret < 0)  
  39.         {  
  40.             perror("epoll ctl failed:");  
  41.             goto fail;  
  42.         }  
  43.     }  
  44.   
  45.     while (1)  
  46.     {  
  47.         ret = epoll_wait(ep_fd, &events[0], 10, 5000);  
  48.         if (ret > 0)  
  49.         {  
  50.             int i = 0;  
  51.             for (; i < ret; i++)  
  52.             {  
  53.                 if (events[i].events & EPOLLHUP)  
  54.                 {  
  55.                     printf("epoll eventfd has epoll hup.\n");  
  56.                     goto fail;  
  57.                 }  
  58.                 else if (events[i].events & EPOLLERR)  
  59.                 {  
  60.                     printf("epoll eventfd has epoll error.\n");  
  61.                     goto fail;  
  62.                 }  
  63.                 else if (events[i].events & EPOLLIN)  
  64.                 {  
  65.                     int event_fd = events[i].data.fd;  
  66.                     ret = read(event_fd, &count, sizeof(count));  
  67.                     if (ret < 0)  
  68.                     {  
  69.                         perror("read fail:");  
  70.                         goto fail;  
  71.                     }  
  72.                     else  
  73.                     {  
  74.                         struct timeval tv;  
  75.   
  76.                         gettimeofday(&tv, NULL);  
  77.                         printf("success read from efd, read %d bytes(%llu) at %lds %ldus\n",  
  78.                                ret, count, tv.tv_sec, tv.tv_usec);  
  79.                     }  
  80.                 }  
  81.             }  
  82.         }  
  83.         else if (ret == 0)  
  84.         {  
  85.             /* time out */  
  86.             printf("epoll wait timed out.\n");  
  87.             break;  
  88.         }  
  89.         else  
  90.         {  
  91.             perror("epoll wait error:");  
  92.             goto fail;  
  93.         }  
  94.     }  
  95.   
  96. fail:  
  97.     if (ep_fd >= 0)  
  98.     {  
  99.         close(ep_fd);  
  100.         ep_fd = -1;  
  101.     }  
  102.   
  103.     return NULL;  
  104. }  
  105.   
  106. int main(int argc, char *argv[])  
  107. {  
  108.     pthread_t pid = 0;  
  109.     uint64_t count = 0;  
  110.     int ret = 0;  
  111.     int i = 0;  
  112.   
  113.     efd = eventfd(0, 0);  
  114.     if (efd < 0)  
  115.     {  
  116.         perror("eventfd failed.");  
  117.         goto fail;  
  118.     }  
  119.   
  120.     ret = pthread_create(&pid, NULL, read_thread, NULL);  
  121.     if (ret < 0)  
  122.     {  
  123.         perror("pthread create:");  
  124.         goto fail;  
  125.     }  
  126.   
  127.     for (i = 0; i < 5; i++)  
  128.     {  
  129.         count = 4;  
  130.         ret = write(efd, &count, sizeof(count));  
  131.         if (ret < 0)  
  132.         {  
  133.             perror("write event fd fail:");  
  134.             goto fail;  
  135.         }  
  136.         else  
  137.         {  
  138.             struct timeval tv;  
  139.   
  140.             gettimeofday(&tv, NULL);  
  141.             printf("success write to efd, write %d bytes(%llu) at %lds %ldus\n",  
  142.                    ret, count, tv.tv_sec, tv.tv_usec);  
  143.         }  
  144.   
  145.         sleep(1);  
  146.     }  
  147.   
  148. fail:  
  149.     if (0 != pid)  
  150.     {  
  151.         pthread_join(pid, NULL);  
  152.         pid = 0;  
  153.     }  
  154.   
  155.     if (efd >= 0)  
  156.     {  
  157.         close(efd);  
  158.         efd = -1;  
  159.     }  
  160.     return ret;  
  161. }  

  1. success write to efd, write 8 bytes(4) at 1328805612s 21939us  
  2. success read from efd, read 8 bytes(4) at 1328805612s 21997us  
  3. success write to efd, write 8 bytes(4) at 1328805613s 22247us  
  4. success read from efd, read 8 bytes(4) at 1328805613s 22287us  
  5. success write to efd, write 8 bytes(4) at 1328805614s 22462us  
  6. success read from efd, read 8 bytes(4) at 1328805614s 22503us  
  7. success write to efd, write 8 bytes(4) at 1328805615s 22688us  
  8. success read from efd, read 8 bytes(4) at 1328805615s 22726us  
  9. success write to efd, write 8 bytes(4) at 1328805616s 22973us  
  10. success read from efd, read 8 bytes(4) at 1328805616s 23007us  
  11. epoll wait timed out.  

同时他也是支持进程间通信的,过程和这个差不多。

来源:python脚本自动迁移

posted @ 2020-06-23 19:33  jiangcheng_15  阅读(553)  评论(0编辑  收藏  举报