项目中要用到libevent,所以就自学了libevent,参考资料为张亮的《libevent源码深度剖析》和《linux高性能服务器编程》
Libevent简介
Libevent是开源社区一款高性能的I/O框架库,其具有如下特点:
1.跨平台支持。Libevent支持Linux、UNIX和Windows。
2.统一事件源。libevent对i/o事件、信号和定时事件提供统一的处理。
3.线程安全。libevent使用libevent_pthreads库来提供线程安全支持。
4.基于reactor模式的实现。
reactor基本知识
reactor是i/o框架库的核心,它主要提供的几个方法是:
1.handle_events:该方法执行事件循环,重复如下过程:等待事件,然后依次处理所有就绪事件对应的时间处理器。
2.register_handler:该方法调用事件多路分发器的register_event方法来往事件多路分发器中注册一个事件。
3.remove_handler:该方法调用事件多路分发器的remove_event方法来删除事件多路分发器中的一个事件。
下图为i/o框架库的工作时序图:
reactor具有如下优点:
1.响应快,不必为单个同步事件所阻塞;
2.编程相对简单,可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/进程的切换开销;
3.可扩展性,可以方便的通过增加reactor实例个数来充分利用CPU资源;
4.可复用性,reactor框架本身与具体事件处理逻辑无关,具有很高的复用性。
libevent库的主要逻辑:
1.调用event_init函数创建event_base对象。一个event_base相当于一个reactor实例。
2.创建具体的事件处理器,并设置它们所从属的reactor实例。evsignal_new和evtimer_new分别用于创建信号事件处理器和定时事件处理器,它们的统一入口是event_new函数,event_new函数成功时返回一个event类型的对象,也就是libevent的事件处理器
3.调用event_add函数,将事件处理器添加到注册事件队列中,并将该事件处理器对应的事件添加到事件多路分发器中。
4.调用event_base_dispatch函数来执行事件循环。
5.事件循环结束后,使用*_free系列函数来释放系统资源。
源代码组织结构
1)头文主要就是 event.h:事件宏定义、接口函数声明,主要结构体 event 的声明;
2)内部头文件
xxx-internal.h:内部数据结构和函数,对外不可见,以达到信息隐藏的目的;
3) libevent 框架
event.c: event 整体框架的代码实现;
4)对系统 I/O 多路复用机制的封装
epoll.c:对 epoll 的封装;
select.c:对 select 的封装;
devpoll.c:对 dev/poll 的封装;
kqueue.c:对 kqueue 的封装;
5)定时事件管理
min-heap.h:其实就是一个以时间作为 key 的小根堆结构;
6)信号管理
signal.c:对信号事件的处理;
7)辅助功能函数
evutil.h 和 evutil.c:一些辅助功能函数,包括创建 socket pair 和一些时间操作函数:加、减
和比较等。
8)日志
log.h 和 log.c: log 日志函数
9)缓冲区管理
evbuffer.c 和 buffer.c: libevent 对缓冲区的封装;
10)基本数据结构
compat\sys 下的两个源文件: queue.h 是 libevent 基本数据结构的实现,包括链表,双向链表,
队列等; _libevent_time.h:一些用于时间操作的结构体定义、函数和宏定义;
11)实用网络库
http 和 evdns:是基于 libevent 实现的 http 服务器和异步 dns 查询库;
event结构体
libevent中的事件处理器是event结构类型。event结构体封装了句柄、事件类型、回调函数、以及其他必要的标志和数据,源代码如下
struct event { TAILQ_ENTRY(event) ev_active_next; TAILQ_ENTRY(event) ev_next; /* 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 { TAILQ_ENTRY(event) ev_io_next; struct timeval ev_timeout; } ev_io; /* used by signal events */ struct { TAILQ_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 */ short ev_flags; ev_uint8_t ev_pri; /* smaller numbers are higher priority */ ev_uint8_t ev_closure; struct timeval ev_timeout; /* allows us to adopt for different types of events */ void (*ev_callback)(evutil_socket_t, short, void *arg); void *ev_arg; };ev_active_next: 表示就绪状态的事件链表指针,当关注的事件就绪后,会把
对应的event放入active的队列里。表示该事件在active队列里的位置
ev_next:表示所有事件队列链表的指针。表示该事件在所有时间列表的位置。
ev_timeout_pos:用于管理超时
ev_fd:event绑定的socket描述符
ev_events:
event关注的事件类型,它可以是以下3种类型:
I/O事件: EV_WRITE和EV_READ
定时事件: EV_TIMEOUT
信号: EV_SIGNAL
辅助选项: EV_PERSIST,表明是一个永久事件
Libevent中的定义为:
#define EV_TIMEOUT 0x01
#define EV_READ 0x02
#define EV_WRITE 0x04
#define EV_SIGNAL 0x08
#define EV_PERSIST 0x10 /* Persistant event */
ev_res:记录了当前激活事件的类型;
ev_flags: libevent 用于标记 event 信息的字段,表明其当前的状态,可能的值有:
#define EVLIST_TIMEOUT 0x01 // event在time堆中
#define EVLIST_INSERTED 0x02 // event在已注册事件链表中
#define EVLIST_SIGNAL 0x04 // 未见使用
#define EVLIST_ACTIVE 0x08 // event在激活链表中
#define EVLIST_INTERNAL 0x10 // 内部使用标记
#define EVLIST_INIT 0x80 // event 已被初始化
ev_pri:当前事件的优先级
ev_timeout:超时时间设置
ev_callback:该事件对应的回调函数,和cb类型一样
ev_arg:回调函数用到参数
ev_ncalls:事件就绪执行时,调用 ev_callback 的次数,通常为 1;
ev_pncalls:指针,通常指向 ev_ncalls 或者为 NULL;
往注册事件队列中添加事件处理器
创建一个event对象的函数是event_new,创建好之后应用程序调用event_add函数将其添加到注册事件队列中,并将对应的事件注册到事件多路分发器上,event_add函数主要是调用一个内部函数event_add_internal来实现的。
eventop结构体
eventop结构体封装了i/o复用机制必要的一些操作,比如注册事件、等待事件等,它为event_base支持的所有后端i/o复用机制提供了一个统一的接口,libevent默认选择的后端i/o复用技术是epoll。
event_base结构体
结构体event_base是libevent的reactor,源码如下:
struct event_base { /** Function pointers and other data to describe this event_base's * backend. */ const struct eventop *evsel; /** Pointer to backend-specific data. */ void *evbase; /** List of changes to tell backend about at next dispatch. Only used * by the O(1) backends. */ struct event_changelist changelist; /** Function pointers used to describe the backend that this event_base * uses for signals */ const struct eventop *evsigsel; /** Data to implement the common signal handelr code. */ struct evsig_info sig; /** Number of virtual events */ int virtual_event_count; /** Number of total events added to this event_base */ int event_count; /** Number of total events active in this event_base */ int event_count_active; /** Set if we should terminate the loop once we're done processing * events. */ int event_gotterm; /** Set if we should terminate the loop immediately */ int event_break; /** Set if we should start a new instance of the loop immediately. */ int event_continue; /** The currently running priority of events */ int event_running_priority; /** Set if we're running the event_base_loop function, to prevent * reentrant invocation. */ int running_loop; /* Active event management. */ /** An array of nactivequeues queues for active events (ones that * have triggered, and whose callbacks need to be called). Low * priority numbers are more important, and stall higher ones. */ struct event_list *activequeues; /** The length of the activequeues array */ int nactivequeues; /* common timeout logic */ /** An array of common_timeout_list* for all of the common timeout * values we know. */ struct common_timeout_list **common_timeout_queues; /** The number of entries used in common_timeout_queues */ int n_common_timeouts; /** The total size of common_timeout_queues. */ int n_common_timeouts_allocated; /** List of defered_cb that are active. We run these after the active * events. */ struct deferred_cb_queue defer_queue; /** Mapping from file descriptors to enabled (added) events */ struct event_io_map io; /** Mapping from signal numbers to enabled (added) events. */ struct event_signal_map sigmap; /** All events that have been enabled (added) in this event_base */ struct event_list eventqueue; /** Stored timeval; used to detect when time is running backwards. */ struct timeval event_tv; /** Priority queue of events with timeouts. */ struct min_heap timeheap; /** Stored timeval: used to avoid calling gettimeofday/clock_gettime * too often. */ struct timeval tv_cache; #if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) /** Difference between internal time (maybe from clock_gettime) and * gettimeofday. */ struct timeval tv_clock_diff; /** Second in which we last updated tv_clock_diff, in monotonic time. */ time_t last_updated_clock_diff; #endif #ifndef _EVENT_DISABLE_THREAD_SUPPORT /* threading support */ /** The thread currently running the event_loop for this base */ unsigned long th_owner_id; /** A lock to prevent conflicting accesses to this event_base */ void *th_base_lock; /** The event whose callback is executing right now */ struct event *current_event; /** A condition that gets signalled when we're done processing an * event with waiters on it. */ void *current_event_cond; /** Number of threads blocking on current_event_cond. */ int current_event_waiters; #endif #ifdef WIN32 /** IOCP support structure, if IOCP is enabled. */ struct event_iocp_port *iocp; #endif /** Flags that this base was configured with */ enum event_base_config_flag flags; /* Notify main thread to wake up break, etc. */ /** True if the base already has a pending notify, and we don't need * to add any more. */ int is_notify_pending; /** A socketpair used by some th_notify functions to wake up the main * thread. */ evutil_socket_t th_notify_fd[2]; /** An event used by some th_notify functions to wake up the main * thread. */ struct event th_notify; /** A function used to wake up the main thread from another thread. */ int (*th_notify_fn)(struct event_base *base); };
事件循环
libevent中实现事件循环的函数是event_base_loop,该函数首先调用i/o事件多路分发器的事件监听函数,以等待事件,当有事件发生时,就依次处理之。
参考博客:点击打开链接