libevent源码分析:time-test例子
time-test例子是libevent自带的一个例子,通过libevent提供的定时事件来实现,间隔固定时间打印的功能。
/*
* gcc -g -o time-test time-test.c -levent_core
*/ #include <sys/types.h>
#include <event2/event-config.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <fcntl.h> #include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h> #include <event2/event.h>
#include <event2/event_struct.h>
#include <event2/util.h> struct timeval lasttime;
int event_is_persistent; static void timeout_cb(evutil_socket_t fd, short event, void *arg)
{
struct timeval newtime, difference;
struct event *timeout = arg;
double elapsed; evutil_gettimeofday(&newtime, NULL);
evutil_timersub(&newtime, &lasttime, &difference);
elapsed = difference.tv_sec + (difference.tv_usec / 1.0e6); printf("timeout_cb called at %d: %.3f seconds elapsed.\n", (int)newtime.tv_sec, elapsed);
lasttime = newtime; if (!event_is_persistent)
{
struct timeval tv;
evutil_timerclear(&tv);
tv.tv_sec = ;
event_add(timeout, &tv);
}
} int main(int argc, char **argv)
{
struct event timeout;
struct timeval tv;
struct event_base *base;
int flags; if (argc == && strcmp(argv[], "-p"))
{
event_is_persistent = ;
flags = EV_PERSIST;
}
else
{
event_is_persistent = ;
flags = ;
} /* Initalize the event library */
base = event_base_new(); /* Initalize one event */
event_assign(&timeout, base, -, flags, timeout_cb, (void*)&timeout); evutil_timerclear(&tv);
tv.tv_sec = ;
event_add(&timeout, &tv); evutil_gettimeofday(&lasttime, NULL);
event_base_dispatch(base); return ;
}
这次就通过分析一个这个简单的例子来加深对libevent的理解。
1、首先通过event_base_new获取一个event_base对象。
2、通过event_assign来对一个event赋值(属于的event_base,监听的事件类型,回调函数等)。
3、通过event_add激活该event。
4、调用event_base_dispatch进入事件循环。
event_base_dispatch内部有一个很大的死循环,不停的调用io复用机制来监听指定文件描述符上的事件,并在相应事件发生的时候,触发相应的回调函数。
回调的堆栈如下:

