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,就是这样了!但是还有很多细节啊,尼玛代码之虐心,非比寻常啊!

原文地址:https://www.cnblogs.com/xiangshancuizhu/p/3250558.html