Libevent源码分析—event_add()
event_add()
int
event_add(struct event *ev, const struct timeval *tv)
{
struct event_base *base = ev->ev_base; //event所属的event_base
const struct eventop *evsel = base->evsel; //event_base的I/O多路复用机制
void *evbase = base->evbase; //event_base的I/O多路复用机制
int res = ;
//DEBUG log.h
event_debug((
"event_add: event: %p, %s%s%scall %p",
ev,
ev->ev_events & EV_READ ? "EV_READ " : " ",
ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",
tv ? "EV_TIMEOUT " : " ",
ev->ev_callback));
assert(!(ev->ev_flags & ~EVLIST_ALL));
/*
* prepare for timeout insertion further below, if we get a
* failure on any step, we should not change any state.
*/
//如果传入了超时时间并且event不再time小根堆上,则在小根堆上预留一个位置
//以保证如果后面有步骤失败,不会改变初始状态,保证是个原子操作
if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {
if (min_heap_reserve(&base->timeheap, //min_heap.h
+ min_heap_size(&base->timeheap)) == -)
return (-); /* ENOMEM == errno */
}
//如果event不在已注册链表或活跃链表中,
//则调用evsel->add()注册event事件到I/O多路复用监听的事件上
if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&
!(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
res = evsel->add(evbase, ev); //将event注册到监听事件上
//注册监听事件成功,则将event注册到已注册事件链表上
if (res != -)
event_queue_insert(base, ev, EVLIST_INSERTED); //插入
}
/*
* we should change the timout state only if the previous event
* addition succeeded.
*/
//前面操作都成功情况下,才能执行下面步骤
//改变超时状态
if (res != - && tv != NULL) {
struct timeval now;
/*
* we already reserved memory above for the case where we
* are not replacing an exisiting timeout.
*/
//EVLIST_TIMEOUT表明event已在定时器堆中
//则删除旧的定时器
if (ev->ev_flags & EVLIST_TIMEOUT)
event_queue_remove(base, ev, EVLIST_TIMEOUT); //移除
/* Check if it is active due to a timeout. Rescheduling
* this timeout before the callback can be executed
* removes it from the active list. */
//如果事件是由于超时而变成活跃事件
//则从活跃事件链表中删除
if ((ev->ev_flags & EVLIST_ACTIVE) &&
(ev->ev_res & EV_TIMEOUT)) {
/* See if we are just active executing this
* event in a loop
*/
if (ev->ev_ncalls && ev->ev_pncalls) {
/* Abort loop */
*ev->ev_pncalls = ; //调用次数清0
}
//从活跃事件链表移除
event_queue_remove(base, ev, EVLIST_ACTIVE); //移除
}
gettime(base, &now);
evutil_timeradd(&now, tv, &ev->ev_timeout); //为event添加超时时间
event_debug((
"event_add: timeout in %ld seconds, call %p",
tv->tv_sec, ev->ev_callback));
//将event插入到小根堆中
event_queue_insert(base, ev, EVLIST_TIMEOUT); //插入
}
return (res);
}
event_queue_insert()
void
event_queue_insert(struct event_base *base, struct event *ev, int queue)
{
//如果event已经在活跃链表中,则返回;否则,出错
if (ev->ev_flags & queue) {
/* Double insertion is possible for active events */
if (queue & EVLIST_ACTIVE)
return;
event_errx(, "%s: %p(fd %d) already on queue %x", __func__,
ev, ev->ev_fd, queue);
}
if (~ev->ev_flags & EVLIST_INTERNAL)
base->event_count++; //增加注册事件数
ev->ev_flags |= queue; //改变event状态
switch (queue) { //根据不同的输入参数队列,选择在不同的事件集合中插入
case EVLIST_INSERTED: //I/O或Signal事件
TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next); //在已注册事件链表插入
break;
case EVLIST_ACTIVE: //活跃事件
base->event_count_active++; //增加活跃事件数
TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri], //在活跃事件链表插入
ev,ev_active_next);
break;
case EVLIST_TIMEOUT: { //定时器事件
min_heap_push(&base->timeheap, ev); //在小根堆插入
break;
}
default:
event_errx(, "%s: unknown queue %x", __func__, queue);
}
}
event_queue_remove()
void
event_queue_remove(struct event_base *base, struct event *ev, int queue)
{
if (!(ev->ev_flags & queue))
event_errx(, "%s: %p(fd %d) not on queue %x", __func__,
ev, ev->ev_fd, queue);
if (~ev->ev_flags & EVLIST_INTERNAL)
base->event_count--;
ev->ev_flags &= ~queue;
switch (queue) {
case EVLIST_INSERTED: //I/O、Signal事件
TAILQ_REMOVE(&base->eventqueue, ev, ev_next);
break;
case EVLIST_ACTIVE: //活跃事件
base->event_count_active--;
TAILQ_REMOVE(base->activequeues[ev->ev_pri],
ev, ev_active_next);
break;
case EVLIST_TIMEOUT: //定时器事件
min_heap_erase(&base->timeheap, ev);
break;
default:
event_errx(, "%s: unknown queue %x", __func__, queue);
}
}
event_del()
int
event_del(struct event *ev)
{
struct event_base *base;
const struct eventop *evsel;
void *evbase;
event_debug(("event_del: %p, callback %p",
ev, ev->ev_callback));
/* An event without a base has not been added */
if (ev->ev_base == NULL)
return (-);
base = ev->ev_base;
evsel = base->evsel;
evbase = base->evbase;
assert(!(ev->ev_flags & ~EVLIST_ALL));
/* See if we are just active executing this event in a loop */
//计数清0
if (ev->ev_ncalls && ev->ev_pncalls) {
/* Abort loop */
*ev->ev_pncalls = ;
}
//根据event不同的状态,从相应的event集合中删除
if (ev->ev_flags & EVLIST_TIMEOUT)
event_queue_remove(base, ev, EVLIST_TIMEOUT);
if (ev->ev_flags & EVLIST_ACTIVE)
event_queue_remove(base, ev, EVLIST_ACTIVE);
if (ev->ev_flags & EVLIST_INSERTED) {
event_queue_remove(base, ev, EVLIST_INSERTED);
return (evsel->del(evbase, ev)); //从I/O多路复用监听的事件中删除
}
return ();
}
Libevent源码分析—event_add()的更多相关文章
- 【转】libevent源码分析
libevent源码分析 转自:http://www.cnblogs.com/hustcat/archive/2010/08/31/1814022.html 这两天没事,看了一下Memcached和l ...
- Libevent源码分析 (1) hello-world
Libevent源码分析 (1) hello-world ⑨月份接触了久闻大名的libevent,当时想读读源码,可是由于事情比较多一直没有时间,现在手头的东西基本告一段落了,我准备读读libeven ...
- libevent源码分析:event_add、event_del
event_add.event_del两个函数分别是使event生效和失效的,下面就来看一下两个函数的实现. event_add int event_add(struct event *ev, con ...
- Libevent源码分析系列【转】
转自:https://www.cnblogs.com/zxiner/p/6919021.html 1.使用libevent库 源码那么多,该怎么分析从哪分析呢?一个好的方法就是先用起来,会用了 ...
- Libevent源码分析系列
1.使用libevent库 源码那么多,该怎么分析从哪分析呢?一个好的方法就是先用起来,会用了,然后去看底层相应的源码,这样比较有条理,自上向下掌握.下面用libevent库写个程序,每隔1秒 ...
- libevent源码分析
这两天没事,看了一下Memcached和libevent的源码,做个小总结. 1.入门 1.1.概述Libevent是一个用于开发可扩展性网络服务器的基于事件驱动(event-driven)模型的网络 ...
- libevent源码分析一--io事件响应
这篇文章将分析libevent如何组织io事件,如何捕捉事件的发生并进行相应的响应.这里不会详细分析event与event_base的细节,仅描述io事件如何存储与如何响应. 1. select l ...
- Libevent源码分析—event_base_dispatch()
我们知道libevent是一个Reactor模式的事件驱动的网络库. 到目前为止,我们已经看了核心的event和event_base结构体的源码,看了初始化这两个结构体的源码,看了注册event的 ...
- libevent源码分析二--timeout事件响应
libevent不仅支持io事件,同时还支持timeout事件与signal事件,这篇文件将分析libevent是如何组织timeout事件以及如何响应timeout事件. 1. min_heap ...
随机推荐
- Leetcode 371.两整数之和 By Python
不使用运算符 + 和 - ,计算两整数 a .b 之和. 示例 1: 输入: a = 1, b = 2 输出: 3 示例 2: 输入: a = -2, b = 3 输出: 1 思路 比如\(5+6=1 ...
- List does not exist. The page you selected contains a list that does not exist. It may have been deleted by another user
当我在subsite里点击"Add a document",报这个错,后来一看event log: 在AAM里加上一条: 问题搞定:
- SQLITE在IIS中使用问题
在WEB中使用这个数据库时,System.Data.SQLite.dll 这个经常会出问题 主要是版本问题,sqlite.DLL的版本要和Framework版本匹配 这是下载地址 http://www ...
- suoi63 树与路径 (倍增lca)
发现对于某一个点它向上发的一条边,它被经过的次数就是这个点子树数量*不是它子树的数量 那就维护一个前缀和,然后每次拿两个端点和它们的lca的值加一加减一减,再乘上加上的值,就是这次修改后答案的增量 ( ...
- AAD Service Principal获取azure user list (Microsoft Graph API)
本段代码是个通用性很强的sample code,不仅能够操作AAD本身,也能通过Azure Service Principal的授权来访问和控制Azure的订阅资源.(Azure某种程度上能看成是两个 ...
- Raspbian首次安装后无法使用SSH链接
使用Putty连接树莓派,出现Network Error:Connection Refused 新版的Raspbian系统默认禁用了SSH. 解决方法:在/boot分区创建名为"ssh&qu ...
- Some Interesting Problems(持续更新中)
这种题目详解,是“一日一测”与“一句话题解”栏目所无法覆盖的,可能是考试用题,也可能是OJ题目.常常非常经典,可以见微知著.故选其精华,小列如下. T1:fleet 给定一个序列,询问[L,R]间有多 ...
- 洛谷P4112 最短不公共子串
题意: 下面,给两个小写字母串A,B,请你计算: (1) A的一个最短的子串,它不是B的子串 (2) A的一个最短的子串,它不是B的子序列 (3) A的一个最短的子序列,它不是B的子串 (4) A的一 ...
- windows & gcc & mingw & mysy 编译 openssl
今天有一个项目需要使用到 https, 以前一直用的都是http请求, 用 socket() 实现 https 请求我还真是头一回遇到. 先网上搜索了一下相关资料,明白了 https 相比较 http ...
- 02-css的选择器
css的选择器:1.基本选择器 2.高级选择器 基本选择器包含: 1.标签选择器 标签选择器可以选中所有的标签元素,比如div,ul,li ,p等等,不管标签藏的多深,都能选中,选中的是所有的,而不是 ...