libevent使用struct event来表示一个事件。
#define evutil_socket_t int #define ev_uint8_t unsigned char #define ev_io_timeout _ev.ev_io.ev_timeout // 存储绝对时间 struct event { evutil_socket_t ev_fd; // 事件相关描述符 short ev_events; // 事件类型 short ev_flags; // 事件状态 ev_uint8_t ev_closure; // 事件结束类型 ev_uint8_t ev_pri; // 事件优先级,越小优先级越高 struct timeval ev_timeout; // 存储相对时间 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; /* for managing timeouts */ union { TAILQ_ENTRY(event) ev_next_with_common_timeout; int min_heap_idx; // 事件在最小堆中的index } ev_timeout_pos; void (*ev_callback)(evutil_socket_t, short, void *arg); // 事件回调函数 void *ev_arg; // 存储事件回调函数参数arg struct event_base *ev_base; ... };
具体字段含义不再细说,可参考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) { if (!base) base = current_base; _event_debug_assert_not_added(ev); ev->ev_base = base; ev->ev_callback = callback; ev->ev_arg = arg; ev->ev_fd = fd; ev->ev_events = events; ev->ev_res = 0; ev->ev_flags = EVLIST_INIT; ev->ev_ncalls = 0; ev->ev_pncalls = NULL; if (events & EV_SIGNAL) { if ((events & (EV_READ|EV_WRITE)) != 0) { event_warnx("%s: EV_SIGNAL is not compatible with " "EV_READ or EV_WRITE", __func__); return -1; } ev->ev_closure = EV_CLOSURE_SIGNAL; } else { if (events & EV_PERSIST) { evutil_timerclear(&ev->ev_io_timeout); ev->ev_closure = EV_CLOSURE_PERSIST; } else { ev->ev_closure = EV_CLOSURE_NONE; } } min_heap_elem_init(ev); if (base != NULL) { /* by default, we put new events into the middle priority */ ev->ev_pri = base->nactivequeues / 2; } _event_debug_note_setup(ev); return 0; }
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 /**@}*/
对于定时器事件,不需要设置EV_TIMEOUT。
ev_flags,事件状态
#define EVLIST_TIMEOUT 0x01 // 事件位于最小堆 #define EVLIST_INSERTED 0x02 // 事件位于总事件队列 #define EVLIST_SIGNAL 0x04 // #define EVLIST_ACTIVE 0x08 // 事件位于激活队列 #define EVLIST_INTERNAL 0x10 #define EVLIST_INIT 0x80 // 事件初始状态
event_add流程
信号事件的event_add过程有点复杂,可以参考
libevent(七)信号事件监听