ev_default_loop()
声明:
EV_API_DECL struct ev_loop *ev_default_loop (unsigned int flags EV_CPP (= 0)) EV_THROW;
EV_API_DECL int ev_default_loop (unsigned int flags EV_CPP (= 0)) EV_THROW; /* returns true when successful */
作者的注释:
/* the default loop is the only one that handles signals and child watchers */
/* you can call this as often as you like */
默认循环是唯一的处理 信号 和 子监视器 的循环,可以随时调用。
它作用于非常关键的一步,libev的使用大致可以分为这几步:
1.调用ev_default_loop初始化struct ev_loop结构
2.调用ev_io_init初始化监视器,该宏(函数)主要是调用ev_init和ev_io_set,主要是负责绑定监视器和回调函数
3.调用ev_io_start启动监视器,该宏(函数)主要是将监视器的文件描述符(Linux万物皆文件)添加到loop->anfds结构体中
4.调用ev_run等待事件的触发
我们以前的例子有这一句:
struct ev_loop *main_loop = ev_default_loop(0);//新建驱动器
ev_io_start(main_loop,&server_sock_w);//将监视器与驱动器绑定-注册
ev_run(main_loop,0);//通常设置为0,表示所有监视器停止后驱动器才停止,还可以手动break
这个main_loop是主循环,所有的子监视器都要注册到主循环里,这里我把它叫‘驱动器’,使用主循环 和 子循环 的好处是在并发编程中,各个循环的监视器不会发生竞争,互不干扰。
这个函数有两个定义,对应不同的条件:
#if EV_MULTIPLICITY
/* the default loop is the only one that handles signals and child watchers */
/* you can call this as often as you like */
EV_API_DECL struct ev_loop *ev_default_loop (unsigned int flags EV_CPP (= 0)) EV_THROW;
#else
EV_API_DECL int ev_default_loop (unsigned int flags EV_CPP (= 0)) EV_THROW; /* returns true when successful */
对EV_MULTIPLICITY:
#ifndef EV_MULTIPLICITY
# define EV_MULTIPLICITY EV_FEATURE_CONFIG
#endif
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”是否已经初始化成功。
EV_FEATURE_CONFIG:
#define EV_FEATURE_CONFIG ((EV_FEATURES) & 4)
#ifndef EV_FEATURES
# if defined __OPTIMIZE_SIZE__
# define EV_FEATURES 0x7c
# else
# define EV_FEATURES 0x7f
# endif
#endif
这两个函数的返回值一个是 ev_loop* 指针,一个是int,可以想象,如果在没有指针的编程语言中,该如何使用。
他们的参数相同:
unsigned int flags EV_CPP (= 0);//unsigned int flags = 0,带默认值的参数
函数定义:
#if EV_MULTIPLICITY //是否支持多loop
ecb_cold
struct ev_loop * //支持函数返回值为 ev_loop*
#else
int //不支持返回值为int
#endif
ev_default_loop (unsigned int flags) EV_THROW //flags默认值为0
{
if (!ev_default_loop_ptr) //如果没定义ev_default_loop_ptr
{
#if EV_MULTIPLICITY
EV_P = ev_default_loop_ptr = &default_loop_struct;
//default_loop_struct 是一个结构体
//ev_default_loop_ptr 是结构体指针
//# define EV_P struct ev_loop *loop
#else
ev_default_loop_ptr = 1;
#endif
loop_init (EV_A_ flags);//初始化,参数:struct ev_loop *loop,flags
//对loop_init()函数后续再分析,它是对主循环进行初始化
if (ev_backend (EV_A))//查看后端列表和建议
{
#if EV_CHILD_ENABLE //如果支持子进程或子线程,下列函数后续分析
ev_signal_init (&childev, childcb, SIGCHLD);
ev_set_priority (&childev, EV_MAXPRI);
ev_signal_start (EV_A_ &childev);
ev_unref (EV_A); /* child watcher should not keep loop alive */
#endif
}
else
ev_default_loop_ptr = 0;
}
return ev_default_loop_ptr;//返回结构体指针
}
结构体和结构体指针的定义如下:
#if EV_MULTIPLICITY
//支持多循环
struct ev_loop
{
ev_tstamp ev_rt_now;//double
#define ev_rt_now ((loop)->ev_rt_now)
//这些预定义是为了统一规范的写法,预定义的时候loop本身并不存在,和其他的全局变量(loop)->ev_xxx 都是为了规范写法
//先定义 变量 ev_rt_now 后定义宏,那么后定义的宏并不会替换掉结构体里前面定义的变量,因为宏的作用域是从定义开始到作用域末尾
//那么定义这个宏有什么意义?
//这个写法,毫无疑问是结构体指针里面的一个成员变量
//在后续定义了结构指针之后,我们就可以直接使用宏定义
//而不用使用 loop->ev_xxx 这种写法了,只是,只是,只是让代码简洁
#define VAR(name,decl) decl
//这个宏定义是为了简化ev_vars.h里面的代码
#include "ev_vars.h"
//这里的 ev_vars.h 全是 VARxxx 这样的宏定义
#undef VAR //后文取消对VAR的宏定义
};
#include "ev_wrap.h"
//ev_wrap.h 里全是 #define xxx ((loop)->xxx) 这样的宏定义
//换句话说,这个头文件里面的所有内容,都是loop结构体里的变量
static struct ev_loop default_loop_struct;
EV_API_DECL struct ev_loop *ev_default_loop_ptr = 0; /* needs to be initialised to make it a definition despite extern */
#else
EV_API_DECL ev_tstamp ev_rt_now = 0; /* needs to be initialised to make it a definition despite extern */
#define VAR(name,decl) static decl;
#include "ev_vars.h"
#undef VAR
//没有指针,那就没有 ev_wrap.h
static int ev_default_loop_ptr;
#endif
#if EV_MULTIPLICITY
struct ev_loop;
# define EV_P struct ev_loop *loop /* a loop as sole parameter in a declaration */
# define EV_P_ EV_P, /* a loop as first of multiple parameters */
// 注意 逗号 ‘,’
# define EV_A loop
这个函数里的主要功能函数是 loop_init()
loop_init()
函数定义:
/* initialise a loop structure, must be zero-initialised */
noinline ecb_cold
//这种重量级的函数一般都不会内联
static void
loop_init (EV_P_ unsigned int flags) EV_THROW //EV_P_ 是 struct ev_loop *loop,
{
if (!backend)
//#define backend ((loop)->backend)
{
origflags = flags;
//#define origflags ((loop)->origflags)
//宏定义用的多了,if else 语句都显得麻烦,为什么?因为宏定义是预编译,它更快啊
#if EV_USE_REALTIME //日历时间
//#ifndef CLOCK_REALTIME
//# undef EV_USE_REALTIME
//# define EV_USE_REALTIME 0
//#endif
if (!have_realtime)
{
struct timespec ts;
//标准头文件 time.h 里的结构体
if (!clock_gettime (CLOCK_REALTIME, &ts))
//# define clock_gettime(id, ts) syscall (SYS_clock_gettime, (id), (ts))
//syscall 系统调用
//CLOCK_REALTIME 系统调用参数
have_realtime = 1;
//static EV_ATOMIC_T have_realtime;
//# define EV_ATOMIC_T sig_atomic_t volatile
//typedef int sig_atomic_t;
// volatile关键字:确保指令不会因为优化而省略
}
#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 */
//pid检查不可通过env覆盖
#ifndef _WIN32
if (flags & EVFLAG_FORKCHECK)
curpid = getpid ();
//#define curpid ((loop)->curpid)
//EVFLAG_FORKCHECK = 0x02000000U, /* check for a fork in each iteration */在每次迭代中间差fork
//getpid() 系统调用,取得进程识别码,许多程序利用取到的此值来建立临时文件,以避免临时文件相同带来的问题
#endif
if (!(flags & EVFLAG_NOENV)
&& !enable_secure ()
&& getenv ("LIBEV_FLAGS"))
//EVFLAG_NOENV = 0x01000000U, /* do NOT consult environment */
flags = atoi (getenv ("LIBEV_FLAGS"));
//涉及到三个函数
ev_rt_now = ev_time ();
// #define ev_rt_now ((loop)->ev_rt_now) 获得当前的日历时间
mn_now = get_clock ();
//#define mn_now ((loop)->mn_now) 获得当前的系统时间
now_floor = mn_now;
//#define now_floor ((loop)->now_floor)
rtmn_diff = ev_rt_now - mn_now;
//#define rtmn_diff ((loop)->rtmn_diff)
#if EV_FEATURE_API
//特征接口
//#define EV_FEATURE_API ((EV_FEATURES) & 8)
invoke_cb = ev_invoke_pending;
//#define invoke_cb ((loop)->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;
//以上全是loop成员的初始化
#if EV_USE_INOTIFY
//使用Linux 的inotify机制
fs_fd = flags & EVFLAG_NOINOTIFY ? -1 : -2;
#endif
#if EV_USE_SIGNALFD
//使用Linux 的 signalfd机制
sigfd = flags & EVFLAG_SIGNALFD ? -2 : -1;
#endif
if (!(flags & EVBACKEND_MASK))
flags |= ev_recommended_backends ();
//flags = flags|ev_recommended_backends ()
//得到当前系统支持的backend类型,比如select,poll...根据底层机制,选择初始化的方式
#if EV_USE_IOCP
if (!backend && (flags & EVBACKEND_IOCP )) backend = iocp_init (EV_A_ flags);
#endif
#if EV_USE_PORT
if (!backend && (flags & EVBACKEND_PORT )) backend = port_init (EV_A_ flags);
#endif
#if EV_USE_KQUEUE
if (!backend && (flags & EVBACKEND_KQUEUE)) backend = kqueue_init (EV_A_ flags);
#endif
#if EV_USE_EPOLL
if (!backend && (flags & EVBACKEND_EPOLL )) backend = epoll_init (EV_A_ flags);
#endif
#if EV_USE_POLL
if (!backend && (flags & EVBACKEND_POLL )) backend = poll_init (EV_A_ flags);
#endif
#if EV_USE_SELECT
if (!backend && (flags & EVBACKEND_SELECT)) backend = select_init (EV_A_ flags);
#endif
//以上就是对底层IO的初始化选择
//可以理解这是一个准备的初始化
//初始化 ev_prepare监视器 pending_w
ev_prepare_init (&pending_w, pendingcb);
//#define pending_w ((loop)->pending_w)
//第二个参数是函数指针,pendingcb是一个函数,但却是一个空函数,函数体里面没有任何语句,返回值为void,作者给的解释:/* dummy callback for pending events */
//#define ev_prepare_init(ev,cb) do { ev_init ((ev), (cb)); ev_prepare_set ((ev)); } while (0)
//和ev_io_init类似
// 等于 ev_init() 和 ev_xxx_set()
//但是,有很多事件没有 ev_xxx_set() 这个函数,但是为了保持代码的简洁和规范的统一...
//作者用宏定义了所有的 ev_xxx_set()函数,不存在的就定义为空...
//然后加了这么一句注释:/* nop, yes, this is a serious in-joke */
//#define ev_prepare_set(ev) /* nop, yes, this is a serious in-joke */
//如果支持 signal 或者 支持 async
#if EV_SIGNAL_ENABLE || EV_ASYNC_ENABLE
ev_init (&pipe_w, pipecb);//初始化管道监视器 pipe_w
ev_set_priority (&pipe_w, EV_MAXPRI);//设置优先级函数
//# define ev_set_priority(ev,pri) ( (ev_watcher *)(void *)(ev))->priority = (pri)
#endif
}
}
本文详细解析了libev库中的ev_default_loop函数,包括其作用、不同条件下的定义及实现方式,并介绍了与之相关的loop_init函数。libev是一个高效的事件库,被广泛应用于并发编程中。
1035

被折叠的 条评论
为什么被折叠?



