eventpipe源码分析

在这里插入图片描述

首先我们看eventhandler的注册函数

void evhandler_register(evhandler_t *evh) {
	evh->type = next_type++;
	//向queue中添加对应的handler
	TAILQ_INSERT_TAIL(&evh_list, evh, node);
}

然后我们看一下关于事件处理对应的逻辑, 函数的参数是事件

static int event_handle(event_t *ev, size_t size) {
	evhandler_t *evh;
	//首先根据对应的类型查找对应的事件handler
	evh = evhandler_find(ev->type);
	//调用处理函数
	return evh->handle(ev, evh->priv);
}

下面这个函数是事件管道的初始化函数

  • 首先我们获取对应的CPU核心数量, 这个主要通过sysconf这个函数来做的,
  • 然后我们根据对应的CPU核心数量去分配内存, 分配的内存主要用于拉取对应的事件,和对应的事件。
  • 其次ebpf内核模块通过perf_event向用户态程序发送消息,需要使用一种特殊的map BPF_MAP_TYPE_PERF_EVENT_ARRAY,我们使用bpf_map_create进行创建
  • 然后队列的初始化函数这个函数,我们会使用对应的perf_open函数来完成相应操作
int evpipe_init(evpipe_t *evp, size_t qsize) {
	uint32_t cpu;
	int err;

	if (G.dump) {
		evp->mapfd = 0xeeee;
		return 0;
	}
    //首先获取系统的cpu核心数量
	evp->ncpus = sysconf(_SC_NPROCESSORS_ONLN);
    //创建一个性能事件数组
	evp->mapfd = bpf_map_create(BPF_MAP_TYPE_PERF_EVENT_ARRAY,
				    sizeof(uint32_t), sizeof(int), evp->ncpus);
	//首先根据cpu核心数量分配对应队列的内存
	evp->q = calloc(evp->ncpus, sizeof(*evp->q));
	evp->poll = calloc(evp->ncpus, sizeof(*evp->poll));
	//创建对应数量的队列
	for (cpu = 0; cpu < evp->ncpus; cpu++) {
		//创建队列
		err = evqueue_init(evp, cpu, qsize);
	}
}

首先ebpf map位于内核态,如果想通知对应的信息给用户,那么就必须借助对应的perf_event,perf是 linux 内核提供的一项与用户进行交互的机制,主要用于内核机制的监视分析, 这是一种软件事件, 同时是用于对应的 bpf 输出。

attr.type          = PERF_TYPE_SOFTWARE;
attr.config        = PERF_COUNT_SW_BPF_OUTPUT;
attr.sample_type   = PERF_SAMPLE_RAW;
attr.wakeup_events = 1;

然后更新对应的id, 通过这种索引关系,我们可以根据所用下标获取对应的perf_event

bpf_map_update(evp->mapfd, &cpu, &q->fd, BPF_ANY);

然后分配对应性能映射内存

  • sysconf(_SC_PAGESIZE):这个调用用来获取系统的页面大小,这通常是内存映射操作需要考虑的一个参数。
  • size += sysconf(_SC_PAGESIZE);:这行代码将当前的size变量增加页面大小,可能是为了确保分配足够的内存。
  • q->mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, q->fd, 0);:这行代码尝试将文件描述符q->fd指向的文件映射到内存中。PROT_READ | PROT_WRITE指定了映射区域的保护属性,允许读写访问。MAP_SHARED表示映射是共享的,对映射区域的修改将反映到文件上。
int evqueue_init(evpipe_t *evp, uint32_t cpu, size_t size) {
	//首先定义一个性能事件的结构体
	struct perf_event_attr attr = { 0 };
	//根据cpu号查询对应队列
	struct evqueue *q = &evp->q[cpu];
	int err;
	//设置对应的属性, 分别是软件事件
	attr.type          = PERF_TYPE_SOFTWARE;
	attr.config        = PERF_COUNT_SW_BPF_OUTPUT;
	attr.sample_type   = PERF_SAMPLE_RAW;
	attr.wakeup_events = 1;
    //打开一个性能事件, 这个事件用于创建对应性能事件队列
	q->fd = perf_event_open(&attr, -1, cpu, -1, 0);
	//更新bpf的map值, 它的键是cpu号码, 它的值是创建的队列
	err = bpf_map_update(evp->mapfd, &cpu, &q->fd, BPF_ANY);
	
	size += sysconf(_SC_PAGESIZE);
	//分配对应的内存
	q->mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, q->fd, 0);
	evp->poll[cpu].fd     = q->fd;
	evp->poll[cpu].events = POLLIN;
	return 0;
}

有了这些基础的配置, 我们就可以通过事件循环来不断的拉取对应的事件了, 关于这点且听下回分解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值