C-libev学习笔记-事件库源码阅读9-API-ev_loop_fork(),ev_backend(),ev_now_update()

ev_loop_fork()

函数声明:

/* this needs to be called after fork, to duplicate the loop */
/* 这个函数要在fork之后调用,去复制循环*/
/* when you want to re-use it in the child */
/* 当你想去 重用它 在子进程中*/
/* you can call it in either the parent or the child */
/* 你可以调用它在父进程或子进程中,任何时间,任何地方*/
/* you can actually call it at any time, anywhere :) */
EV_API_DECL void ev_loop_fork (EV_P) EV_THROW;

函数定义:

void
ev_loop_fork (EV_P) EV_THROW
{
  postfork = 1;
  // #define postfork ((loop)->postfork)
}

从作者的描述来看,如果你在fork了一个进程,并且想在这个进程中使用另一个进程中的循环,则可调用此函数,此函数将复制一份循环到此进程中,但我们看底层原理,它仅仅是把postfork 也就是 loop->postfork 设置成1,表示有别的进程在使用这个循环,那么可能在对循环的销毁上,或者一些操作上,要受此参数的影响,那么笔者理解它可能类似,浅拷贝,因为它并没有真正复制,而是使用了同一个。

ev_backend()

函数声明:

EV_API_DECL unsigned int ev_backend (EV_P) EV_THROW; /* backend in use by loop */ /* 循环使用的后端*/

函数定义:

unsigned int
ev_backend (EV_P) EV_THROW
{
  return backend;
  // #define backend ((loop)->backend)
}

返回循环使用的后端,这个后端只是一个代号,以前记录的函数我记得有给这个变量赋值的函数。

ev_now_update()

函数声明:

EV_API_DECL void ev_now_update (EV_P) EV_THROW; /* update event loop time */ /* 更新事件循环的时间*/

函数定义:

void
ev_now_update (EV_P) EV_THROW
{
  time_update (EV_A_ 1e100);
}

通过嵌套的函数来看,更新事件循环的时间开销是非常大的。

time_update()

/* fetch new monotonic and realtime times from the kernel */
/* also detect if there was a timejump, and act accordingly */
/*从内核获取新的单调和实时时间*/
/*同时检测是否存在时间跳变,并相应地采取行动*/

// static
inline_speed void
time_update (EV_P_ ev_tstamp max_block)
{
    // 如果使用的是monotonic时间
#if EV_USE_MONOTONIC
  if (expect_true (have_monotonic)) // 等价 if(have_monotonic)
    {
      int i;
      ev_tstamp odiff = rtmn_diff;
      // #define rtmn_diff ((loop)->rtmn_diff)

      mn_now = get_clock ();
      // #define mn_now ((loop)->mn_now)

      /* only fetch the realtime clock every 0.5*MIN_TIMEJUMP seconds */
      /* interpolate in the meantime */
      /*仅 每0.5*MIN_TIMEJUMP秒 获取一次实时时钟*/
      /*同时插入*/

      // #define MIN_TIMEJUMP  1. /* minimum timejump that gets detected (if monotonic clock available) */ /* 如果monotonic时钟可用,这是检测的最小跳时间变*/
      // #define now_floor ((loop)->now_floor)
      if (expect_true (mn_now - now_floor < MIN_TIMEJUMP * .5))
        {
          ev_rt_now = rtmn_diff + mn_now;
          // #define ev_rt_now ((loop)->ev_rt_now)
          return;
        }

      now_floor = mn_now;
      ev_rt_now = ev_time ();

      /* loop a few times, before making important decisions.
       * on the choice of "4": one iteration isn't enough,
       * in case we get preempted during the calls to
       * ev_time and get_clock. a second call is almost guaranteed
       * to succeed in that case, though. and looping a few more times
       * doesn't hurt either as we only do this on time-jumps or
       * in the unlikely event of having been preempted here.
       */
      // 在做出重要决定之前,循环几次。
      // 选择“4”:一次迭代是不够的,
      // 以防在调用ev_time和get_clock时被抢占。
      // 不过,在这种情况下,第二次呼叫几乎肯定会成功。
      // 再循环几次也不会有什么坏处,因为我们只会在时间跳跃时这样做,
      // 或者在不太可能的情况下被抢先。

      for (i = 4; --i; )
        {
          ev_tstamp diff;
          rtmn_diff = ev_rt_now - mn_now;

          diff = odiff - rtmn_diff;

          if (expect_true ((diff < 0. ? -diff : diff) < MIN_TIMEJUMP))
            return; /* all is well */

          ev_rt_now = ev_time ();
          mn_now    = get_clock ();
          now_floor = mn_now;
        }

      /* no timer adjustment, as the monotonic clock doesn't jump */
      // 没有定时器调整,因为单调时钟不会跳转
      /* timers_reschedule (EV_A_ rtmn_diff - odiff) */
      
# if EV_PERIODIC_ENABLE
      periodics_reschedule (EV_A);
# endif
    }
  else
#endif
    {
      ev_rt_now = ev_time ();

      if (expect_false (mn_now > ev_rt_now || ev_rt_now > mn_now + max_block + MIN_TIMEJUMP))
        {
          /* adjust timers. this is easy, as the offset is the same for all of them */
          // 调整计时器。这很容易,因为它们的偏移量都相同
          timers_reschedule (EV_A_ ev_rt_now - mn_now);
#if EV_PERIODIC_ENABLE
          periodics_reschedule (EV_A);
#endif
        }

      mn_now = ev_rt_now;
    }
}

