`
lobin
  • 浏览: 425484 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

libevent: 源代码分析-事件分发

 
阅读更多

libevent事件分发由event_dispatch函数负责处理。

首先是要调用struct event_base实例的evsel成员的dispatch函数,这个dispatch函数根据选择的不同事件处理机制,调用对应的dispatch函数,比如epoll, dispatch函数对应应该是epoll_dispatch,poll对应应该是poll_dispatch,select对应应该是select_dispatch,/dev/poll对应应该是devpoll_dispatch,kqueue对应应该是kq_dispatch,端口对应应该evport_dispatch。虽然名字理解起来为“分发”,它们其实主要就是轮训触发的“事件”。这里的“事件”应该理解为IO事件更准确,这个IO事件是个比较抽象的概念,且不同的事件处理机制中,有些是“名副其实”的事件驱动的,如epoll,poll,有些并不那么“名副其实”,如select,我们轮训的其实是fd_set。

 

调用struct event_base实例的evsel成员的dispatch函数的时候,通常会轮训到多个事件,libevent将这些事件加入到一个活动队列中,这个活动队列是个优先级队列,根据事件的优先级将事件加入到对应优先级的队列中。这个队列是个尾队列。然后libevent去消费处理这些活动事件,对应事件处理函数去分发处理。

 

如果活动队列没有要处理的事件,event_dispatch函数将退出。

 

event_dispatch

函数原型

int event_dispatch(void);

 

int
event_dispatch(void)
{
	return (event_loop(0));
}
这里直接调用的event_loop函数。
event_loop函数将调用struct event_base实例的evsel成员的dispatch函数去分发事件。这个struct event_base实例通常是内部全局的struct event_base实例,如果是通过event_base_new初始化libevent的话,则是通过调用event_base_set设置的事件的ev_base,指向初始化的struct event_base实例。

 

 

event_loop

函数原型

int event_loop(int);

int
event_loop(int flags)
{
	return event_base_loop(current_base, flags);
}

函数event_loop又直接调用了event_base_loop函数。

 

event_base_loop

函数原型

int event_base_loop(struct event_base *, int);

int
event_base_loop(struct event_base *base, int flags)
{
	const struct eventop *evsel = base->evsel;
	void *evbase = base->evbase;
	struct timeval tv;
	struct timeval *tv_p;
	int res, done;

	/* clear time cache */
	base->tv_cache.tv_sec = 0;

	if (base->sig.ev_signal_added)
		evsignal_base = base;
	done = 0;
	while (!done) {
		/* Terminate the loop if we have been asked to */
		if (base->event_gotterm) {
			base->event_gotterm = 0;
			break;
		}

		if (base->event_break) {
			base->event_break = 0;
			break;
		}

		/* You cannot use this interface for multi-threaded apps */
		while (event_gotsig) {
			event_gotsig = 0;
			if (event_sigcb) {
				res = (*event_sigcb)();
				if (res == -1) {
					errno = EINTR;
					return (-1);
				}
			}
		}

		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);
		}
		
		/* If we have no events, we just exit */
		if (!event_haveevents(base)) {
			event_debug(("%s: no events registered.", __func__));
			return (1);
		}

		/* update last old time */
		gettime(base, &base->event_tv);

		/* clear time cache */
		base->tv_cache.tv_sec = 0;

		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);
}

激活事件

event_active

函数原型

void event_active(struct event *, int, short);

void
event_active(struct event *ev, int res, short ncalls)
{
	/* We get different kinds of events, add them together */
	if (ev->ev_flags & EVLIST_ACTIVE) {
		ev->ev_res |= res;
		return;
	}

	ev->ev_res = res;
	ev->ev_ncalls = ncalls;
	ev->ev_pncalls = NULL;
	event_queue_insert(ev->ev_base, ev, EVLIST_ACTIVE);
}

event_active直接将激活的事件放入对应活动队列中。尾队列。

 

处理活动事件

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)
			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) {
			  	ev->ev_pncalls = NULL;
				return;
			}
		}
		ev->ev_pncalls = NULL;
	}
}

 

分享到:
评论

相关推荐

    libevent-2.1.8-stable(源码库).zip

    - **事件分发**:当相关事件发生时,libevent会调用开发者提供的回调函数,处理相应事件。 3. **libevent的应用场景** - **网络服务器**:libevent适用于构建高性能的网络服务器,如HTTP服务器、FTP服务器等,能...

    libevent-1.4.11-stable.tar.gz

    - **Event Base**:事件基础结构,管理所有事件,负责调度和分发。 - **Event**:表示单个事件,如读写事件、定时事件等,关联一个回调函数。 - **Buffer**:用于高效地读写数据,支持内存池,减少内存分配的开销...

    libevent-1.4.8-stable.tar.gz

    2. `src/`:存放libevent的核心源代码,包括各种事件处理函数和事件模型的实现。 3. `examples/`:提供了一些简单的示例程序,演示了libevent的基本用法。 4. `doc/`:包含API文档和一些其他说明文件,帮助开发者...

    libevent的视频服务器源代码

    三、Libevent源代码解析 1. **初始化Libevent**:在服务器启动时,首先需要调用`event_base_new()`创建一个事件基础结构,然后设置事件处理回调函数。 2. **监听套接字**:通过`socket()`创建监听套接字,使用`...

    libevent源码分析1

    libevent的源码组织清晰,主要分为几个关键部分:事件基础结构、事件调度器、各种事件源(如文件描述符、信号、定时器等)以及多线程支持。源码中的核心组件是`event.c`和`event.h`,它们定义了事件处理的基本接口...

    Libevent学习手册(高清)+libevent源码深度剖析(很适合初学者)

    1. **源码结构**:分析Libevent的源代码组织结构,理解各个模块的功能和相互关系。 2. **事件调度算法**:研究Libevent如何高效地调度和分发事件,以及如何优化性能。 3. **内存管理**:查看Libevent的内存分配和...

    libevent源码分析[收集].pdf

    《libevent源码深度剖析》是一本专注于解析libevent库源代码的专业技术文档,作者张亮希望通过详尽的分析,帮助读者深入理解libevent的工作原理和实现细节。libevent是一个高度可移植的事件通知库,它允许程序员以一...

    qt_eventdispatcher_libevent-master.zip

    【描述】"qt_eventdispatcher_libevent" 提示这是一个针对Qt的扩展模块,目的是利用Libevent的强大功能,优化Qt中的事件分发机制,特别是对于网络I/O操作。在Qt框架中,事件调度器(Event Dispatcher)负责管理应用...

    线程池方式的libevent-server.zip

    而"ConsoleApplication1"可能是项目的主要源代码文件,其中可能包含了实现线程池和libevent事件处理逻辑的代码。在这些源码中,我们可以找到如何初始化线程池,如何注册libevent事件,以及如何在事件触发时调用适当...

    cpp-事件调度器和回调列表的C库

    1. **事件调度器(Event Loop)**:核心模块,负责监听和分发事件,可能是基于epoll、kqueue、IOCP等系统接口实现的。 2. **注册/取消注册接口**:允许用户添加或删除对特定事件的回调函数。 3. **事件处理器(Event...

    libevent官方文档英文版

    此外,文档中提供的源代码示例则在所谓的“3条款”或“修改版”BSD许可证下授权,这意味着源代码的使用也受到开源软件许可条款的约束。 文档的目标读者是已经具备C语言基础和对基本C网络调用(如socket()、connect...

    libevent文档

    文档内容介绍了Libevent库的使用方法,Libevent是一个开源的、高性能的C语言事件通知库,支持多种类型的事件通知,包括IO事件、定时器事件和信号事件。它最初由Nick Mathewson编写,并且在2009至2012年间版权所有。...

    libevent服务器 demo

    这个库的核心功能是管理事件循环,通过将事件分发到不同的事件处理器,使得程序可以高效地处理大量并发连接。在本示例中,“libevent服务器 demo”是一个简单的应用,演示了如何利用libevent来构建一个服务器。 **...

    分布式缓存服务器memcacaed的源代码

    源代码中的`event.c/h`包含了事件处理的实现。 6. **命令协议** Memcached支持简单的文本协议,允许客户端发送命令如`GET`, `SET`, `DELETE`等。在源代码中,`protocol_binary.c/h`文件处理了这些命令的解析和响应...

    squid 3.5.1源代码

    在源代码分析中,我们可以深入理解其工作原理和内部机制。 源代码版本 3.5.1 是 Squid 的一个稳定版本,发布于2014年,包含了当时的最新特性和改进。这个版本提供了许多重要的功能,如缓存策略优化、SSL/TLS 加密...

    共享顺风车项目源代码压缩文件

    共享顺风车项目源代码压缩文件提供了实现高并发共享出行服务的编程实例,主要涉及到的编程语言是C++,并且运用了线程池和libevent库来处理并发事件。在这个项目中,我们可以深入理解如何在分布式系统中构建高效、可...

    PopChain-Original:Popchain的源代码-Blockchain source code

    POPCHAIN是基于区块链技术的实时流媒体数字内容分发服务平台,旨在创建一个泛娱乐生态系统。 有关了解Pop的资源可能会有所帮助。 基本使用资源: 联系我们: 建立PopChain 在Ubuntu上构建(16.04 LTS) git ...

    APEX1500:APEX1500使用的开源软件包的源代码内容-开源

    【标题】"APEX1500开源软件包解析:揭秘边缘QAM数字前端设备的源代码" 在当今的数字电视领域,边缘量子调制器(QAM)设备扮演着至关重要的角色,尤其是在视频点播(VOD)和选择性数字视频(SDV)等服务中。本文将...

    p2p技术源代码 (C++ )

    压缩包内的文件“p2p source code”可能是P2P技术的C++源代码实现,通过阅读和分析这些代码,你可以更深入地了解P2P网络的具体实现细节,包括节点交互、数据存储和传输、网络协议等。同时,“说明.htm”和“下载说明...

Global site tag (gtag.js) - Google Analytics