好吧,神马都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的更多相关文章

  1. libev学习笔记

    转 libev的使用--结合Socket编程 作者:cxy450019566 之前自己学过一些libev编程的基础,这次写压测刚好用上了,才算真正动手写了些东西,在这里做一些总结.写这篇文章是为了用浅 ...

  2. libev 学习使用

    libev 简单的I/O库.  a high performance full featured event loop written in c libev 的大小也比 libevent 小得多并且自 ...

  3. 【转载】使用事件模型 & libev学习

    参考这篇文章: http://www.ibm.com/developerworks/cn/linux/l-cn-edntwk/ 这里面使用的是 libev ,不是libevent Nodejs就是采用 ...

  4. libev学习(一)

    一.libev简介 Libev是一个事件循环:你注册感兴趣的特定事件(比如一个文件可以读取时或者发生超时时),它将管理这些事件源,将这些事件反馈给你的程序.为了实现这些,至少要在你的进程(或线程)中执 ...

  5. Libev学习笔记4

    这一节首先分析Libev的定时器部分,然后分析signal部分. 对定时器的使用主要有两个函数: ev_timer_init (&timeout_watcher, timeout_cb, .) ...

  6. Libev学习笔记3

    设置完需要监听的事件之后,就开始event loop了.在Libev中,该工作由ev_run函数完成.它的大致流程如下: int ev_run (EV_P_ int flags) { do { /* ...

  7. Libev学习笔记2

    这一节根据官方文档给出的简单示例,深入代码内部,了解其实现机制.示例代码如下: int main (void) { struct ev_loop *loop = EV_DEFAULT; ev_io_i ...

  8. Libev学习笔记1

    和Libevent相似,Libev是一个高性事件驱动框架,据说性能比Libevent要高,bug比Libevent要少.Libev只是一个事件驱动框架,不是网络库,因为它的内部并没有任何socket编 ...

  9. libev学习代码

随机推荐

  1. [浅谈CSS核心概念] CSS布局模型:float和position

    1.流动模型 HTML元素在默认情况下都是按照"流动模型"进行布局的,网上也有人称之为"普通流"."文档流"之类的.这种布局模式的特点在于: ...

  2. php操作oracle查询时中文乱码

    putenv("LD_LIBRARY_PATH=/usr/lib/oracle/12.1/client64/lib"); putenv("ORACLE_HOME=/usr ...

  3. vue-cli,build 后,报错的解决办法

    报错如下图: 或: 解决办法:config / index.js 中,找到 build { assetsPublicPath: '/' },将其设置为:assetsPublicPath: './ ' ...

  4. WPF绑定文本时使用指定格式文本

    原文:WPF绑定文本时使用指定格式文本 Text="{Binding PlayletModel.characters,StringFormat=Cast : {0}}" Strin ...

  5. tkinter 弹出窗口 传值回到 主窗口

    有些时候,我们需要使用弹出窗口,对程序的运行参数进行设置.有两种选择 一.标准窗口 如果只对一个参数进行设置(或者说从弹出窗口取回一个值),那么可以使用simpledialog,导入方法: from ...

  6. 基于Boost库的HTTP Post函数

    两个函数的区别: 提交表单数据和提交文本数据 表单数据: request_stream << "Content-Type: application/x-www-form-urle ...

  7. Qt FFMPEG+OpenCV开启摄像头

    //ffmpegDecode.h #ifndef __FFMPEG_DECODE_H__ #define __FFMPEG_DECODE_H__ #include "global.h&quo ...

  8. CF1096G Lucky Tickets

    https://www.luogu.org/problemnew/show/CF1096G 显然dp出用\(\frac{n}{2}\)个数能拼出来的每个数的方案数,平方相加就行了,dp显然ntt+快速 ...

  9. Macaca 基础原理浅析

    导语 前面几篇文章介绍了在Macaca实践中的一些实用技巧与解决方案,今天简单分析一下Macaca的基础原理.这篇文章将以前面所分享的UI自动化Macaca-Java版实践心得中的demo为基础,进行 ...

  10. Django的跨域请求

    一 同源策略 同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响.可以说Web是构建在同源策略基础之 ...