libevent之event_base
2015-09-22 11:45
387 查看
event_base是libevent的事务处理框架,负责事件注册、删除等,属于Reactor模式中的Reactor。
其中值得注意的是evsel和evbase。evsel指向了全局变量
中的一个元素,而evbase则实际执行多路复用机制的实例化。
如果我们看函数event_base_new_with_config的定义就会比较清晰evsel和evbase之间的关系了:
由上边程序知道,event_base创建的关键所在是event_base_new_with_config函数,而此函数又通过调用多路调用机制的初始化函数来初始化event_base实例:
以epoll为例,其对event_base实例的初始化函数为:
创建事件(涉及内存分配)。
1. event_add
添加事件到event_base。
2. event_del
将事件从监听列表(pending list)中移除。
3. event_free
释放由event_new创建的事件(内存)。从其定义可看出其与event_del的区别:
3. event_callback_fn
事件的回调函数,用于执行具体的I/O操作。其定义如下:
超时事件:
信号事件:
libevent源码深度剖析七
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源码深度剖析七
相关文章推荐
- ORACLE随机数DBMS_RANDOM包
- [Leetcode]Binary Tree Inorder Traversal
- 同一Activity实例被多次重复创建的解决方法
- C++ 引用
- JSP入门教程之客户端验证、常用输出方式及JSTL基本用法
- 物理引擎中velocity的单位是个什么鬼?
- 物理引擎中velocity的单位是个什么鬼?
- 生活中的MVC模式,一个吃货的理解
- MYSQL启动报1067错误 MySQL服务无法启动 或者Can't create/write to file#sql6e80_1905f7_3.MYI'
- linux shell 管道命令(pipe)使用及与shell重定向区别
- 前景目标检测方法(总结)
- 一千行MySQL学习笔记(一)
- 物理引擎中velocity的单位是个什么鬼?
- 学习网址记录
- 20150922
- mysql的相关问题处理
- Sending redirect to another servlet/JSP without loosing the request parameters
- xcode7,ios9 部分兼容设置
- Hdu 5452 Minimum Cut (2015 ACM/ICPC Asia Regional Shenyang Online) dfs + LCA
- 黑马程序员——异常处理全过程:不怕一万,就怕万一