epoll (eventfd)在内核5.15下的保姆使用案例

环境

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)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_三剑客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值