Libevent源码分析—event_base_dispatch()
- int
- event_base_dispatch(struct event_base *event_base)
- {
- return (event_base_loop(event_base, )); //调用event_base_loop()
- }
可以看到,该函数只是做了调用event_base_loop()这一个动作,所以工作实际是在函数event_base_loop()内完成的。
event_base_loop()
- int
- event_base_loop(struct event_base *base, int flags)
- {
- const struct eventop *evsel = base->evsel;
- void *evbase = base->evbase; //event_base的I/O多路复用
- struct timeval tv;
- struct timeval *tv_p;
- int res, done;
- /* clear time cache */
- //清空时间缓存
- base->tv_cache.tv_sec = ;
- //处理Signal事件时,指定信号所属的event_base
- if (base->sig.ev_signal_added)
- evsignal_base = base;
- done = ;
- while (!done) { //进入事件主循环
- /* Terminate the loop if we have been asked to */
- //设置event_base的标记,以表明是否需要跳出循环
- if (base->event_gotterm) { //event_loopexit_cb()可设置
- base->event_gotterm = ;
- break;
- }
- if (base->event_break) { //event_base_loopbreak()可设置
- base->event_break = ;
- break;
- }
- /* You cannot use this interface for multi-threaded apps */
- //当event_gotsig被设置时,则event_sigcb就是信号处理的回调函数
- while (event_gotsig) {
- event_gotsig = ;
- if (event_sigcb) {
- res = (*event_sigcb)(); //调用信号处理的回调函数
- if (res == -) {
- errno = EINTR;
- return (-);
- }
- }
- }
- timeout_correct(base, &tv); //校准时间
- tv_p = &tv;
- //根据定时器堆中最小超时时间计算I/O多路复用的最大等待时间tv_p
- 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 ();
- }
- /* update last old time */
- gettime(base, &base->event_tv);
- /* clear time cache */
- base->tv_cache.tv_sec = ;
- //调用I/O多路复用,监听事件
- res = evsel->dispatch(base, evbase, tv_p);
- if (res == -)
- return (-);
- //将time cache赋值为当前系统时间
- gettime(base, &base->tv_cache);
- //检查定时事件,将就绪的定时事件从小根堆中删除,插入到活跃事件链表中
- timeout_process(base);
- if (base->event_count_active) {
- //处理event_base的活跃链表中的事件
- //调用event的回调函数,优先级高的event先处理
- event_process_active(base);
- if (!base->event_count_active && (flags & EVLOOP_ONCE))
- done = ;
- } else if (flags & EVLOOP_NONBLOCK)
- done = ;
- }
- /* clear time cache */
- //循环结束,清空时间缓存
- base->tv_cache.tv_sec = ;
- event_debug(("%s: asked to terminate loop.", __func__));
- return ();
- }
epoll_dispatch()
- struct eventop {
- const char *name;
- void *(*init)(struct event_base *); //初始化
- int (*add)(void *, struct event *); //注册事件
- int (*del)(void *, struct event *); //删除事件
- int (*dispatch)(struct event_base *, void *, struct timeval *); //事件分发
- void (*dealloc)(struct event_base *, void *); //注销,释放资源
- /* set if we need to reinitialize the event base */
- int need_reinit;
- };
- const struct eventop epollops = {
- "epoll",
- epoll_init,
- epoll_add,
- epoll_del,
- epoll_dispatch,
- epoll_dealloc,
- /* need reinit */
- };
- static int
- epoll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
- {
- struct epollop *epollop = arg;
- struct epoll_event *events = epollop->events;
- struct evepoll *evep;
- int i, res, timeout = -;
- if (tv != NULL)
- timeout = tv->tv_sec * + (tv->tv_usec + ) / ; //转换为微米
- if (timeout > MAX_EPOLL_TIMEOUT_MSEC) { //设置最大超时时间
- /* Linux kernels can wait forever if the timeout is too big;
- * see comment on MAX_EPOLL_TIMEOUT_MSEC. */
- timeout = MAX_EPOLL_TIMEOUT_MSEC;
- }
- res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout); //监听事件发生
- if (res == -) {
- if (errno != EINTR) {
- event_warn("epoll_wait");
- return (-);
- }
- evsignal_process(base); //由于Signal事件发生中断,处理Signal事件
- return ();
- } else if (base->sig.evsignal_caught) {
- evsignal_process(base); //有Signal事件发生,处理Signal事件
- }
- event_debug(("%s: epoll_wait reports %d", __func__, res));
- for (i = ; i < res; i++) { //处理活跃事件
- int what = events[i].events; //活跃类型
- struct event *evread = NULL, *evwrite = NULL;
- int fd = events[i].data.fd; //event的文件描述符
- if (fd < || fd >= epollop->nfds)
- continue;
- evep = &epollop->fds[fd];
- if (what & (EPOLLHUP|EPOLLERR)) { //判断epoll的events类型,并找到注册的event
- evread = evep->evread;
- evwrite = evep->evwrite;
- } else {
- if (what & EPOLLIN) {
- evread = evep->evread;
- }
- if (what & EPOLLOUT) {
- evwrite = evep->evwrite;
- }
- }
- if (!(evread||evwrite))
- continue;
- //添加event到活跃事件链表中
- if (evread != NULL)
- event_active(evread, EV_READ, );
- if (evwrite != NULL)
- event_active(evwrite, EV_WRITE, );
- }
- //如果注册的事件全部变为活跃,则增大events数组为原来两倍
- if (res == epollop->nevents && epollop->nevents < MAX_NEVENTS) {
- /* We used all of the event space this time. We should
- be ready for more events next time. */
- int new_nevents = epollop->nevents * ;
- struct epoll_event *new_events;
- new_events = realloc(epollop->events,
- new_nevents * sizeof(struct epoll_event));
- if (new_events) {
- epollop->events = new_events;
- epollop->nevents = new_nevents;
- }
- }
- return ();
- }
event_process_active()
- /*
- * Active events are stored in priority queues. Lower priorities are always
- * process before higher priorities. Low priority events can starve high
- * priority ones.
- */
- static void
- event_process_active(struct event_base *base)
- {
- struct event *ev;
- struct event_list *activeq = NULL;
- int i;
- short ncalls;
- for (i = ; i < base->nactivequeues; ++i) { //取出第一个活跃链表
- if (TAILQ_FIRST(base->activequeues[i]) != NULL) {
- activeq = base->activequeues[i];
- break;
- }
- }
- assert(activeq != NULL);
- //优先处理优先级值最小的event
- 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;
- //调用该event的回调函数,event.ev_res保存返回值
- (*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源码分析—event_base_dispatch()的更多相关文章
- Libevent源码分析 (1) hello-world
Libevent源码分析 (1) hello-world ⑨月份接触了久闻大名的libevent,当时想读读源码,可是由于事情比较多一直没有时间,现在手头的东西基本告一段落了,我准备读读libeven ...
- 【转】libevent源码分析
libevent源码分析 转自:http://www.cnblogs.com/hustcat/archive/2010/08/31/1814022.html 这两天没事,看了一下Memcached和l ...
- Libevent源码分析系列【转】
转自:https://www.cnblogs.com/zxiner/p/6919021.html 1.使用libevent库 源码那么多,该怎么分析从哪分析呢?一个好的方法就是先用起来,会用了 ...
- Libevent源码分析系列
1.使用libevent库 源码那么多,该怎么分析从哪分析呢?一个好的方法就是先用起来,会用了,然后去看底层相应的源码,这样比较有条理,自上向下掌握.下面用libevent库写个程序,每隔1秒 ...
- libevent源码分析
这两天没事,看了一下Memcached和libevent的源码,做个小总结. 1.入门 1.1.概述Libevent是一个用于开发可扩展性网络服务器的基于事件驱动(event-driven)模型的网络 ...
- libevent源码分析二--timeout事件响应
libevent不仅支持io事件,同时还支持timeout事件与signal事件,这篇文件将分析libevent是如何组织timeout事件以及如何响应timeout事件. 1. min_heap ...
- libevent源码分析一--io事件响应
这篇文章将分析libevent如何组织io事件,如何捕捉事件的发生并进行相应的响应.这里不会详细分析event与event_base的细节,仅描述io事件如何存储与如何响应. 1. select l ...
- libevent源码分析(一)
分析libevent的源代码,我的想法的是先分析各种结构体,struct event_base.struct event,然后是event_base_new函数.event_new函数.event_a ...
- Libevent源码分析—event_init()
下面开始看初始化event_base结构的相关函数.相关源码位于event.c event_init() 首先调用event_init()初始化event_base结构体 struct event_b ...
随机推荐
- SharePoint 2013 APP 开发示例 (五)跨域访问 Web Service (REST API)
虽然 JQuery 也能通过授权header实现跨域, 但SharePoint 提供了更简单的方法,它被实现在SP.RequestExecutor里 .它能访问跨域的服务包括REST AP ...
- 【转】在单片机中,C语言的一些误用和总结!
在学习单片机的时候才真正知道C语言是什么,它是来干什么的~但是C语言用到嵌入式只是它小小的一部分应用,还有很多地方呢. 我们是不是在写程序的时候,错误很多就算编译通过了也达不到我们预期的结果,完了自己 ...
- CISCN2018-WP
MISC: 验证码: 用token登录 输入好验证码就可以得到flag Picture: 图片隐写,一下就想到binwalk或者winhex打开试试 binwalk打开无果 将这段数据ctrl+shi ...
- random模块(十九)
1 ).random() 返回0<=n<1之间的随机实数n: 2 ).choice(seq) 从序列seq中返回随机的元素: 3 ).getrandbits(n) 以长整型形式返回n个随机 ...
- Java设计模式--缺省适配器模式
我认为这个模式比较常见,还记得我们学习Swing的时候吗,有没有见过很多Adapter?那时候不知道Adapter的意义所在,但至少知道他能够省去我们不需要的实现. 这个社会有N中职业(job),但是 ...
- Docker从入门到飞升:基础配置安装
导读 Docker近几年非常火,因为它是容器虚拟化,更能够充分提高硬件资源的使用率.其实利用率高不算什么,它最大的优势是能给让运维人员或者开发人员快速部署和交付资源,大大提高了工作效率.几乎所有的大企 ...
- 5、Python-字典
定义 info = {'name': '班长', 'id': 88, 'sex': 'man', 'address': '地球亚洲中国北京'} print(info['name']) print(in ...
- IdeaVim-常用操作
IdeaVim简介 IdeaVim是IntelliJ IDEA的一款插件,他提高了我们写代码的速度,对代码的跳转,查找也很友好. 安装位置 安装之后它在 Tools > Vim Emulator ...
- np.array和np.asarray区别
- gcc和gdb使用笔记
gcc: http://wiki.ubuntu.org.cn/Gcchowto gdb: http://wiki.ubuntu.org.cn/%E7%94%A8GDB%E8%B0%83%E8%AF%9 ...