libevent之event_base
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)
/**@}*/
事件处理主循环
有待添加
参考资料
libevent之event_base的更多相关文章
- libevent(四)event_base 2
接上文libevent(三)event_base event_io_map event_list是双向链表,min_heap是小根堆,那event_io_map是什么呢? #ifdef WIN32 # ...
- libevent(三)event_base
libevent能够处理三种事件: I/O.定时器.信号. event_base 统一管理所有事件. struct event_base { const struct eventop *evsel; ...
- libevent源码深度剖析
原文地址: http://blog.csdn.net/sparkliang/article/details/4957667 第一章 1,前言 Libevent是一个轻量级的开源高性能网络库,使用者众多 ...
- libevent入门教程
首先给出官方文档吧: http://libevent.org ,首页有个Programming with Libevent,里面是一节一节的介绍libevent,但是感觉信息量太大了,而且还是英文的- ...
- Libevent源码分析—event_init()
下面开始看初始化event_base结构的相关函数.相关源码位于event.c event_init() 首先调用event_init()初始化event_base结构体 struct event_b ...
- libevent源码剖析
libevent是一个使用C语言编写的,轻量级的开源高性能网络库,使用者很多,研究者也很多.由于代码简洁,设计思想简明巧妙,因此很适合用来学习,提升自己C语言的能力. libevent有这样显著地几个 ...
- libevent(了解)
1 前言 Libevent是一个轻量级的开源高性能网络库,使用者众多,研究者更甚,相关文章也不少.写这一系列文章的用意在于,一则分享心得:二则对libevent代码和设计思想做系统的.更深层次的分析, ...
- libevent网络编程汇总
libevent源码剖析: ========================================================== 1.libevent源码剖析一(序) 2.libeve ...
- libevent源码深度剖析八
libevent源码深度剖析八 ——集成信号处理 张亮 现在我们已经了解了libevent的基本框架:事件管理框架和事件主循环.上节提到了libevent中I/O事件和Signal以及Timer事件的 ...
随机推荐
- ROS新功能包PlotJuggler绘图
http://www.ros.org/news/2017/01/new-package-plotjuggler.html PlotJuggler,一个基于Qt的应用程序,允许用户加载,搜索和绘图数据. ...
- RxJava(十)switchIfEmpty操作符实现Android检查本地缓存逻辑判断
欢迎转载,转载请标明出处: http://blog.csdn.net/johnny901114/article/details/52585912 本文出自:[余志强的博客] switchIfEmpty ...
- JVM远程DEBUG(JPDA )
原理 1. JPDA简介 JPDA(Java Platform Debugger Architecture)为Java平台上的调试器定义了一个标准的体系结构.该体系结构包括3个主要组成部分:JVM T ...
- FORM实现中打开图片,链接,文档(参考自itpub上一篇帖子,整理而来)
FORM实现中打开图片,链接,文档 参考自itpub上一篇帖子,整理而来 1.添加PL程序库D2kwutil.pll 2.主要实现程序 /*过程参数说明: v_application --打开文件的应 ...
- 使用Java正则表达式去掉Double类型的数据后面多余的0
方法 /** * 使用java正则表达式去掉多余的.与0 * @param s * @return */ public static String subZeroAndDot(String s){ i ...
- iOS开发之WKWebView代替UIWebView
前言 Xcode8发布以后,编译器开始不支持IOS7,所以很多应用在适配IOS10之后都不在适配IOS7了,其中包括了很多大公司,网易新闻,滴滴出行等.因此,我们公司的应用也打算淘汰IOS7. 支持到 ...
- 剑指offer面试题3 二维数组中的查找 (java)
注:java主要可以利用字符串的length方法求出长度解决这个问题带来方便 public class FindNum { public static void main(String[] args) ...
- JDBC数据库连接简介(一)
jdbc的由来 odbc(open database connection) 最初各个数据库比如mysql和oracle等,虽然都支持sql,但是他们的连接方式是不一样的,需要按照相应的api来编写不 ...
- Android简易实战教程--第六话《开发一键锁屏应用2·完成》
转载请注明出处:http://blog.csdn.net/qq_32059827/article/details/51885687点击打开链接 上一篇,初步开发了这个应用,功能都有了(见http:// ...
- Linux/Unix--设备类型
在Linux以及所有的Unix系统中,设备被分为以下三种类型: 块设备 字符设备 网络设备 块设备通常写为 blkdev ,它是可以寻址的 ...