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 ...
随机推荐
- iOS 自定义键盘ToolBar(与键盘的弹出、收起保持一致)
1.监听键盘改变的通知 [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyBoardWillCha ...
- laravel 在windows中使用一键安装包步骤
安装 PHP 注意一:Laravel 5.0 开始对 PHP 版本的要求是 >=5.4,Laravel 5.1 要求 PHP 版本 >=5.5.9,所以,建议大家尽量安装 5.5.x 的最 ...
- charles抓包工具分享
今天,给大组内QA做了一次分享,主要面向移动端测试,介绍了我平时在测试工作中用到的功能,大家都积极响应,现场搭环境,现场操作,现场提问解答,最后大家都成功的利用起来了,感觉很有成就感.下面介绍我今天分 ...
- Mac上安装django
参考:https://docs.djangoproject.com/en/1.9/topics/install/#installing-official-release 升级pip sudo pip ...
- jquery 选择器(name,属性,元素)大全
jQuery 选择器大体上可分为:基本选择器.层次选择器.过滤选择器.表单选择器. 其中过滤选择器可以分为:简单过滤选择器.内容过滤选择器.可见性过滤选择器.属性过滤选择器.子元素过滤选择器.表单对象 ...
- LL谱面分析和难度标定
LL谱面分析和难度标定 先介绍一下LL谱面的存储方式:TimeLine序列(简称TL序列),TL序列中的每一个元素(即音符)可以由一个C语言中的结构体来表示: struct note{ int lin ...
- Css背景渐变
语法: background:linear-gradient( 渐变方向,起点颜色,终点颜色 ) 参数说明: 渐变方向:可以使用top,left,或者指定具体的角度(deg为单位),比如top是自上而 ...
- Java工程师三大框架面试题汇总
1. Hibernate3 提供了属性的延迟加载功能? 当Hibernate在查询数据的时候,数据并没有存在与内存中,当程序真正对数据的操作时,对象才存在与内存中,就实现了延迟加载,他节省了服务器的内 ...
- Hdu 1214 圆桌会议
圆桌会议 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- springMVC--@requestBody
springMVC支持将前端传来的json字符串直接自动解析,注意点如下: 后台 1,在需要自动解析的参数前加上“@requestBody”,例如“public boolean updateOnePd ...