libev学习之ev_run
好吧,神马都init好了,loop毕竟是个环呐,在哪跑起来呢,ok,他是ev_run的工作:
int ev_run (EV_P_ int flags)
{
#if EV_FEATURE_API
++loop_depth;
#endif assert (("libev: ev_loop recursion during release detected", loop_done != EVBREAK_RECURSE)); loop_done = EVBREAK_CANCEL; EV_INVOKE_PENDING; /* in case we recurse, ensure ordering stays nice and clean */ do
{
#if EV_VERIFY >= 2
ev_verify (EV_A);
#endif #ifndef _WIN32
if (expect_false (curpid)) /* penalise the forking check even more */
if (expect_false (getpid () != curpid))
{
curpid = getpid ();
postfork = ;
}
#endif #if EV_FORK_ENABLE
/* we might have forked, so queue fork handlers */
if (expect_false (postfork))
if (forkcnt)
{
queue_events (EV_A_ (W *)forks, forkcnt, EV_FORK);
EV_INVOKE_PENDING;
}
#endif #if EV_PREPARE_ENABLE
/* queue prepare watchers (and execute them) */
if (expect_false (preparecnt))
{
queue_events (EV_A_ (W *)prepares, preparecnt, EV_PREPARE);
EV_INVOKE_PENDING;
}
#endif if (expect_false (loop_done))
break; /* we might have forked, so reify kernel state if necessary */
if (expect_false (postfork))
loop_fork (EV_A); /* update fd-related kernel structures */
fd_reify (EV_A); /* calculate blocking time */
{
ev_tstamp waittime = .;
ev_tstamp sleeptime = .; /* remember old timestamp for io_blocktime calculation */
ev_tstamp prev_mn_now = mn_now; /* update time to cancel out callback processing overhead */
time_update (EV_A_ 1e100); /* from now on, we want a pipe-wake-up */
pipe_write_wanted = ; ECB_MEMORY_FENCE; /* make sure pipe_write_wanted is visible before we check for potential skips */ if (expect_true (!(flags & EVRUN_NOWAIT || idleall || !activecnt || pipe_write_skipped)))
{
waittime = MAX_BLOCKTIME; if (timercnt)
{
ev_tstamp to = ANHE_at (timers [HEAP0]) - mn_now;
if (waittime > to) waittime = to;
} #if EV_PERIODIC_ENABLE
if (periodiccnt)
{
ev_tstamp to = ANHE_at (periodics [HEAP0]) - ev_rt_now;
if (waittime > to) waittime = to;
}
#endif /* don't let timeouts decrease the waittime below timeout_blocktime */
if (expect_false (waittime < timeout_blocktime))
waittime = timeout_blocktime; /* at this point, we NEED to wait, so we have to ensure */
/* to pass a minimum nonzero value to the backend */
if (expect_false (waittime < backend_mintime))
waittime = backend_mintime; /* extra check because io_blocktime is commonly 0 */
if (expect_false (io_blocktime))
{
sleeptime = io_blocktime - (mn_now - prev_mn_now); if (sleeptime > waittime - backend_mintime)
sleeptime = waittime - backend_mintime; if (expect_true (sleeptime > .))
{
ev_sleep (sleeptime);
waittime -= sleeptime;
}
}
} #if EV_FEATURE_API
++loop_count;
#endif
assert ((loop_done = EVBREAK_RECURSE, )); /* assert for side effect */
backend_poll (EV_A_ waittime);
assert ((loop_done = EVBREAK_CANCEL, )); /* assert for side effect */ pipe_write_wanted = ; /* just an optimisation, no fence needed */ ECB_MEMORY_FENCE_ACQUIRE;
if (pipe_write_skipped)
{
assert (("libev: pipe_w not active, but pipe not written", ev_is_active (&pipe_w)));
ev_feed_event (EV_A_ &pipe_w, EV_CUSTOM);
} /* update ev_rt_now, do magic */
time_update (EV_A_ waittime + sleeptime);
} /* queue pending timers and reschedule them */
timers_reify (EV_A); /* relative timers called last */
#if EV_PERIODIC_ENABLE
periodics_reify (EV_A); /* absolute timers called first */
#endif #if EV_IDLE_ENABLE
/* queue idle watchers unless other events are pending */
idle_reify (EV_A);
#endif #if EV_CHECK_ENABLE
/* queue check watchers, to be executed first */
if (expect_false (checkcnt))
queue_events (EV_A_ (W *)checks, checkcnt, EV_CHECK);
#endif EV_INVOKE_PENDING;
}
while (expect_true (
activecnt
&& !loop_done
&& !(flags & (EVRUN_ONCE | EVRUN_NOWAIT))
)); if (loop_done == EVBREAK_ONE)
loop_done = EVBREAK_CANCEL; #if EV_FEATURE_API
--loop_depth;
#endif return activecnt;
}
看到了那么多ifdef有木有想shi的赶脚,尼玛。对于win32下,我们来精简下,哈哈:
int
ev_run (EV_P_ int flags)
{
assert (("libev: ev_loop recursion during release detected", loop_done != EVBREAK_RECURSE)); loop_done = EVBREAK_CANCEL;
//激活已经pending的事件
EV_INVOKE_PENDING; /* in case we recurse, ensure ordering stays nice and clean */ do
{
if (expect_false (curpid)) /* penalise the forking check even more */
if (expect_false (getpid () != curpid))
{
curpid = getpid ();
postfork = ;
} if (expect_false (loop_done))
break; /* update fd-related kernel structures */
fd_reify (EV_A);//把更改的事件进行更新 /* calculate blocking time */
{
ev_tstamp waittime = .;
ev_tstamp sleeptime = .; /* remember old timestamp for io_blocktime calculation */
ev_tstamp prev_mn_now = mn_now; /* update time to cancel out callback processing overhead */
time_update (EV_A_ 1e100); /* from now on, we want a pipe-wake-up */
pipe_write_wanted = ; ECB_MEMORY_FENCE; /* make sure pipe_write_wanted is visible before we check for potential skips */ if (expect_true (!(flags & EVRUN_NOWAIT || idleall || !activecnt || pipe_write_skipped)))
{
waittime = MAX_BLOCKTIME; if (timercnt)
{
ev_tstamp to = ANHE_at (timers [HEAP0]) - mn_now;
if (waittime > to) waittime = to;
} /* don't let timeouts decrease the waittime below timeout_blocktime */
if (expect_false (waittime < timeout_blocktime))
waittime = timeout_blocktime; /* at this point, we NEED to wait, so we have to ensure */
/* to pass a minimum nonzero value to the backend */
if (expect_false (waittime < backend_mintime))
waittime = backend_mintime; /* extra check because io_blocktime is commonly 0 */
if (expect_false (io_blocktime))
{
sleeptime = io_blocktime - (mn_now - prev_mn_now); if (sleeptime > waittime - backend_mintime)
sleeptime = waittime - backend_mintime; if (expect_true (sleeptime > .))
{
ev_sleep (sleeptime); //以上这么大一堆,都是在计算必要的sleep事件,其实就是阻塞嘛
waittime -= sleeptime;
}
}
} assert ((loop_done = EVBREAK_RECURSE, )); /* assert for side effect */
backend_poll (EV_A_ waittime);//这里开始调用上层封装的epool,select进行轮询,收集pending事件
assert ((loop_done = EVBREAK_CANCEL, )); /* assert for side effect */ pipe_write_wanted = ; /* just an optimisation, no fence needed */ ECB_MEMORY_FENCE_ACQUIRE;
if (pipe_write_skipped)
{
assert (("libev: pipe_w not active, but pipe not written", ev_is_active (&pipe_w)));
ev_feed_event (EV_A_ &pipe_w, EV_CUSTOM);
} /* update ev_rt_now, do magic */
time_update (EV_A_ waittime + sleeptime);
} /* queue pending timers and reschedule them */
timers_reify (EV_A); /* relative timers called last *///对pending的timer事件进行收集 EV_INVOKE_PENDING; //遍历所有pending事件
}
while (expect_true (
activecnt
&& !loop_done
&& !(flags & (EVRUN_ONCE | EVRUN_NOWAIT))
)); if (loop_done == EVBREAK_ONE)
loop_done = EVBREAK_CANCEL; return activecnt;
}
所有总结下,ev_run是libev的核心,
他主要做了五件事情:
1.更新更改的FD事件
2.进行必要的sleep
3.backend_poll收集pending的IO事件
4.收集pending的timer事件
5.调用所有pending的事件
ok,就是这样了!但是还有很多细节啊,尼玛代码之虐心,非比寻常啊!
libev学习之ev_run的更多相关文章
- libev学习笔记
转 libev的使用--结合Socket编程 作者:cxy450019566 之前自己学过一些libev编程的基础,这次写压测刚好用上了,才算真正动手写了些东西,在这里做一些总结.写这篇文章是为了用浅 ...
- libev 学习使用
libev 简单的I/O库. a high performance full featured event loop written in c libev 的大小也比 libevent 小得多并且自 ...
- 【转载】使用事件模型 & libev学习
参考这篇文章: http://www.ibm.com/developerworks/cn/linux/l-cn-edntwk/ 这里面使用的是 libev ,不是libevent Nodejs就是采用 ...
- libev学习(一)
一.libev简介 Libev是一个事件循环:你注册感兴趣的特定事件(比如一个文件可以读取时或者发生超时时),它将管理这些事件源,将这些事件反馈给你的程序.为了实现这些,至少要在你的进程(或线程)中执 ...
- Libev学习笔记4
这一节首先分析Libev的定时器部分,然后分析signal部分. 对定时器的使用主要有两个函数: ev_timer_init (&timeout_watcher, timeout_cb, .) ...
- Libev学习笔记3
设置完需要监听的事件之后,就开始event loop了.在Libev中,该工作由ev_run函数完成.它的大致流程如下: int ev_run (EV_P_ int flags) { do { /* ...
- Libev学习笔记2
这一节根据官方文档给出的简单示例,深入代码内部,了解其实现机制.示例代码如下: int main (void) { struct ev_loop *loop = EV_DEFAULT; ev_io_i ...
- Libev学习笔记1
和Libevent相似,Libev是一个高性事件驱动框架,据说性能比Libevent要高,bug比Libevent要少.Libev只是一个事件驱动框架,不是网络库,因为它的内部并没有任何socket编 ...
- libev学习代码
随机推荐
- day73
今日内容: 1基于双下划线的跨表查询 套路一样,用__跨表 -一对多 -多对多 # 北京出版社出版的所有图书 res = models.Publish.objects.filter(n ...
- 第4章 初识STM32
第4章 初识STM32 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/firege ...
- jquery方法简单记录
append() - 在被选元素的结尾插入内容 prepend() - 在被选元素的开头插入内容 after() - 在被选元素之后插入内容 before() - 在被选元素之前插入内容 firs ...
- 20155226 《网络对抗》Exp9 Web安全基础
20155226 <网络对抗>Exp9 Web安全基础 实践过程 开启webgoat 输入java -jar webgoat-container-7.1-exec.jar 在浏览器输入lo ...
- Asp.Net StateServer实现共同域名下Session共享
概述 在实验的时候,参照了多方的信息,确实成功了,这里简单记录一下. 我们知道,在Asp.Net的Web.Config文件中,System.Web节点下,有个sessionState节点,它说明了应用 ...
- 【arm学习】我的第一个裸板程序
初学ARM感觉写个裸板程序还真的不容易,可能是没有用到ADS,keil之类的开发平台的缘故吧.编译,链接过程在linux平台上完成,这样学起来更有实感,还能顺便熟悉linux环境,以及命令,何乐而不为 ...
- python3 简单进度条代码
进度条代码函数实现 import sys, time class ShowProcess(object): """ 显示处理进度的类 调用该类相关函数即可实现处理进度的显 ...
- [APIO2015]巴厘岛的雕塑[按位贪心+dp]
题意 给你长度为 \(n\) 的序列,要求分成 \(k\) 段连续非空的区间,求所有区间和的 \(or\) 最小值. 分析 定义 \(f_{i,j}\) 表示前 \(i\) 个点分成 \(j\) 段的 ...
- Flask学习-Flask app启动过程
因为0.1版本整体代码大概只有350行,比较简单.所以本篇文章会以Flask 0.1版本源码为基础进行剖析Flask应用的启动过程. Flask参考资料flask,官网有一个最简单app: from ...
- Centos 7 部署Kubernetes(K8S)集群
资源链接:https://pan.baidu.com/s/1-PT_QQAf7cTu_znX-S-r9Q 密码:33sr 转发:http://blog.51cto.com/lizhenliang/19 ...