可以看到是依次调用了event_base_loop()->event_process_active()->event_process_active_single_queue()->timeout_cb()。
int
event_base_loop(struct event_base *base, int flags)
{
const struct eventop *evsel = base->evsel;
struct timeval tv;
struct timeval *tv_p;
int res, done, retval = ; /* Grab the lock. We will release it inside evsel.dispatch, and again
* as we invoke user callbacks. */
EVBASE_ACQUIRE_LOCK(base, th_base_lock); if (base->running_loop) {
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 -;
} base->running_loop = ; clear_time_cache(base); if (base->sig.ev_signal_added && base->sig.ev_n_signals_added)
evsig_set_base_(base); done = ; #ifndef EVENT__DISABLE_THREAD_SUPPORT
base->th_owner_id = EVTHREAD_GET_ID();
#endif base->event_gotterm = base->event_break = ; while (!done) {
base->event_continue = ;
base->n_deferreds_queued = ; /* Terminate the loop if we have been asked to */
if (base->event_gotterm) {
break;
} if (base->event_break) {
break;
} 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 (==(flags&EVLOOP_NO_EXIT_ON_EMPTY) &&
!event_haveevents(base) && !N_ACTIVE_CALLBACKS(base)) {
event_debug(("%s: no events registered.", __func__));
retval = ;
goto done;
} event_queue_make_later_events_active(base); clear_time_cache(base); res = evsel->dispatch(base, tv_p); if (res == -) {
event_debug(("%s: dispatch returned unsuccessfully.",
__func__));
retval = -;
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) ==
&& n != )
done = ;
} else if (flags & EVLOOP_NONBLOCK)
done = ;
}
event_debug(("%s: asked to terminate loop.", __func__)); done:
clear_time_cache(base);
base->running_loop = ; EVBASE_RELEASE_LOCK(base, th_base_lock); return (retval);
}
event_base_loop()
其实如果去打开event_base_loop()函数的实现来看,会发现对于事件的处理时分两步的,先是调用dispatch,把不同io复用机制得到的事件转换为统一的libevent事件,并将这些事件放到event_base的激活事件队列中,然后再调用event_process_active函数从激活事件队列中挨个读取每个事件并调用其回调函数。
libevent源码分析:time-test例子的更多相关文章
- libevent源码分析:http-server例子
http-server例子是libevent提供的一个简单web服务器,实现了对静态网页的处理功能. /* * gcc -g -o http-server http-server.c -levent ...
- libevent源码分析:hello-world例子
hello-world是libevent自带的一个例子,这个例子的作用是启动后监听一个端口,对于所有通过这个端口连接上服务器的程序发送一段字符:hello-world,然后关闭连接. /* * gcc ...
- libevent源码分析:signal-test例子
signal-test是libevent自带的一个例子,展示了libevent对于信号事件的处理方法. #include <sys/types.h> #include <event2 ...
- 【转】libevent源码分析
libevent源码分析 转自:http://www.cnblogs.com/hustcat/archive/2010/08/31/1814022.html 这两天没事,看了一下Memcached和l ...
- Libevent源码分析 (1) hello-world
Libevent源码分析 (1) hello-world ⑨月份接触了久闻大名的libevent,当时想读读源码,可是由于事情比较多一直没有时间,现在手头的东西基本告一段落了,我准备读读libeven ...
- 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 ...
随机推荐
- Java 三章错题
1.每个类都使用Object作为超类.所以对象(包括数组)都实现这个类的方法. 2.在不明确给出超类的情况下,java会自动把object作为要定义的超类. 可以使用类型为Object的变量指向任意类 ...
- 取到 tableview 自定义section header 上的button
在自定义的组头上,添加了一个button,在点击cell是想取到相应的组头上的button来进行操作时(比如说隐藏.是否响应点击事件等)时,我遇到了取不到所有button的问题,试过了常规的通过vie ...
- QT 调试时出现 During startup program exited with code 0xc0000135 错误
我用的QT creator 5.70 出现上述原因是动态库加载不成功,但是QTcreator 不会提示什么动态库,具体缺乏什么动态库要用VS新建一个工程调用才可以看到,这也是QT Creator很大的 ...
- jsp页面常用控件
1.点击按钮返回 上一页: <input type="submit" value="返回" onclick="javascript :histo ...
- zookeeper清除事物日志
dataDir=/data/zookeeper/data dataLogDir=/data/zookeeper/log zk事物日志(快照)存放目录,高负荷工作的时候,会产生大量的日志,需 ...
- openfire更改数据库
修改openfire安装目录下./conf/openfire.xml <setup>true</setup>中的true为false,重新启动,然后配置
- sql关联表查询结果并插入
这里涉及三个表,AA,BB,CC,将AA的数据更新到CC表中,将AA中LABEL_ID分别截取字段与BB表中的label_id对应查询到LABEL_NAME作为CC表的一个字段插入,这里分成四段查询 ...
- JOIN,WHERE判断和ORDERBY排序
MySQL可以很好的支持大数据量的存取,但是一般说来,数据库中的表越小,在它上面执行的查询也就会越快.因此,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设得尽可能小. 如果重复代码只是 ...
- WebForm Repeater: 重复器
Repeater控件,可以用来一次显示一组数据项.比如,可以用它们显示一个数据表中的所有行. Repeater控件完全由模板驱动,提供了最大的灵活性,可以任意设置它的输出格式. ...
- CentOS 7 启动、重启、chkconfig等命令已经合并为systemctl
CentOS 7系统服务启动.重启.设置服务启动项命令以合并为,systemctl . 现在用service 或/etc/init.d/命令,重启,重新启动,停止等没效果,因为命令合并为systemc ...