Libevent源码分析-----Libevent工作流程探究


        转载请注明出处:http://blog.csdn.net/luotuo44/article/details/38501341


        之前的博文讲了很多Libevent的基础构件,现在以一个实际例子来初步探究Libevent的基本工作流程。由于还有很多Libevent的细节并没有讲所以,这里的探究还是比较简洁,例子也相当简单。

#include<unistd.h>
#include<stdio.h>
#include<event.h>
#include<thread.h>


void cmd_cb(int fd, short events, void *arg)
{
    char buf[1024];
    printf("in the cmd_cb\n");

    read(fd, buf, sizeof(buf));
}


int main()
{
    evthread_use_pthreads();

    //使用默认的event_base配置
    struct event_base *base = event_base_new();

    struct event *cmd_ev = event_new(base, STDIN_FILENO,
                                     EV_READ | EV_PERSIST, cmd_cb, NULL);

    event_add(cmd_ev, NULL); //没有超时

    event_base_dispatch(base);

    return 0;
}
        上面代码估计是不会比读者写的第一个Libevent程序复杂。但这已经包含了Libevent的基础工作流程。这里将进入这些函数的内部探究,并且只会讲解之前博文出现过的,没出现的,尽量不讲。在讲解之前,要先了解一下struct event这个结构体。

struct event {
	TAILQ_ENTRY(event) ev_active_next; //激活队列
	TAILQ_ENTRY(event) ev_next; //注册事件队列
	/* for managing timeouts */
	union {
		TAILQ_ENTRY(event) ev_next_with_common_timeout;
		int min_heap_idx; //指明该event结构体在堆的位置
	} ev_timeout_pos; //仅用于定时事件处理器(event).EV_TIMEOUT类型

	//对于I/O事件,是文件描述符;对于signal事件,是信号值
	evutil_socket_t ev_fd;

	struct event_base *ev_base; //所属的event_base

	//因为信号和I/O是不能同时设置的。所以可以使用共用体以省内存
	//在低版本的Libevent,两者是分开的,不在共用体内。
	union {
	//无论是信号还是IO,都有一个TAILQ_ENTRY的队列。它用于这样的情景:
	//用户对同一个fd调用event_new多次,并且都使用了不同的回调函数。
	//每次调用event_new都会产生一个event*。这个xxx_next成员就是把这些
	//event连接起来的。
	
		/* used for io events */
		//用于IO事件
		struct {
			TAILQ_ENTRY(event) ev_io_next;
			struct timeval ev_timeout;
		} ev_io;

		/* used by signal events */
		//用于信号事件
		struct {
			TAILQ_ENTRY(event) ev_signal_next;
			short ev_ncalls; //事件就绪执行时,调用ev_callback的次数			/* Allows deletes in callback */
			short *ev_pncalls; //指针,指向次数
		} ev_signal;
	} _ev;

	short ev_events;//记录监听的事件类型 EV_READ EVTIMEOUT之类
	short ev_res;		/* result passed to event callback *///记录了当前激活事件的类型
	//libevent用于标记event信息的字段,表明其当前的状态.
	//可能值为前面的EVLIST_XXX
	short ev_flags; 

	//本event的优先级。调用event_priority_set设置
	ev_uint8_t ev_pri;
	ev_uint8_t ev_closure;
	struct timeval ev_timeout;//用于定时器,指定定时器的超时值

	/* allows us to adopt for different types of events */
	void (*ev_callback)(evutil_socket_t, short, void *arg); //回调函数
	void *ev_arg; //回调函数的参数
};
        event结构体里面有几个TAILQ_ENTRY队列节点类型。这里因为一个event是会同时处于多个队列之中。比如前几篇博文说到的同一个文件描述符或者信号值对应的多个event会被连在一起,所有的被加入到event_base的event也会连在一起,所有被激活的event也会被连在一起。所以会有多个QAILQ_ENTRY。

        event结构体只有一两个之前没有说到的概念,这不妨碍理解event结构体。而event_base结构体则会太多之前没有说到的概念,所以这里就不贴出event_base的代码了。

        在读这篇博文前,最好读一下前面几篇博文,因为会用到其他讲到的东西。如果之前有讲过的东西,这里也将一笔带过。

 

        好了,开始探究。

        最前面的evthread_use_pthreads();就不多说了,看《多线程、锁、条件变量(一)》和《多线程、锁、条件变量(二)》这两篇博文吧。


创建event_base:

        下面看一下event_base_new函数。它是由event_base_new_with_config函数实现的。我们还是看后面那个函数吧。

//event.c文件
struct event_base *
event_base_new_with_config(const struct event_config *cfg)
{
	int i;
	struct event_base *base;
	int should_check_environment;


	//之所以不用mm_malloc是因为mm_malloc并不会清零该内存区域。
	//而这个函数是会清零申请到的内存区域,这相当于被base初始化
	if ((base =
  • 7
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值