一:代码流程
在Libev中,启动一个IO监视器,等待该监视器上的事件触发,然后调用该监视器的回调函数。整个的流程是这样的:
首先调用ev_default_loop初始化struct ev_loop结构;
然后调用ev_io_init初始化监视器中的属性,该宏主要就是调用ev_init和ev_io_set;
然后调用ev_io_start启动该监视器,该函数主要是将监视器添加到loop->anfds结构中,将监视的描述符添加到((loop)->fdchanges)中;
调用ev_run开始等待事件的触发,该函数中:
首先会调用fd_reify函数,该函数根据((loop)->fdchanges)中记录的描述符,将该描述符上的事件添加到backend所使用的数据结构中,比如select中的fd_set中;
然后调用time_update更新当前的时间,如果日历时间被人为调整的话,则相应的调整超时事件和周期事件;
调用backend_poll开始等待事件的发生,如果事件在规定时间内触发的话,则会调用fd_event将触发的监视器记录到loop->pendings中;
backend的监听函数(select,poll,epoll_wait)返回之后,首先再次调用time_update更新当前的时间,然后调用ev_invoke_pending,依次处理loop->pendings中的监视器,调用该监视器的回调函数。
以上就是Libev中IO监视器的工作流程,下面详细分析各个函数:
1:ev_default_loop函数
#if EV_MULTIPLICITY
struct ev_loop *
#else
int
#endif
ev_default_loop (unsigned int flags)
{
if (!ev_default_loop_ptr)
{
#if EV_MULTIPLICITY
struct ev_loop *loop = ev_default_loop_ptr = &default_loop_struct;
#else
ev_default_loop_ptr = 1;
#endif
loop_init (loop, flags);
if (ev_backend (loop))
{
#if EV_CHILD_ENABLE
ev_signal_init (&childev, childcb, SIGCHLD);
ev_set_priority (&childev, EV_MAXPRI);
ev_signal_start (EV_A_ &childev);
ev_unref (loop); /* child watcher should not keep loop alive */
#endif
}
else
ev_default_loop_ptr = 0;
}
return ev_default_loop_ptr;
}
EV_MULTIPLICITY宏用来决定是否支持多个loop。系统提供了默认的loop结构default_loop_struct,和指向其的指针ev_default_loop_ptr。
如果支持多个loop,则default_loop_struct就是一个静态的struct ev_loop类型的结构体,其中包含了各种成员,比如ev_tstamp ev_rt_now; int pendingpri;等等。
ev_default_loop_ptr就是指向struct ev_loop 类型的指针。
如果不支持多个loop,则上述的struct ev_loop结构就不复存在,其成员都是以静态变量的形式进行定义,而ev_default_loop_ptr也只是一个int变量,用来表明”loop”是否已经初始化成功。
下面的描述,均以支持多个loop为准。
在ev_default_loop中,首先是调用loop_init初始化loop中的各种成员:
static void loop_init (struct ev_loop *loop, unsigned int flags)
{
if (!backend)
{
origflags = flags;
#if EV_USE_REALTIME
if (!have_realtime)
{
struct timespec ts;
if (!clock_gettime (CLOCK_REALTIME, &ts))
have_realtime = 1;
}
#endif
#if EV_USE_MONOTONIC
if (!have_monotonic)
{
struct timespec ts;
if (!clock_gettime (CLOCK_MONOTONIC, &ts))
have_monotonic = 1;
}
#endif
/* pid check not overridable via env */
#ifndef _WIN32
if (flags & EVFLAG_FORKCHECK)
curpid = getpid ();
#endif
if (!(flags & EVFLAG_NOENV) && !enable_secure () && getenv ("LIBEV_FLAGS"))
flags = atoi (getenv ("LIBEV_FLAGS"));
ev_rt_now = ev_time ();
mn_now = get_clock ();
now_floor = mn_now;
rtmn_diff = ev_rt_now - mn_now;
#if EV_FEATURE_API
invoke_cb = ev_invoke_pending;
#endif
io_blocktime = 0.;
timeout_blocktime = 0.;
backend = 0;
backend_fd = -1;
sig_pending = 0;
#if EV_ASYNC_ENABLE
async_pending = 0;
#endif
pipe_write_skipped = 0;
pipe_write_wanted = 0;
evpipe [0] = -1;
evpipe [1] = -1;
#if EV_USE_INOTIFY
fs_fd = flags & EVFLAG_NOINOTIFY ? -1 : -2;
#endif
#if EV_USE_SIGNALFD
sigfd = flags &