修改记录:
3-29 初稿
介绍完类型与变量之后,就可以开始看程序的主轴了。我们从使用event-test.c入手可以看到的是:(略去之前创建命名管道和socket)
/* Initalize the event library */
event_init();
/* Initalize one event */
event_set(&evfifo, socket, EV_READ, fifo_read, &evfifo);
/* Add it to the active events, without a timeout */
event_add(&evfifo, NULL);
event_dispatch();
首先是
event_init进行了全体初始化。
在0.1中这个函数很简单,就是把之前的四个全局队列头结点置空。
在0.2中,除了初始化队列之外,选择第一个系统支持的函数处理程序,其顺序是kqueue, event_ports, epoll, poll, select(存疑。没去看现在的顺序是怎样,但肯定不是随机选择的)
在找到了合适的程序支持,比如发现了select函数可以使用之后,把select的结构体selectop的地址传给evbase。selectop的结构体是
struct selectop {
int event_fds; /* fd_set最大值 */
int event_fdsz; //fd_set的大小
fd_set *event_readset;
fd_set *event_writeset;
} sop;
其次是用
event_set初始化一个事件
event_set(&evfifo, socket, EV_READ, fifo_read, &evfifo);
这一步也很简单,其实就是把socket以及事件、标志通通给结构体evfifo赋值,没有其它东西。
再次是用
event_add给之前初始化的事件配置定时器
第一步先看event_add之时传入的时间是否为空,如果不为空的话已现在的时间为准,并加上传入的时间作为结束时间。
第二步是看event中的标志是否是EVLIST_TIMEOUT,如果是EVLIST_TIMEOUT则先从timequeue中移除此事件,这个标志
第三步是从头遍历timequeue,按照从近到远的顺序找到event该被插入的位置。
第四步是给event挂上EVLIST_TIMEOUT的标志
第五步是判断libevent是否正在循环中,如果在而且标志了EVLIST_ADD,则返回;否则插进addqueue队尾,并标志EVLIST_ADD。可以看出EVLIST_ADD表明此event是否已经added进addqueue。我们可以把addqueue理解成待处理事件。如果不在循环中,则调用
event_add_post(ev)——
在0.1中,事件被插入队列后会被标记上EVLIST_READ或者EVLIST_WRITE;
而在0.2中,readqueue和writequeue被合并成了eventqueue,并统一标记为EVLIST_INSERTED
注:LOG_DBG是log.h中的一个宏,用于记录日志
最后是进入处理循环
event_dispatch
//这个是0.2版本的处理循环
while (1) {
timeout_next(&tv);
event_inloop = 1;
res = evsel->dispatch(evbase, &tv);
event_inloop = 0;
if (res == -1)
return (-1);
maxfd = 0;
for (ev = TAILQ_FIRST(&addqueue); ev;
ev = TAILQ_FIRST(&addqueue)) {
TAILQ_REMOVE(&addqueue, ev, ev_add_next);
ev->ev_flags &= ~EVLIST_ADD;
event_add_post(ev);
if (ev->ev_fd > maxfd)
maxfd = ev->ev_fd;
}
if (evsel->recalc(evbase, maxfd) == -1)
return (-1);
timeout_process();
}
dispatch是重中之重,里面进行的操作如下
- 重新计算fd_set也就是readset或者sop->event_readset变量所需要的空间大小,并把fd_set清零。
- 把readqueue与writequeue中的所有事件的套接字放入fd_set中。
- 从timequeue队列中取出第一个定时器到时时间tv。在tv时间之前select读写的fd_set
- 锁上循环区(event_inloop=1),一一取readqueue或eventqueue的事件,先把这些事件从所有队列中移除之后,在一一调用各事件的回调函数即fifo_read。传入fifo_read的参数包括该事件的指针。fifo_read中再次调用event_set把event加入队列中,下次循环便会继续监听此事件。
- 解锁循环区(event_inloop=0),把addqueue中的event全部取出来,放进readqueue或者0.2版本中的eventqueue
- 调用recalc重新计算fd_set,也就是2中的步骤
- 最后,对照当前时间,把timequeue队列中还没有超时的事件取出来调用回调函数。
注:0.1和0.2版本的处理顺序有所不同(在进入循环区前后所调用的东西不同。0.1是select之后再循环,0.2反之),但基本上一致
至此除event_pending外的主要函数全部介绍完毕(event_pending主要用来检查某个事件是否已被标记在计划中)
总结:
libevent0.x主要使用了Tail Queue这一数据结构存放系统各种待处理的事件队列。(现在觉得这种类型蛮奇葩的,用双向链表应该也是可以,不知Niels当初有何考量)其中一个事件(event)包含了对应的套接字和当时队列中下一个事件的指针。
每次在回调之后,都需要重新把事件加入到队列中,这是因为每次select的对象都是队列。
在0.1的一个循环中,程序先处理readqueue再处理writequeue。在0.2中,libevent把read和write一视同仁,都合并成了eventqueue
分享到:
相关推荐
为方便阅读,把blog上的libevent源码深度剖析系列文章整合成一个pdf。
本文将对libevent源码进行分析,深入理解其实现原理以及关键的数据结构和函数接口。我们首先从libevent源码的整体架构开始,然后详细介绍一些重要的组件和它们的实现方式。 1. 开篇 在分析libevent源码之前,有必要...
libevent的原理和源码分析对于深入理解网络编程的底层机制至关重要。 首先,libevent的核心是其事件模型。它基于事件驱动编程模型,这种模型能够高效地处理大量并发连接。当有事件发生时,libevent会调用相应的回调...
在“libevent v0.1”中,主要包含以下关键知识点: 1. **事件基类(Event Base)**:每个libevent实例都有一个事件基类,它是所有事件处理的入口点。开发者可以通过它来注册事件、调度事件循环和取消事件。 2. **...
在深入Libevent源码分析之前,需要了解它的核心概念,主要包括事件循环、事件处理器、IO事件、定时器事件、信号事件等。事件循环是Libevent的中枢,它在后台运行,检测事件源的变化,并触发相应的事件处理器。事件...
Libevent 源码解析 Libevent 是一个高性能的事件驱动库,广泛应用于网络编程和高性能服务器开发中。下面是对 Libevent 源码的深入剖析,涵盖了其架构设计、事件处理机制、Reactor 模式、事件循环、IO multiplexing...
6. **源码解析**:深入阅读libevent的源码,可以理解其内部实现细节,如事件调度算法、多线程支持和异步I/O处理等。 7. **性能优化**:libevent提供了很多配置选项来优化性能,例如选择合适的事件模型、使用多线程...
libevent-1.0c.tar.gz [GPG Sig] - Release 2005-04-03 Bug fixes for Windows, Solaris and improved logging interface. libevent-1.0b.tar.gz [GPG Sig] - Release ...libevent-0.1.tar.gz - Release 2000-11-14
《深入解析libevent-1.0b:多线程网络通信库的...通过理解和掌握libevent的源码,开发者能够构建出更高效、可靠的网络服务。无论是对初学者还是经验丰富的程序员,libevent都是一个值得深入学习和研究的优秀开源项目。
通过深入理解和使用libevent源码,开发者可以更好地定制自己的网络应用,实现高效、稳定的服务。 总结,libevent是一个强大的工具,它提供了事件驱动的编程模型,适用于处理大量并发连接。通过理解并熟练运用...
libevent库,文字版,很清晰,附带libevent参考手册(中文版) libevent源码深度剖析,根据libevent开源代码框架进行剖析,很不错值得学习借鉴,还有libevent中C语言的功底值得学习揣摩!
跟网络无关的,libevent也有一些缓冲区管理的函数,而且是c风格的函数,实用性不是太大。libevent没有提供缓存的函数。 虽然libevent实用上的价值不大,但它提供的接口形式还是不错的,实现类似的lib的时候仍然...
《libevent源码深度剖析》一书主要针对的是libevent这一开源库进行深入解析,旨在帮助读者理解并掌握libevent的核心原理与应用。libevent是一个事件通知库,它允许程序员以一种统一的方式来处理各种类型的I/O事件和...
**二、libevent的主要功能** 1. **网络I/O**:libevent提供了对TCP、UDP、UNIX域套接字等协议的支持,可以方便地进行网络通信。 2. **定时器**:通过`event_base_new()`创建事件基后,可以使用`event_new()`创建...
《libevent参考手册(中文版)》和《libevent源码深度剖析》是两本针对libevent库的重要参考资料。libevent是一个开源的事件通知库,它使得开发者能够编写高性能、可扩展的网络服务器或者客户端应用。这个库的核心...
你可以从libevent的官方网站获取源码,并按照官方的编译指南在VS2008环境中编译。编译完成后,你会得到.lib和.dll文件,这些都是你在项目中链接libevent库所必需的。 在创建客户端和服务端 demo 时,我们通常会涉及...
libevent-1.0d.tar.gz [GPG Sig] - Release 2005-04-22 Several minor bug fixes and building of shared libraries. libevent-1.0c.tar.gz [GPG Sig] - Release 2005-04...libevent-0.1.tar.gz - Release 2000-11-14
libevent-1.0e.tar.gz [GPG Sig] - Release 2005-04-26 Important fix to bug in poll implementation introduced in 1.0d. libevent-1.0d.tar.gz [GPG Sig] - Release ...libevent-0.1.tar.gz - Release 2000-11-14
epoll反应堆 libevent.c核心源码