- 浏览: 1401068 次
- 性别:
- 来自: 火星
文章分类
最新评论
-
aidd:
内核处理time_wait状态详解 -
ahtest:
赞一下~~
一个简单的ruby Metaprogram的例子 -
itiProCareer:
简直胡说八道,误人子弟啊。。。。谁告诉你 Ruby 1.9 ...
ruby中的类变量与类实例变量 -
dear531:
还得补充一句,惊群了之后,数据打印显示,只有一个子线程继续接受 ...
linux已经不存在惊群现象 -
dear531:
我用select试验了,用的ubuntu12.10,内核3.5 ...
linux已经不存在惊群现象
最近刚刚一个项目自己用libevent,因此这几天又把libevent的代码拿出来翻了下,当初看的时候有些似是而非的东西,这次是基本没有了。这篇也算是前面几篇libevent的blog的补充了。
我们这里用select来讲,其他的事件驱动器都相似。
我们来看,其中activequeues我们知道是表示激活的事件队列.这里libevent的处理是,select被唤醒后,调用event_active方法,将此事件插入到activequeues队列中,这里这个队列的实现是用tail queue。然后libevent会执行event_process_active方法,从而从激活队列中,依次执行所激活的事件。这里这个队列之所以是一个指针的指针,是因为,libevent中事件还分为优先级,这样每个优先级都有一个activequeues队列。
记下来我们再来看定时器的实现,libevent会在每次执行循环时,从优先级队列中取出来最小的那个时间,然后将它加入到select中,从而实现定时器。而在每次select超时退出后,libevent会从小到大取出超时时间(直到大于当前时间),每次和当前时间比较,如果已超时,则会从优先级队列中删除此节点,然后将此超时事件加入到激活队列中。
接下来我们来看相关代码。
来看timeout_next方法
其中event_active是通过event_queue_insert来插入到激活队列的,因此我们来看这个函数:
最后来看执行激活队列
struct event_base { const struct eventop *evsel; void *evbase; int event_count; /* counts number of total events */ int event_count_active; /* counts number of active events */ int event_gotterm; /* Set to terminate loop */ int event_break; /* Set to terminate loop immediately */ /* active event management */ struct event_list **activequeues; int nactivequeues; /* signal handling info */ struct evsignal_info sig; struct event_list eventqueue; struct timeval event_tv; struct min_heap timeheap; struct timeval tv_cache; };
我们这里用select来讲,其他的事件驱动器都相似。
我们来看,其中activequeues我们知道是表示激活的事件队列.这里libevent的处理是,select被唤醒后,调用event_active方法,将此事件插入到activequeues队列中,这里这个队列的实现是用tail queue。然后libevent会执行event_process_active方法,从而从激活队列中,依次执行所激活的事件。这里这个队列之所以是一个指针的指针,是因为,libevent中事件还分为优先级,这样每个优先级都有一个activequeues队列。
记下来我们再来看定时器的实现,libevent会在每次执行循环时,从优先级队列中取出来最小的那个时间,然后将它加入到select中,从而实现定时器。而在每次select超时退出后,libevent会从小到大取出超时时间(直到大于当前时间),每次和当前时间比较,如果已超时,则会从优先级队列中删除此节点,然后将此超时事件加入到激活队列中。
接下来我们来看相关代码。
int event_base_loop(struct event_base *base, int flags) { .................................................. timeout_correct(base, &tv); tv_p = &tv; ///判断是否有激活事件,如果没有的话我们则会从优先级队列中取出最小的那个时间。也就是离现在最近的那个超时时间。 if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK)) { ///下面会介绍这个函数 timeout_next(base, &tv_p); } else { /* * if we have active events, we just poll new events * without waiting. */ evutil_timerclear(&tv); } ......................................................... /* clear time cache */ base->tv_cache.tv_sec = 0; ///调用相关事件驱动引擎的dispatch方法,这个方法中会将已激活的事件加入到激活队列,这里看到tv_p也就是上面取到的超时时间被传入到dispatch。 res = evsel->dispatch(base, evbase, tv_p); if (res == -1) return (-1); gettime(base, &base->tv_cache); ///处理超时事件,将所有已超时的事件加入到激活队列。下面我们会介绍这个函数 timeout_process(base); if (base->event_count_active) { ///执行激活事件队列 event_process_active(base); if (!base->event_count_active && (flags & EVLOOP_ONCE)) ///判断是否退出。 done = 1; } else if (flags & EVLOOP_NONBLOCK) done = 1; } /* clear time cache */ base->tv_cache.tv_sec = 0; event_debug(("%s: asked to terminate loop.", __func__)); return (0); }
来看timeout_next方法
static int timeout_next(struct event_base *base, struct timeval **tv_p) { struct timeval now; struct event *ev; struct timeval *tv = *tv_p; ///取出最小的那个时间。 if ((ev = min_heap_top(&base->timeheap)) == NULL) { /* if no time-based events are active wait for I/O */ *tv_p = NULL; return (0); } ///得到当前的时间。 if (gettime(base, &now) == -1) return (-1); ///已超时则直接退出 if (evutil_timercmp(&ev->ev_timeout, &now, <=)) { evutil_timerclear(tv); return (0); } ///将定时器事件减去当前时间,也就是超时时间付给tv。 evutil_timersub(&ev->ev_timeout, &now, tv); assert(tv->tv_sec >= 0); assert(tv->tv_usec >= 0); event_debug(("timeout_next: in %ld seconds", tv->tv_sec)); return (0); }
void timeout_process(struct event_base *base) { .............................................. gettime(base, &now); ///开始遍历此优先级队列 while ((ev = min_heap_top(&base->timeheap))) { ///如果比当前时间大,则说明还没到超时时间因此直接退出。 if (evutil_timercmp(&ev->ev_timeout, &now, >)) break; ///删除此超时事件,因此我们在使用定时器时,需要我们每次进入定时器后,再次add此事件。 /* delete this event from the I/O queues */ event_del(ev); event_debug(("timeout_process: call %p", ev->ev_callback)); ///加入激活队列。 event_active(ev, EV_TIMEOUT, 1); } }
其中event_active是通过event_queue_insert来插入到激活队列的,因此我们来看这个函数:
void event_queue_insert(struct event_base *base, struct event *ev, int queue) { .............................................. ev->ev_flags |= queue; switch (queue) { ///这个主要用来保存所有的激活以及非激活队列,也就是eventqueue. case EVLIST_INSERTED: 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(1, "%s: unknown queue %x", __func__, queue); } }
最后来看执行激活队列
static void event_process_active(struct event_base *base) { struct event *ev; struct event_list *activeq = NULL; int i; short ncalls; ///取出相应的激活队列 for (i = 0; i < base->nactivequeues; ++i) { if (TAILQ_FIRST(base->activequeues[i]) != NULL) { activeq = base->activequeues[i]; break; } } assert(activeq != NULL); ///开始遍历上面取出的队列 for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) { if (ev->ev_events & EV_PERSIST) ///如果有persist标志,则只从激活队列中移除此事件,否则则从全局事件列表中删除此事件。 event_queue_remove(base, ev, EVLIST_ACTIVE); else event_del(ev); /* Allows deletes to work */ ncalls = ev->ev_ncalls; ev->ev_pncalls = &ncalls; ///每个事件的回调函数的调用次数 while (ncalls) { ncalls--; ev->ev_ncalls = ncalls; ///调用回调函数 (*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg); if (event_gotsig || base->event_break) return; } } }
发表评论
-
gcc的几个自动优化
2009-11-10 00:44 5145我的gcc版本是4.4.1 先来看const和define以 ... -
gdb学习笔记(一)
2009-10-17 14:11 11733这里只是一个摘要。具体的细节还需要去看manual。 1 ... -
ydb的内存模型
2009-09-06 18:02 1986阿宝同学推荐了这个东 ... -
glibc中strlen的实现
2009-08-04 09:10 4526glibc中的strlen的实现主要的思想就是每次检测4个字节 ... -
libevent源码浅析(三)
2009-03-17 00:08 4587这次我们来看libevent的信号的处理。 在libeven ... -
libevent源码浅析(二)
2009-02-22 00:11 4077我们来看下libevent的定时器的实现 在libevent ... -
libevent源码浅析(一)
2009-02-14 13:23 7440这里分析的是libevent-1.4.9。 PS:前面还看了 ... -
linux下的time处理
2009-01-04 18:02 6849在内核中有3个不同的时间: Wall time(real t ... -
libev简单使用介绍
2008-12-30 09:52 11558更详细的用法请看他的 ... -
linux下的elf结构
2008-12-12 00:20 5188可以看到链接器和加载器看待elf是完全不同的,链接器看到 ... -
php的c扩展
2008-12-07 18:24 4571在php中最核心的一个数据结构就是这个: typedef u ... -
linux下的管理内存相关的函数
2008-11-27 00:56 4486malloc的实现,在linux下的实现是这样的,当所需 ... -
linux下的数据对齐
2008-11-25 12:15 3649数据对齐也就是通过硬件来估算在数据的地址和内存块之间的联系。当 ... -
linux下检测ip冲突
2008-11-16 20:18 8181原理其实很简单,那就是广播一个arp包,然后recv,如果没有 ... -
今天碰到的一个问题
2008-10-29 22:33 1266将位图用 bmptopnm 转成pcl6的打印语言,然后直接c ... -
ftruncate和msync
2008-10-23 22:10 3503int ftruncate(int fd, off_t le ... -
GUN C正则表达式
2008-09-25 23:47 6193最近项目中要处理文本,因此就用了gun的正则表达式,它是pos ... -
看代码看的头晕
2008-09-06 01:04 1873最近工作需要在看ghostscript的代码,看得我头晕眼花, ... -
[转帖]MISRA--作为工业标准的C编程规范
2008-08-21 13:19 2836本文档转贴自孟岩的blog ... -
代码大全读书笔记1
2008-04-26 19:16 3825这么好的书,觉得写点东西,记录一下比较好。 4.1选择编程语 ...
相关推荐
为方便阅读,把blog上的libevent源码深度剖析系列文章整合成一个pdf。
本文将对libevent源码进行分析,深入理解其实现原理以及关键的数据结构和函数接口。我们首先从libevent源码的整体架构开始,然后详细介绍一些重要的组件和它们的实现方式。 1. 开篇 在分析libevent源码之前,有必要...
在深入Libevent源码分析之前,需要了解它的核心概念,主要包括事件循环、事件处理器、IO事件、定时器事件、信号事件等。事件循环是Libevent的中枢,它在后台运行,检测事件源的变化,并触发相应的事件处理器。事件...
libevent库,文字版,很清晰,附带libevent参考手册(中文版) libevent源码深度剖析,根据libevent开源代码框架进行剖析,很不错值得学习借鉴,还有libevent中C语言的功底值得学习揣摩!
Libevent 源码解析 Libevent 是一个高性能的事件驱动库,广泛应用于网络编程和高性能服务器开发中。下面是对 Libevent 源码的深入剖析,涵盖了其架构设计、事件处理机制、Reactor 模式、事件循环、IO multiplexing...
libevent源码深度剖析
《libevent参考手册(中文版)》和《libevent源码深度剖析》是两本针对libevent库的重要参考资料。libevent是一个开源的事件通知库,它使得开发者能够编写高性能、可扩展的网络服务器或者客户端应用。这个库的核心...
《libevent源码深度剖析》 libevent是一个高度优化的事件通知库,广泛应用于网络编程,尤其是服务器端的高性能设计。它提供了一种抽象层,允许程序员以一致的方式处理各种类型的事件,包括文件描述符(如套接字)的...
3. **事件类型**:Libevent支持四种基本事件类型:读事件、写事件、信号事件和定时事件。读事件用于检测文件描述符是否有可读数据,写事件检测是否有可写空间,信号事件处理操作系统信号,定时事件则用于设置超时或...
**libevent库源码详解** libevent是一个高度可移植、事件驱动的网络库,它能够帮助程序员处理大量的并发连接,并且有效地利用系统资源。在2.1.8stable版本中,libevent提供了丰富的功能和优化,使其成为开发高性能...
标题中的“jm源码”和“libevent源码”指的是两个知名的开源项目,分别是JM(可能是Java Microservices的简称)和Libevent。这两个组件在IT领域,尤其是网络编程和服务器开发中扮演着重要角色。 首先,让我们深入...
libevent 源码深度剖析.pdf libevent 源码 深度 剖析 pdf
这个“Libevent源码和资料合集”包含了Libevent的核心源代码以及相关的学习资源,对于深入理解和使用Libevent至关重要。 Libevent 的主要功能是通过事件驱动模型来管理非阻塞I/O。它支持多种事件模型,包括epoll...
《libevent源码分析1》 在深入探讨libevent的源码之前,我们先来了解一下这个库的基本情况。libevent是一个高度可扩展的事件通知库,它用于编写高性能、高并发的网络服务器。它的核心功能是提供了一种高效的方式来...
**四、libevent 库文件分析** 在解压后的`libevent`文件中,通常包含以下内容: 1. `include/` 目录:包含头文件,如`event.h`、`event_config.h`等,定义了`libevent`的接口。 2. `src/` 目录:包含了`libevent`...