zoukankan      html  css  js  c++  java
  • 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 = 1;
              }
    #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  = 0.;
            ev_tstamp sleeptime = 0.;
    
            /* 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 = 1;
    
            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 > 0.))
                      {
                        ev_sleep (sleeptime);
                        waittime -= sleeptime;
                      }
                  }
              }
    
    #if EV_FEATURE_API
            ++loop_count;
    #endif
            assert ((loop_done = EVBREAK_RECURSE, 1)); /* assert for side effect */
            backend_poll (EV_A_ waittime);
            assert ((loop_done = EVBREAK_CANCEL, 1)); /* assert for side effect */
    
            pipe_write_wanted = 0; /* 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下,我们来精简下,哈哈:

      1 int
      2 ev_run (EV_P_ int flags)
      3 {
      4   assert (("libev: ev_loop recursion during release detected", loop_done != EVBREAK_RECURSE));
      5 
      6   loop_done = EVBREAK_CANCEL;
      7  //激活已经pending的事件
      8   EV_INVOKE_PENDING; /* in case we recurse, ensure ordering stays nice and clean */
      9 
     10   do
     11     {
     12       if (expect_false (curpid)) /* penalise the forking check even more */
     13         if (expect_false (getpid () != curpid))
     14           {
     15             curpid = getpid ();
     16             postfork = 1;
     17           }
     18 
     19       if (expect_false (loop_done))
     20         break;
     21 
     22       /* update fd-related kernel structures */
     23       fd_reify (EV_A);//把更改的事件进行更新
     24 
     25       /* calculate blocking time */
     26       {
     27         ev_tstamp waittime  = 0.;
     28         ev_tstamp sleeptime = 0.;
     29 
     30         /* remember old timestamp for io_blocktime calculation */
     31         ev_tstamp prev_mn_now = mn_now;
     32 
     33         /* update time to cancel out callback processing overhead */
     34         time_update (EV_A_ 1e100);
     35 
     36         /* from now on, we want a pipe-wake-up */
     37         pipe_write_wanted = 1;
     38 
     39         ECB_MEMORY_FENCE; /* make sure pipe_write_wanted is visible before we check for potential skips */
     40 
     41         if (expect_true (!(flags & EVRUN_NOWAIT || idleall || !activecnt || pipe_write_skipped)))
     42           {
     43             waittime = MAX_BLOCKTIME;
     44 
     45             if (timercnt)
     46               {
     47                 ev_tstamp to = ANHE_at (timers [HEAP0]) - mn_now;
     48                 if (waittime > to) waittime = to;
     49               }
     50 
     51             /* don't let timeouts decrease the waittime below timeout_blocktime */
     52             if (expect_false (waittime < timeout_blocktime))
     53               waittime = timeout_blocktime;
     54 
     55             /* at this point, we NEED to wait, so we have to ensure */
     56             /* to pass a minimum nonzero value to the backend */
     57             if (expect_false (waittime < backend_mintime))
     58               waittime = backend_mintime;
     59 
     60             /* extra check because io_blocktime is commonly 0 */
     61             if (expect_false (io_blocktime))
     62               {
     63                 sleeptime = io_blocktime - (mn_now - prev_mn_now);
     64 
     65                 if (sleeptime > waittime - backend_mintime)
     66                   sleeptime = waittime - backend_mintime;
     67 
     68                 if (expect_true (sleeptime > 0.))
     69                   {
     70                     ev_sleep (sleeptime); //以上这么大一堆,都是在计算必要的sleep事件,其实就是阻塞嘛
     71                     waittime -= sleeptime;
     72                   }
     73               }
     74           }
     75 
     76         assert ((loop_done = EVBREAK_RECURSE, 1)); /* assert for side effect */
     77         backend_poll (EV_A_ waittime);//这里开始调用上层封装的epool,select进行轮询,收集pending事件
     78         assert ((loop_done = EVBREAK_CANCEL, 1)); /* assert for side effect */
     79 
     80         pipe_write_wanted = 0; /* just an optimisation, no fence needed */
     81 
     82         ECB_MEMORY_FENCE_ACQUIRE;
     83         if (pipe_write_skipped)
     84           {
     85             assert (("libev: pipe_w not active, but pipe not written", ev_is_active (&pipe_w)));
     86             ev_feed_event (EV_A_ &pipe_w, EV_CUSTOM);
     87           }
     88 
     89 
     90         /* update ev_rt_now, do magic */
     91         time_update (EV_A_ waittime + sleeptime);
     92       }
     93 
     94       /* queue pending timers and reschedule them */
     95       timers_reify (EV_A); /* relative timers called last *///对pending的timer事件进行收集
     96 
     97       EV_INVOKE_PENDING; //遍历所有pending事件
     98     }
     99   while (expect_true (
    100     activecnt
    101     && !loop_done
    102     && !(flags & (EVRUN_ONCE | EVRUN_NOWAIT))
    103   ));
    104 
    105   if (loop_done == EVBREAK_ONE)
    106     loop_done = EVBREAK_CANCEL;
    107 
    108   return activecnt;
    109 }

     所有总结下,ev_run是libev的核心,

    他主要做了五件事情:

    1.更新更改的FD事件

    2.进行必要的sleep

    3.backend_poll收集pending的IO事件

    4.收集pending的timer事件

    5.调用所有pending的事件

    ok,就是这样了!但是还有很多细节啊,尼玛代码之虐心,非比寻常啊!

  • 相关阅读:
    Python 写Windows Service服务程序
    关于Python 获取windows信息收集
    Pyqt 获取windows系统中已安装软件列表
    Python 打开目录与指定文件
    【转载】Pyqt 编写的俄罗斯方块
    Python win32api提取exe图标icon
    Pyqt QListWidget之缩略图列表
    Pyqt 时时CPU使用情况
    Python 的三目运算
    Chrome Crx 插件下载
  • 原文地址:https://www.cnblogs.com/xiangshancuizhu/p/3250558.html
Copyright © 2011-2022 走看看