libevent项目分析(二) -- 例程分析

来源:互联网 发布:澳洲网络运营商 编辑:程序博客网 时间:2024/06/05 14:10

初始化

libevent库的使用是从对event_base结构初始化开始的,前面例程中使用的方法是不带任何参数的event_base_new函数,类似的还有event_init函数。前者创建并初始化了一个默认的event_config结构,然后调用event_base_new_with_config函数;而后者更加简单,用了一个NULL做为参数调用event_base_new_with_config函数。所以可以理解libevent库的初始化核心是event_base_new_with_config函数,对该函数的分析留给后面,这次不打算分析到具体函数的实现 :)


事件定义

libevent库实现的就是事件监听和驱动机制,该库中对事件的定义是event结构。该结构不是很复杂,但比较重要,这里列出几个比较重要的成员变量

1,双向事件链表

TAILQ_ENTRY(event) ev_active_next;

TAILQ_ENTRY(event) ev_next;

其中TAILQ_ENTRY宏在event2/event_struct.h文件中定义如下

/* Fix so that people don't have to run with <sys/queue.h> */
#ifndef TAILQ_ENTRY
#define _EVENT_DEFINED_TQENTRY
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next;/* next element */\
struct type **tqe_prev;/* address of previous next element */\
}
#endif /* !TAILQ_ENTRY */


2,事件对应的句柄

SOCKET事件句柄 

    evutil_socket_t ev_fd;

IO事件句柄

/* 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;

PS : 1,IO事件句柄与信号事件句柄通过union方式定义;2,定时器事件是靠时间差比较来监听,所以这里没有定时器事件的句柄


3,event_base指针: 通过该成员变量,event事件可以知道自己注册在哪个event_base

    struct event_base *ev_base;


4,event属性 :

    short ev_events;

/**
 * @name event flags
 *
 * Flags to pass to event_new(), event_assign(), event_pending(), and
 * anything else with an argument of the form "short events"
 */
/**@{*/
/** Indicates that a timeout has occurred.  It's not necessary to pass
 * this flag to event_for new()/event_assign() to get a timeout. */
#define EV_TIMEOUT 0x01
/** Wait for a socket or FD to become readable */
#define EV_READ 0x02
/** Wait for a socket or FD to become writeable */
#define EV_WRITE 0x04
/** Wait for a POSIX signal to be raised*/
#define EV_SIGNAL 0x08
/**
 * Persistent event: won't get removed automatically when activated.
 *
 * When a persistent event with a timeout becomes activated, its timeout
 * is reset to 0.
 */
#define EV_PERSIST 0x10
/** Select edge-triggered behavior, if supported by the backend. */
#define EV_ET       0x20
/**@}*/


5,event标识:

    short ev_flags;

#define EVLIST_TIMEOUT0x01
#define EVLIST_INSERTED 0x02
#define EVLIST_SIGNAL 0x04
#define EVLIST_ACTIVE 0x08
#define EVLIST_INTERNAL 0x10
#define EVLIST_INIT 0x80


6,事件优先级:数值越小,优先级越高,默认为适中

    ev_uint8_t ev_pri;


7,事件对应的回调函数指针及参数

/* allows us to adopt for different types of events */
void (*ev_callback)(evutil_socket_t, short, void *arg);
void *ev_arg;


事件初始化

和event相关的函数有下面几个:

event创建:event_new

event设置:event_setevent_assign

event释放: event_free

其中最核心的是event_assign函数,这里分析其参数的意义,说明事件关注的方面

int event_assign(struct event *ev, struct event_base *base, evutil_socket_t fd, short events, void (*callback)(evutil_socket_t, short, void *), void *arg)

struct event *ev :event事件指针

struct event_base *base : event_base指针

evutil_socket_t fd : 套接口句柄,其他类型事件可以赋值-1

short events : 事件的属性

void (*callback)(evutil_socket_t, short, void *) : 事件处理回调函数指针

void *arg : 事件处理回调函数参数


注册事件

例程中通过event_add函数注册一个定时事件,实际上注册事件是由event_add_internal函数实现,event_add函数会为调用event_add_internal函数增加锁保护。event_add_internal函数通过事件的ev_events属性判断事件类型,从而调用不同函数实现事件注册

对于IO事件的注册由evmap_io_add函数实现

int evmap_io_add(struct event_base *base, evutil_socket_t fd, struct event *ev)

PS :相关的其他几个和IO事件操作函数evmap_io_init,evmap_io_del,evmap_io_active


对于Signal事件的注册由evmap_signal_add函数实现

int evmap_signal_add(struct event_base *base, int sig, struct event *ev)

PS :相关的其他几个和Signal事件操作函数evmap_signal_init,evmap_signal_del,evmap_signal_active


对于定时器事件的注册由event_add_internal参数中的const struct timeval *tv参数决定???


事件驱动

例程通过调用event_base_dispatch函数驱动事件,实际上事件驱动机制是由event_base_loop函数封装实现的。这里需注意event_base结构的成员变量const struct eventop *evsel,这个指针指向eventops数组中的一个元素,根据宏定义选择不同的事件监听机制(例如poll/select/epoll等),这里先不细说。


事件回调

在源代码中一时还没发现是在哪里回调了事件处理函数,换一种途径,通过gdb在例程的时间事件处理函数设置断点跟踪,可以发现事件处理函数是由event_process_active_single_queue函数调用的,关系如下:

(gdb) where
#0  handle_timer (fd=-1, event=1, arg=0xbffff054) at mytimer.c:19
#1  0x0011e248 in event_process_active_single_queue (base=0x804a008, flags=0)
    at event.c:1340
#2  event_process_active (base=0x804a008, flags=0) at event.c:1407
#3  event_base_loop (base=0x804a008, flags=0) at event.c:1604
#4  0x0011f255 in event_base_dispatch (event_base=0x804a008) at event.c:1435
#5  0x080486c4 in main (argc=1, argv=0xbffff164) at mytimer.c:43

原创粉丝点击