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学习代码
随机推荐
- Android实现导航菜单随着ListView联动,当导航菜单遇到顶部菜单时停止在哪里,并且listview仍能滑动
需求:现要实现一个特殊UI的处理,如下图所示: 该布局的上面是一个“按钮”,中间是一个“空白布局(当然也可以是ViewPager等)”,下面是一个页面的导航菜单,底部是一个ListView. 要求:滑 ...
- Django进阶(2)
1.在D盘创建mysite工程项目: django-admin startproject mysite manage.py ----- Django项目里面的工具,通过它可以调用django she ...
- 【小程序】 的识别
给标签添加 decode="{{true}}" space="{{true}}" 属性 eg: <text decode="{{true} ...
- [SDOI2011]工作安排 BZOJ2245
分析: 费用流裸题,按照题面要求建边就可以了,语文题,我读了10多分钟才知道这题干啥...特别是注意一个细节a[j+1]-a[j]... 附上代码: #include <cstdio> # ...
- day 11 前方高能-迭代器
第一类对象 -----函数名 == 变量名 函数对象可以像变量一样进行赋值 还可以作为列表的元素进行使用 可以作为返回值返回 def wrapper(): def inner(): ...
- 大数据入门第十七天——storm上游数据源 之kafka详解(二)常用命令
一.kafka常用命令 1.创建topic bin/kafka-topics. --replication-factor --zookeeper mini1: // 如果配置了PATH可以省略相关命令 ...
- 网络对抗技术 2017-2018-2 20152515 Exp2 后门原理与实践
1.实验内容 (1)使用netcat获取主机操作Shell,cron启动 (0.5分) 关于netcat:是一个底层工具,进行基本的TCP UDP数据收发.常被与其他工具结合使用,起到后门的作用. 相 ...
- 01-BAT算法特训班
- 如何完全卸载VS2010(亲自体验过) (转)
1.首先用360卸载,当卸载完成后,提示有残余的话,就强力清除 2,接着,下载IobitUninstaller工具 3.按照下面进行卸载 1.Microsoft .NET Framework 4 框架 ...
- Android与Libgdx入门实例
本文讲解如何实现Android与Libgdx各自的Hello World过程. 1. Android版Hello World 点击Eclipse快捷方式,选择New Android Applicati ...