Libevent源码分析-event处理流程

event处理流程

Libevent处理时间的大概流程为

1、设置event_base(即初始化Reactor)

2、设置event事件(初始化event)

3、将event和event_base关联(将event注册到event_base)

4、进入循环,等待事件

5、事件发生,处理事件。

用UML序列图可以表示为:

#include <iostream>
#include <sys/time.h>
#include <event.h>
struct event ev;
struct timeval tv;

void time_cb(int fd, short event, void* argc)
{
    std::cout<<"Timer wakeup"<<std::endl;
    event_add(&ev, &tv);
}

int main()
{

    struct event_base* base=event_base_new();

    tv.tv_sec=10;
    tv.tv_usec=0;
    evtimer_set(&ev, time_cb, NULL);//设置定时器事件
    event_base_set(base, &ev);//将event和event_base关联
    event_add(&ev, &tv);//注册事件
    event_base_dispatch(base);//进入loop循环,等待事件

    return 0;
}

首先创建了event_base作为Reactor,设置了定时器事件作为event。随后将ev和base关联,注册ev到事件分发器(evsel,在event_base中)。最后进入loop循环,等待事件发生。

看一下event_base_set(base, &ev)

int event_base_set(struct event_base *base, struct event *ev)
{
    /* Only innocent events may be assigned to a different base */
    if (ev->ev_flags != EVLIST_INIT)//确保event已经初始化
        return (-1);

    _event_debug_assert_is_setup(ev);

    ev->ev_base = base;//设置event_base为event的Reactor
    ev->ev_pri = base->nactivequeues/2;//event的优先级

    return (0);
}

可以看出这一步只是将event和event_base关联,即在event中保存它所在的Reactor。

再来看看event_add(&ev, &tv)

int event_add(struct event *ev, const struct timeval *tv)
{
    int res;

    if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
        event_warnx("%s: event has no event_base set.", __func__);
        return -1;
    }

    EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);

    res = event_add_internal(ev, tv, 0);//这里才是主体部分

    EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);

    return (res);
}

再来看一下event_add_internal(ev, tv, 0),略去了部分代码

static inline int
event_add_internal(struct event *ev, const struct timeval *tv,
    int tv_is_absolute)
{
    struct event_base *base = ev->ev_base;
    int res = 0;
    int notify = 0;

    if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {//tv不为空,且要添加到time堆中,则为time堆扩容
        if (min_heap_reserve(&base->timeheap,
            1 + min_heap_size(&base->timeheap)) == -1)
            return (-1);  /* ENOMEM == errno */
    }

    /*如果事件是IO或信号事件,且事件已经添加或激活,则插入到相应队列
    */
    if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&
        !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
        if (ev->ev_events & (EV_READ|EV_WRITE))//IO事件
            res = evmap_io_add(base, ev->ev_fd, ev);//添加到IO事件队列
        else if (ev->ev_events & EV_SIGNAL)//信号事件
            res = evmap_signal_add(base, (int)ev->ev_fd, ev);//添加到信号事件队列
        if (res != -1)
            event_queue_insert(base, ev, EVLIST_INSERTED);//将事件插入到队列base->eventqueue
        if (res == 1) {
            /* evmap says we need to notify the main thread. */
            notify = 1;
            res = 0;
        }
    }

        gettime(base, &now);//更新base中的time

        event_queue_insert(base, ev, EVLIST_TIMEOUT);//添加到定时器小根堆

    /* if we are not in the right thread, we need to wake up the loop */
    if (res != -1 && notify && EVBASE_NEED_NOTIFY(base))//如果当前线程不是loop所在线程,唤醒loop线程。
        evthread_notify_base(base);

    return (res);
}

最后看一下event_base_dispatch(base);

int event_base_dispatch(struct event_base *event_base)
{
    return (event_base_loop(event_base, 0));
}

看一下event_base_loop(event_base, 0)

