event_base是libevent的事务处理框架,负责事件注册、删除等,属于Reactor模式中的Reactor。
event_base结构体
event_base结构体定义于<event_internal.h>中:
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[];
/** 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);
};
其中值得注意的是evsel和evbase。evsel指向了全局变量
static const struct eventop *eventops[]
中的一个元素,而evbase则实际执行多路复用机制的实例化。
如果我们看函数event_base_new_with_config的定义就会比较清晰evsel和evbase之间的关系了:
// <event.c>
1 struct event_base *
event_base_new_with_config(const struct event_config *cfg)
{
...... for (i = ; eventops[i] && !base->evbase; i++) {
if (cfg != NULL) {
/* determine if this backend should be avoided */
if (event_config_is_avoided_method(cfg,
eventops[i]->name))
continue;
if ((eventops[i]->features & cfg->require_features)
!= cfg->require_features)
continue;
} /* also obey the environment variables */
if (should_check_environment &&
event_is_method_disabled(eventops[i]->name))
continue; base->evsel = eventops[i]; base->evbase = base->evsel->init(base);
} ......
}
event_base创建及初始化
创建event_base对象即是创建一个libevent实例。具体的创建函数是event_base_new:
struct event_base *
event_base_new(void)
{
struct event_base *base = NULL;
struct event_config *cfg = event_config_new();
if (cfg) {
base = event_base_new_with_config(cfg);
event_config_free(cfg);
}
return base;
}
由上边程序知道,event_base创建的关键所在是event_base_new_with_config函数,而此函数又通过调用多路调用机制的初始化函数来初始化event_base实例:
// <event.c>
struct event_base *
event_base_new_with_config(const struct event_config *cfg)
{
...... for (i = ; eventops[i] && !base->evbase; i++) {
if (cfg != NULL) {
/* determine if this backend should be avoided */
if (event_config_is_avoided_method(cfg,
eventops[i]->name))
continue;
if ((eventops[i]->features & cfg->require_features)
!= cfg->require_features)
continue;
} /* also obey the environment variables */
if (should_check_environment &&
event_is_method_disabled(eventops[i]->name))
continue; base->evsel = eventops[i]; base->evbase = base->evsel->init(base);
} ......
}
以epoll为例,其对event_base实例的初始化函数为:
static void *
epoll_init(struct event_base *base)
{
int epfd;
struct epollop *epollop; /* Initialize the kernel queue. (The size field is ignored since
* 2.6.8.) */
if ((epfd = epoll_create()) == -) {
if (errno != ENOSYS)
event_warn("epoll_create");
return (NULL);
} evutil_make_socket_closeonexec(epfd); if (!(epollop = mm_calloc(, sizeof(struct epollop)))) {
close(epfd);
return (NULL);
} epollop->epfd = epfd; /* Initialize fields */
epollop->events = mm_calloc(INITIAL_NEVENT, sizeof(struct epoll_event));
if (epollop->events == NULL) {
mm_free(epollop);
close(epfd);
return (NULL);
}
epollop->nevents = INITIAL_NEVENT; if ((base->flags & EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST) != ||
((base->flags & EVENT_BASE_FLAG_IGNORE_ENV) == &&
evutil_getenv("EVENT_EPOLL_USE_CHANGELIST") != NULL))
base->evsel = &epollops_changelist; evsig_init(base); return (epollop);
} struct epollop {
struct epoll_event *events; //并发服务器--02(基于I/O复用——运用epoll技术)
int nevents;
int epfd;
};
接口函数
事件相关的常用接口函数
1. event_new
创建事件(涉及内存分配)。
1. event_add
添加事件到event_base。
2. event_del
将事件从监听列表(pending list)中移除。
3. event_free
释放由event_new创建的事件(内存)。从其定义可看出其与event_del的区别:
void
event_free(struct event *ev)
{
_event_debug_assert_is_setup(ev); /* make sure that this event won't be coming back to haunt us. */
event_del(ev);
_event_debug_note_teardown(ev);
mm_free(ev); }
3. event_callback_fn
事件的回调函数,用于执行具体的I/O操作。其定义如下:
/**
A callback function for an event. It receives three arguments: @param fd An fd or signal
@param events One or more EV_* flags
@param arg A user-supplied argument. @see event_new()
*/
typedef void (*event_callback_fn)(evutil_socket_t, short, void *);
超时和信号事件的特殊接口函数
为了方便对超时和信号事件的处理,libevent特别为它们定义了接口函数(实际是对通用函数的封装)。
超时事件:
/**
@name evtimer_* macros Aliases for working with one-shot timer events */
/**@{*/
#define evtimer_assign(ev, b, cb, arg) \
event_assign((ev), (b), -, , (cb), (arg))
#define evtimer_new(b, cb, arg) event_new((b), -1, 0, (cb), (arg))
#define evtimer_add(ev, tv) event_add((ev), (tv))
#define evtimer_del(ev) event_del(ev)
#define evtimer_pending(ev, tv) event_pending((ev), EV_TIMEOUT, (tv))
#define evtimer_initialized(ev) event_initialized(ev)
/**@}*/
信号事件:
/**
@name evsignal_* macros Aliases for working with signal events
*/
/**@{*/
#define evsignal_add(ev, tv) event_add((ev), (tv))
#define evsignal_assign(ev, b, x, cb, arg) \
event_assign((ev), (b), (x), EV_SIGNAL|EV_PERSIST, cb, (arg))
#define evsignal_new(b, x, cb, arg) \
event_new((b), (x), EV_SIGNAL|EV_PERSIST, (cb), (arg))
#define evsignal_del(ev) event_del(ev)
#define evsignal_pending(ev, tv) event_pending((ev), EV_SIGNAL, (tv))
#define evsignal_initialized(ev) event_initialized(ev)
/**@}*/
事件处理主循环
有待添加