环境
Ubuntu 20
Linux 5.15.0-67-generic
背景
使用用例很多,但因为内核版本问题,系统调用接口eventfd()创建的事件,使用write接口是不正常的,写入总是失败,返回值是-1,查询资料后发现有单独的接口可调用,这次没有深究是从哪个内核版本commmit的,因此没有做版本适配。总之内核版本问题在开发的时候不要轻信C站上给出的测试,对于没有给出内核版本的代码都要保留质疑的态度。
系统调用接口
int epoll_create1(int flags);
int eventfd(unsigned int initval, int flags);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
着重说eventfd的参数initval,这是创建事件时,事件内容data的初始值,只要不是0,那就会表示当前创建就触发事件,wait时当前是触发态。
其它的系统调用函数就不说明了,都能百度到。
主文件
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/eventfd.h>
#include <sys/epoll.h>
#include <pthread.h>
#include <string.h>
#include<signal.h>
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
#define MAX_EVENT_FD 32
static struct epoll_event *vfio_event;
static void *thread_func_rec(void *arg)
{
uint64_t r_data = 0;
int wake_event_num, i = 0;
char *data = NULL;
int *epoll_fd = (int*)arg;
for (;;) {
wake_event_num = epoll_wait(*epoll_fd, vfio_event, MAX_EVENT_FD, 100); //100ms
if (wake_event_num) {
for (i = 0; i < wake_event_num; i++) {
if(vfio_event[i].events & EPOLLIN) {
printf("ack the fd num: %d event\n", vfio_event[i].data.fd);
read(vfio_event[i].data.fd, &r_data, sizeof(uint64_t)); // read the eventfd will add the event back to the waiting list
printf("event recieve :%lx\n", r_data);
data = (char*)r_data;
printf("data = %s\n", data);
}
}
}
}
}
void create_eventfd(int num, int *fd, int epoll_fd)
{
struct epoll_event event;
int i = 0;
int efd = 0;
int ret = 0;
for (i = 0; i < num && i < MAX_EVENT_FD; i++) {
efd = eventfd(0, 0); //EFD_NONBLOCK
if (efd == -1)
handle_error("eventfd");
event.data.fd = efd;
event.events = EPOLLIN | EPOLLET; // EPOLLET Edge-Triggered
ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, efd, &event);
if (ret)
handle_error("epoll_ctl");
printf("fd[%d] = %d\n", i, efd);
fd[i] = efd;
}
}
int main(int argc, char *argv[])
{
pthread_t thread_r;
ssize_t ret_size = 0;
int num = 0, i = 0;
char data[64] = {0};
int fd[MAX_EVENT_FD] = {0};
int epoll_fd = 0;
int ret = 0;
epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (epoll_fd == -1)
handle_error("epoll_create1");
create_eventfd(MAX_EVENT_FD, fd, epoll_fd);
vfio_event = calloc(MAX_EVENT_FD, sizeof(struct epoll_event));
if (vfio_event == NULL)
handle_error("calloc");
ret_size = pthread_create(&thread_r, NULL, thread_func_rec, &epoll_fd);
if (ret_size != 0)
handle_error("pthread_create");
for (;;) {
printf("please input the number of event to trigger\n");
scanf("%d", &num);
printf("input num = %d\n", num);
if (num >= MAX_EVENT_FD)
break;
else {
sprintf(data,"please trigger %d event", num);
printf("func fd = %d\n", fd[num]);
ret = eventfd_write(fd[num], (eventfd_t)data);
printf("ret_size = %d\n", ret);
}
}
pthread_kill(thread_r, 0);
for (i = 0; i < num && i < MAX_EVENT_FD; i++) {
close(fd[i]);
}
free(vfio_event);
vfio_event = NULL;
exit(EXIT_SUCCESS);
}
编译文件
target = test_event
obj = eventfd-main.o
CFLAGS = -pthread
$(target):$(obj)
gcc $(CFLAGS) $^ -o $@
.PHONY:clean
clean:
rm *.o $(target)