get_clock()

inline_size ev_tstamp
get_clock (void)
{
#if EV_USE_MONOTONIC
  if (expect_true (have_monotonic))
    {
      struct timespec ts;
      clock_gettime (CLOCK_MONOTONIC, &ts);
      return ts.tv_sec + ts.tv_nsec * 1e-9;
    }
#endif

  return ev_time ();
}

根据是否为monotonic时间,是则使用系统调用syscall (SYS_clock_gettime, (id), (ts))返回的时间,不是则使用ev_time()返回的时间 ev_time() 在-4文章里涉及过

timers_reschedule()

/* adjust all timers by a given offset */
// 按给定的偏移量调整所有计时器 --偏移量是 更新的时间 和 当时的时间 的差值
noinline ecb_cold // 不会被优先考虑优化的函数
static void
timers_reschedule (EV_P_ ev_tstamp adjust)
{
  int i;
  // #define timercnt ((loop)->timercnt) 计时器的数量,要调整每一个计时器
  for (i = 0; i < timercnt; ++i)
    {
      ANHE *he = timers + i + HEAP0; 
      // #define timers ((loop)->timers)
      // #define HEAP0 (DHEAP - 1) /* index of first element in heap */ /* 堆中第一个元素的索引 */
      // #define DHEAP 4

      ANHE_w (*he)->at += adjust;
      ANHE_at_cache (*he);
    }
}

periodics_reschedule()

/* simply recalculate all periodics */
/* 重新计算所有周期 */
/* TODO: maybe ensure that at least one event happens when jumping forward? */
/* TODO:也许可以确保向前跳跃时至少发生一个事件?*/
noinline ecb_cold
static void
periodics_reschedule (EV_P)
{
  int i;

  /* adjust periodics after time jump */
  /* 调整时间跳跃后的周期 */

  // #define periodiccnt ((loop)->periodiccnt)
  for (i = HEAP0; i < periodiccnt + HEAP0; ++i)
    {
      
      ev_periodic *w = (ev_periodic *)ANHE_w (periodics [i]);

      if (w->reschedule_cb)
          // #define ev_at(w) ((WT)(w))->at
        ev_at (w) = w->reschedule_cb (w, ev_rt_now);
      else if (w->interval)
        periodic_recalc (EV_A_ w);

      ANHE_at_cache (periodics [i]);
    }

  reheap (periodics, periodiccnt);
}
#endif

periodic_recalc()

noinline
static void
periodic_recalc (EV_P_ ev_periodic *w)
{
  ev_tstamp interval = w->interval > MIN_INTERVAL ? w->interval : MIN_INTERVAL;
  ev_tstamp at = w->offset + interval * ev_floor ((ev_rt_now - w->offset) / interval);

  /* the above almost always errs on the low side */
  while (at <= ev_rt_now)
    {
      ev_tstamp nat = at + w->interval;

      /* when resolution fails us, we use ev_rt_now */
      if (expect_false (nat == at))
        {
          at = ev_rt_now;
          break;
        }

      at = nat;
    }

  ev_at (w) = at;
}

该函数用来计算下一个触发时间点,

ANHE结构体

/* Heap Entry */
/* 堆入口*/
#if EV_HEAP_CACHE_AT
// # define EV_HEAP_CACHE_AT EV_FEATURE_DATA
// #define EV_FEATURE_DATA     ((EV_FEATURES) &  2)
  /* a heap element */
  /* 堆的一个元素 */
  typedef struct {
    ev_tstamp at;// double at
    WT w; // typedef ev_watcher_time *WT;
  } ANHE;

  #define ANHE_w(he)        (he).w     /* access watcher, read-write */ /* 访问监视器,读写*/
  #define ANHE_at(he)       (he).at    /* access cached at, read-only */ /* 访问缓存,只读*/
  #define ANHE_at_cache(he) (he).at = (he).w->at /* update at from watcher */ /* 更新监视器*/
#else
  /* a heap element */
  typedef WT ANHE;

  #define ANHE_w(he)        (he)
  #define ANHE_at(he)       (he)->at
  #define ANHE_at_cache(he)
#endif
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橙子砰砰枪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值