您的位置:首页 > 其它

libevent之event_base

2015-09-22 11:45 387 查看
  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[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);
};


  其中值得注意的是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 = 0; 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 = 0; 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->[b]init[/b](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(32000)) == -1) {
if (errno != ENOSYS)
event_warn("epoll_create");
return (NULL);
}

evutil_make_socket_closeonexec(epfd);

if (!(epollop = mm_calloc(1, 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) != 0 ||
((base->flags & EVENT_BASE_FLAG_IGNORE_ENV) == 0 &&
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), -1, 0, (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)
/**@}*/ 


事件处理主循环

有待添加

参考资料

  libevent源码深度剖析六

  libevent源码深度剖析七
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: