一起来感受下eventfd的魅力(二kernel通过eventfd向user空间发送消息事件通知)
Posted 高桐@BILL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一起来感受下eventfd的魅力(二kernel通过eventfd向user空间发送消息事件通知)相关的知识,希望对你有一定的参考价值。
写在前面
接下来我们来尝试写一个测试程序,该测试程序首先在用户空间创建eventfd对象,然后再通过kernel模块程序更新eventfd的计数器以实现向用户控件程序发送事件消息通知。
一、用户空间程序代码
1.1 源码
efd_us.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h> //Definition of uint64_t
#include <sys/eventfd.h>
int efd; //Eventfd file descriptor
uint64_t eftd_ctr;
int retval; //for select()
fd_set rfds; //for select()
int s;
int main()
//Create eventfd
efd = eventfd(0,0);
if (efd == -1)
printf("\\nUnable to create eventfd! Exiting...\\n");
exit(EXIT_FAILURE);
printf("\\nefd=%d pid=%d",efd,getpid());
//Watch efd
FD_ZERO(&rfds);
FD_SET(efd, &rfds);
printf("\\nNow waiting on select()...");
fflush(stdout);
retval = select(efd+1, &rfds, NULL, NULL, NULL);
if (retval == -1)
printf("\\nselect() error. Exiting...");
exit(EXIT_FAILURE);
else if (retval > 0)
printf("\\nselect() says data is available now. Exiting...");
printf("\\nreturned from select(), now executing read()...");
s = read(efd, &eftd_ctr, sizeof(uint64_t));
if (s != sizeof(uint64_t))
printf("\\neventfd read error. Exiting...");
else
printf("\\nReturned from read(), value read = %lld",eftd_ctr);
else if (retval == 0)
printf("\\nselect() says that no data was available");
printf("\\nClosing eventfd. Exiting...");
close(efd);
printf("\\n");
exit(EXIT_SUCCESS);
1.2 编译方法
gcc efd_us.c -o efd_us
二、内核模块代码
efd_lmk.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pid.h>
#include <linux/sched.h>
#include <linux/fdtable.h>
#include <linux/rcupdate.h>
#include <linux/eventfd.h>
//Received from userspace. Process ID and eventfd's File descriptor are enough to uniquely identify an eventfd object.
int pid;
int efd;
//Resolved references...
struct task_struct * userspace_task = NULL; //...to userspace program's task struct
struct file * efd_file = NULL; //...to eventfd's file struct
struct eventfd_ctx * efd_ctx = NULL; //...and finally to eventfd context
//Increment Counter by 1
static uint64_t plus_one = 1;
int init_module(void)
printk(KERN_ALERT "~~~Received from userspace: pid=%d efd=%d\\n",pid,efd);
userspace_task = pid_task(find_vpid(pid), PIDTYPE_PID);
printk(KERN_ALERT "~~~Resolved pointer to the userspace program's task struct: %p\\n",userspace_task);
printk(KERN_ALERT "~~~Resolved pointer to the userspace program's files struct: %p\\n",userspace_task->files);
rcu_read_lock();
efd_file = fcheck_files(userspace_task->files, efd);
rcu_read_unlock();
printk(KERN_ALERT "~~~Resolved pointer to the userspace program's eventfd's file struct: %p\\n",efd_file);
efd_ctx = eventfd_ctx_fileget(efd_file);
if (!efd_ctx)
printk(KERN_ALERT "~~~eventfd_ctx_fileget() Jhol, Bye.\\n");
return -1;
printk(KERN_ALERT "~~~Resolved pointer to the userspace program's eventfd's context: %p\\n",efd_ctx);
eventfd_signal(efd_ctx, plus_one);
printk(KERN_ALERT "~~~Incremented userspace program's eventfd's counter by 1\\n");
eventfd_ctx_put(efd_ctx);
return 0;
void cleanup_module(void)
printk(KERN_ALERT "~~~Module Exiting...\\n");
MODULE_LICENSE("GPL");
module_param(pid, int, 0);
module_param(efd, int, 0);
三、 编译对应Ubuntu版本的内核源码
3.1 更新sources.list
deb-src http://archive.ubuntu.com/ubuntu bionic main
deb-src http://archive.ubuntu.com/ubuntu bionic-updates main
3.2 安装必须的包
sudo apt-get build-dep linux linux-image-$(uname -r)
3.3 安装必须工具链
sudo apt-get install libncurses-dev gawk flex bison openssl libssl-dev dkms libelf-dev libudev-dev libpci-dev libiberty-dev autoconf git
编译内核模块
make modules
如:make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- modules
直接make,不加任何参数,就是make all,包含make modules。
make modules是单独编译模块,驱动被配置成M的都是modules,modules不会被编译进内核image,需要单独安装到rootfs。
3.4 下载当前内核对应源码
apt-get source linux-image-unsigned-$(uname -r)
或 git clone git://kernel.ubuntu.com/ubuntu/ubuntu-<release codename>.git
3.5 修改配置
chmod a+x debian/rules chmod a+x debian/scripts/* chmod a+x debian/scripts/misc/* LANG=C fakeroot debian/rules clean LANG=C fakeroot debian/rules editconfigs # you need to go through each (Y, Exit, Y, Exit..) or get a complaint about config later
3.6 编译内核·
LANG=C fakeroot debian/rules clean # quicker build: LANG=C fakeroot debian/rules binary-headers binary-generic binary-perarch # if you need linux-tools or lowlatency kernel, run instead: LANG=C fakeroot debian/rules binary
注意!可复制系统当前配置文件(没有试过)
bill@bill-VirtualBox:/boot$ sudo cp config-5.4.0-84-generic ../usr/src/linux-headers-5.4.0-84-generic/.config
四、FAQ
4.1 执行“apt-get source linux-image-$(uname -r)”,提示"E:您必须在sources.list中指定源代码(deb-src)URI"
解决方案:在软件和更新(ubuntu)勾选“源代码”
以上是关于一起来感受下eventfd的魅力(二kernel通过eventfd向user空间发送消息事件通知)的主要内容,如果未能解决你的问题,请参考以下文章
Intel 计划在Linux kernel中引入 User Interrupts,效率是eventfd的10倍
Intel 计划在Linux kernel中引入 User Interrupts,效率是eventfd的10倍
手写自定义springboot-starter,感受框架的魅力和原理