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