Libevent 源码剖析(始)

本文深入剖析Libevent库的源码,从一个实例入手,详细介绍了事件处理器的创建、事件的添加与处理流程。通过代码示例,展示了如何使用Libevent进行事件驱动编程,包括信号事件、定时事件的处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Libevent 源码剖析二

从简单使用到源码分析一步步学习

一个实例

任何一个代码的学习都是从hello world开始的

#include <sys/signal.h>
#include <event.h>

void signal_cb( int fd, short event, void *arg)
{
	struct event_base *base = (struct event_base *)arg;
	struct timeval delay = {2, 0};
	printf("Caught an interrupt signal; exiting cleanly in 2s");
	event_base_loopexit(base, &delay);
}

void timeout_cb( int fd, short event, void *argc)
{
	printf("timeout\n");
}

int main(int argc, char **argv)
{
	struct event_base *base = event_init();
	struct event *signal_event = evsignal_new(base, SIGINT, signal_cb, base);
	event_add(signal_event, NULL);

	struct timeval tv = {1, 0};
	struct event *timeout_event = evtimer_new(base, timeout_cb, NULL);
	event_add(timeout_event, &tv);
	
	event_base_dispatch(base);

	event_free(timeout_event);
	event_free(signal_event);
	event_base_free(base);
	return 0;
}

libevent库的主要逻辑

  1. 调用event_init 函数创建event_base 对象,一个event_base相当于一个reactor实例。
    2)创建具体的事件处理器,并且设置它们所从属的Reactor实例,evsignal_new/evtimer_new 分别用于创建信号事件处理器和定时事件处理器,它们是定义在include/event2/event.h文件中的宏
#define evsignal_new(b, x, cb, arg) \
	event_new((b), (x), EV_SIGNAL|EV_PERSIST, (cb), (arg))
#define evtimer_new(b, cb, arg)	event_new((b), -1, 0, (cb), (arg))

它们的统一入口是event_new函数,用于创建事件处理器的函数

/*
*@parm base : 事件处理器从属的Reactor, fd:指定与该事件处理器关联的句柄(创建IO事件传描述符,创建信号事件是传信号值,创建定时事件处理器时传-1)
*@parm event 可选事件  (12-1)   
*   #define EV_TIMEOUT 0x01 //定时
* 	#define EV_READ 0x02	//可读
* 	#define EV_WRITE 0x04	//可写
* 	#define EV_SIGNAL 0x08	//信号
* 	#define EV_PRESIST 0x10 //永久事件
* 	#define EV_ET 0x20	//ET事件,需要EPOLL等系统调用的支持
* @parm cb : 指定目标事件对应的回调函数。相当与事件处理器中的handl_event
* @parm	arg:Reactor传递给回调的参数
*return : libevent的事件处理器
*/
struct event* event_new(struct event_base *base, evutil_socket_t fd, short events,
						coid (*cb)(evutil_socket_t, short, void *), void *arg);

libevent主要概念词汇描述

  • 事件:指的是一个局柄上绑定的事件,比如文件描述符0上的可读事件
  • 事件处理器:也就是event结构体类型的对象,除了包含事件必须具备的两个要素(句柄,事件类型)外,还要其他的成员比如回调函数
  • 事件有事件多路分发器管理,事件处理器有事件队列管理。事件队列包括多种,比如event_base中的注册事件队列,活动事件队列和通用定时器队列,以及evmap中的IO事件队列,信号事件队列。
  • 事件循环对一个被激活的事件(就绪事件)的处理,指的是执行其回调函数

3)调用event_add函数,将事件处理器添加到注册事件队列中,并将该事件处理器对应的事件添加到事件多路分发器中。event_add函数相当与Reactor中的register_handler方法。
4)调用event_base_dispatch函数来执行事件循环
5)事件循环结束后,是*_free系列函数释放系统资源

event结构体

struct event_callback {
	TAILQ_ENTRY(event_callback) evcb_active_next;
	short evcb_flags;  /*事件标志*/
	ev_uint8_t evcb_pri;	/* smaller numbers are higher priority */
	ev_uint8_t evcb_closure;
	/* allows us to adopt for different types of events */
        union {
		void (*evcb_callback)(evutil_socket_t, short, void *);
		void (*evcb_selfcb)(struct event_callback *, void *);
		void (*evcb_evfinalize)(struct event *, void *);
		void (*evcb_cbfinalize)(struct event_callback *, void *);
	} evcb_cb_union;
	void *evcb_arg;
};

struct event_base;
struct event {
	struct event_callback ev_evcallback;

	/* for managing timeouts */
	union {
		TAILQ_ENTRY(event) ev_next_with_common_timeout;
		int min_heap_idx;
	} ev_timeout_pos;
	evutil_socket_t ev_fd;

	struct event_base *ev_base;

	union {
		/* used for io events */
		struct {
			LIST_ENTRY (event) ev_io_next;
			struct timeval ev_timeout;
		} ev_io;

		/* used by signal events */
		struct {
			LIST_ENTRY (event) ev_signal_next;
			short ev_ncalls;
			/* Allows deletes in callback */
			short *ev_pncalls;
		} ev_signal;
	} ev_;

	short ev_events;
	short ev_res;		/* result passed to event callback */
	struct timeval ev_timeout;
};
  • ev_events 代表事件类型,取值可以是上述可选事件所标志的按位或(互斥事件除外)
  • ev_active_next:活动事件队列,所有被激活的事件处理器通过该成员串联成一个尾队列
  • ev_time_pos:仅仅用于定时事件处理器
  • _ev:一个union,所有具有相同文件描述符的IO事件处理器通过ev.ev_io_ev_io_next串联成一个尾队列,我们称之为IO事件队列
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值