int
event_base_loop(struct event_base *base, int flags)
{
    const struct eventop *evsel = base->evsel;//事件分发器 event demultiplexer
    struct timeval tv;
    struct timeval *tv_p;
    int res, done, retval = 0;

    if (base->running_loop) {//loop循环只能在event_base所在线程
        event_warnx("%s: reentrant invocation.  Only one event_base_loop"
            " can run on each event_base at once.", __func__);
        EVBASE_RELEASE_LOCK(base, th_base_lock);
        return -1;
    }

    base->running_loop = 1;//表明even_base在运行loop,防止其他线程运行

    clear_time_cache(base);//置零tv_cache

    if (base->sig.ev_signal_added && base->sig.ev_n_signals_added)//如果信号事件设置
        evsig_set_base(base);//设置signal_pair[0]位信号源

    done = 0;

    base->event_gotterm = base->event_break = 0;

    while (!done) {//进入loop循环主体
        base->event_continue = 0;

        /* Terminate the loop if we have been asked to */
        if (base->event_gotterm) {
            break;
        }
        if (base->event_break) {
            break;
        }

        timeout_correct(base, &tv);//更新时间

        tv_p = &tv;
        if (!N_ACTIVE_CALLBACKS(base) && !(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) && !N_ACTIVE_CALLBACKS(base)) {
            event_debug(("%s: no events registered.", __func__));
            retval = 1;
            goto done;//用了goto?
        }

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

        clear_time_cache(base);

        res = evsel->dispatch(base, tv_p);//epoll_wait等,阻塞等待事件

        if (res == -1) {
            event_debug(("%s: dispatch returned unsuccessfully.",
                __func__));
            retval = -1;
            goto done;
        }

        update_time_cache(base);

        timeout_process(base);//处理到时事件

        if (N_ACTIVE_CALLBACKS(base)) {
            int n = event_process_active(base);//处理事件,处理过程中有优先级
            if ((flags & EVLOOP_ONCE)
                && N_ACTIVE_CALLBACKS(base) == 0
                && n != 0)
                done = 1;
        } else if (flags & EVLOOP_NONBLOCK)
            done = 1;
    }

done://goto用的label
    clear_time_cache(base);
    base->running_loop = 0;

    EVBASE_RELEASE_LOCK(base, th_base_lock);

    return (retval);
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-05 15:40:23

Libevent源码分析-event处理流程的相关文章

libevent源码分析-event

event结构 event相关接口 Libevent对event的管理 event结构 event是Reactor模式中的最重要的组件.它包含了了一个句柄fd,并设置监听这个句柄上的哪些事件(读/写等),设置了对应的函数指针,在事件到来时,回调函数指针来处理事件. 先看一下event的结构.它位于include/event2/event_struct.h中 struct event { TAILQ_ENTRY(event) ev_active_next; TAILQ_ENTRY(event) e

Libevent源码分析—event, event_base

event和event_base是libevent的两个核心结构体,分别是反应堆模式中的Event和Reactor.源码分别位于event.h和event-internal.h中 1.event: struct event { TAILQ_ENTRY (event) ev_next; //I/O事件 TAILQ_ENTRY (event) ev_active_next; //所有激活事件的链表 TAILQ_ENTRY (event) ev_signal_next; //Signal事件 //定时

Libevent源码分析-timer和signal处理

timer处理 Signal处理 timerfd和signalfd timerfd signalfd timer处理 在Libevent源码分析-event处理流程中,使用了定时器,来看一下源码: evtimer_set(&ev, time_cb, NULL);//设置定时器事件 其中evtimer_set是个宏定义 #define evtimer_set(ev, cb, arg) event_set((ev), -1, 0, (cb), (arg)) //event_set原型 void ev

【转】libevent源码分析

libevent源码分析 转自:http://www.cnblogs.com/hustcat/archive/2010/08/31/1814022.html 这两天没事,看了一下Memcached和libevent的源码,做个小总结. 1.入门 1.1.概述Libevent是一个用于开发可扩展性网络服务器的基于事件驱动(event-driven)模型的网络库.Libevent有几个显著的亮点: (1)事件驱动(event-driven),高性能:(2)轻量级,专注于网络,不如 ACE 那么臃肿庞

Libevent源码分析 (1) hello-world

Libevent源码分析 (1) hello-world ⑨月份接触了久闻大名的libevent,当时想读读源码,可是由于事情比较多一直没有时间,现在手头的东西基本告一段落了,我准备读读libevent的源码,凡是我觉得有必要的内容均一一记录,与君共勉. 首先要说说什么是libevent: libevent是一个事件通知库,libevent API提供一种机制使得我们可以在一个文件描述符(file descriptor)发生特定事件时或者timeout发生时执行指定的回调函数.libevent意

HBase1.0.0源码分析之请求处理流程分析以Put操作为例(二)

HBase1.0.0源码分析之请求处理流程分析以Put操作为例(二) 1.通过mutate(put)操作,将单个put操作添加到缓冲操作中,这些缓冲操作其实就是Put的父类的一个List的集合.如下: private List<Row> writeAsyncBuffer = new LinkedList<>(); writeAsyncBuffer.add(m); 当writeAsyncBuffer满了之后或者是人为的调用backgroundFlushCommits操作促使缓冲池中的

openVswitch(OVS)源码分析之工作流程(哈希桶结构体的解释)

这篇blog是专门解决前篇openVswitch(OVS)源码分析之工作流程(哈希桶结构体的疑惑)中提到的哈希桶结构flex_array结构体成员变量含义的问题. 引用下前篇blog中分析讨论得到的flex_array结构体成员变量的含义结论: struct { int element_size; // 这是flex_array_part结构体存放的哈希头指针的大小 int total_nr_elements; // 这是全部flex_array_part结构体中的哈希头指针的总个数 int e

Spark SQL源码分析之核心流程

自从去年Spark Submit 2013 Michael Armbrust分享了他的Catalyst,到至今1年多了,Spark SQL的贡献者从几人到了几十人,而且发展速度异常迅猛,究其原因,个人认为有以下2点: 1.整合:将SQL类型的查询语言整合到 Spark 的核心RDD概念里.这样可以应用于多种任务,流处理,批处理,包括机器学习里都可以引入Sql. 2.效率:因为Shark受到hive的编程模型限制,无法再继续优化来适应Spark模型里. 前一段时间测试过Shark,并且对Spark

leveldb源码分析--插入删除流程

由于网络上对leveldb的分析文章都比较丰富,一些基础概念和模型都介绍得比较多,所以本人就不再对这些概念以专门的篇幅进行介绍,本文主要以代码流程注释的方式. 首先我们从db的插入和删除开始以对整个体系有一个感性的认识,首先看插入: Status DB::Put(const WriteOptions& opt, const Slice& key, const Slice& value) { WriteBatch batch; //leveldb中不管单个插入还是多个插入都是以Wri