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;#elseEV_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_MULTIPLICITYEV_P = ev_default_loop_ptr = &default_loop_struct;//default_loop_struct 是一个结构体//ev_default_loop_ptr 是结构体指针//# define EV_P  struct ev_loop *loop
#elseev_default_loop_ptr = 1;
#endifloop_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}elseev_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 */#elseEV_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
//#endifif (!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 _WIN32if (flags & EVFLAG_FORKCHECK)curpid = getpid ();//#define curpid ((loop)->curpid)//EVFLAG_FORKCHECK = 0x02000000U, /* check for a fork in each iteration */在每次迭代中间差fork//getpid() 系统调用,取得进程识别码,许多程序利用取到的此值来建立临时文件,以避免临时文件相同带来的问题
#endifif (!(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 是一个函数
#endifio_blocktime       = 0.;timeout_blocktime  = 0.;backend            = 0;backend_fd         = -1;sig_pending        = 0;
#if EV_ASYNC_ENABLEasync_pending      = 0;
#endifpipe_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;
#endifif (!(flags & EVBACKEND_MASK))flags |= ev_recommended_backends ();//flags = flags|ev_recommended_backends ()//得到当前系统支持的backend类型,比如select,poll...根据底层机制,选择初始化的方式
#if EV_USE_IOCPif (!backend && (flags & EVBACKEND_IOCP  )) backend = iocp_init   (EV_A_ flags);
#endif
#if EV_USE_PORTif (!backend && (flags & EVBACKEND_PORT  )) backend = port_init   (EV_A_ flags);
#endif
#if EV_USE_KQUEUEif (!backend && (flags & EVBACKEND_KQUEUE)) backend = kqueue_init (EV_A_ flags);
#endif
#if EV_USE_EPOLLif (!backend && (flags & EVBACKEND_EPOLL )) backend = epoll_init  (EV_A_ flags);
#endif
#if EV_USE_POLLif (!backend && (flags & EVBACKEND_POLL  )) backend = poll_init   (EV_A_ flags);
#endif
#if EV_USE_SELECTif (!backend && (flags & EVBACKEND_SELECT)) backend = select_init (EV_A_ flags);
#endif
//以上就是对底层IO的初始化选择//可以理解这是一个准备的初始化
//初始化 ev_prepare监视器 pending_wev_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_ENABLEev_init (&pipe_w, pipecb);//初始化管道监视器 pipe_wev_set_priority (&pipe_w, EV_MAXPRI);//设置优先级函数//# define ev_set_priority(ev,pri)             (   (ev_watcher *)(void *)(ev))->priority = (pri)
#endif}
}

C-libev学习笔记-事件库源码阅读6-API-ev_default_loop(),ev_init()相关推荐

  1. Halide学习笔记----Halide tutorial源码阅读3

    Halide入门教程03 // Halide tutorial lesson 3: Inspecting the generated code // Halide入门第三课:检测生成代码// This ...

  2. Halide学习笔记----Halide tutorial源码阅读2

    Halide入门教程02 // Halide tutorial lesson 2: Processing images // Halide入门第二课: 处理图像// This lesson demon ...

  3. Halide学习笔记----Halide tutorial源码阅读5

    Halide入门教程05 // Halide教程第五课:向量化,并行化,平铺,数据分块 // 本课展示了如何才操作函数像素索引的计算顺序,包括向量化/并行化/平铺/分块等技术// 在linux系统中, ...

  4. python学习笔记之三——MakeHuman源码阅读

    1.@装饰器的用法 简单的说,@装饰器就是用来提供调用的, def funA(arg):print 'A'a=arg()@funA def funB():print 'B' 此处的@相当于funA(f ...

  5. K8s基础知识学习笔记及部分源码剖析

    K8s基础知识学习笔记及部分源码剖析 在学习b站黑马k8s视频资料的基础上,查阅了配套基础知识笔记和源码剖析,仅作个人学习和回顾使用. 参考资料: 概念 | Kubernetes 四层.七层负载均衡的 ...

  6. JUC.Condition学习笔记[附详细源码解析]

    JUC.Condition学习笔记[附详细源码解析] 目录 Condition的概念 大体实现流程 I.初始化状态 II.await()操作 III.signal()操作 3个主要方法 Conditi ...

  7. LOAM笔记及A-LOAM源码阅读

    转载出处:LOAM笔记及A-LOAM源码阅读 - WellP.C - 博客园 导读 下面是我对LOAM论文的理解以及对A-LOAM的源码阅读(中文注释版的A-LOAM已经push到github,见A- ...

  8. Vuex 4源码学习笔记 - 通过Vuex源码学习E2E测试(十一)

    在上一篇笔记中:Vuex 4源码学习笔记 - 做好changelog更新日志很重要(十) 我们学到了通过conventional-changelog来生成项目的Changelog更新日志,通过更新日志 ...

  9. 【从线性回归到 卷积神经网络CNN 循环神经网络RNN Pytorch 学习笔记 目录整合 源码解读 B站刘二大人 绪论(0/10)】

    深度学习 Pytorch 学习笔记 目录整合 数学推导与源码详解 B站刘二大人 目录传送门: 线性模型 Linear-Model 数学原理分析以及源码详解 深度学习 Pytorch笔记 B站刘二大人( ...

最新文章

  1. hiho_1139_二分+bfs搜索
  2. 两次include一个文件的问题
  3. 路由 交换 网桥 相关转贴
  4. java入门从哪下手_java新手0基础如何最快速的入门
  5. poj 1860 Currency Exchange (最短路bellman_ford思想找正权环 最长路)
  6. vue.js 入门,简介
  7. hash函数MurmurHash
  8. VB:读取及设定NumLock/CapsLock/ScrollLock的值
  9. 【数据科学】什么是数据科学?
  10. java 哈希表入门
  11. 【图像处理】基于matlab GUI自动报靶系统(重弹孔)【含Matlab源码 973期】
  12. eclipse中文包和控制台中文显示乱码
  13. 第一次:《三国志2017》游戏纯玩体验及总结
  14. java识别手写文字_Java 实现OCR 识别图像文字(手写中文)----tess4j
  15. 资阳停车场系统推荐_专业停车场系统维护业务广泛
  16. hl uoj1841 走格子
  17. 从零搭建Hexo博客并部署腾讯云服务器(宝宝级教学)
  18. 锁仓怎么解_锁仓后解锁技巧
  19. pvr.ccz文件转png方法
  20. css鼠标经过字体抖动,jQuery+css3实现文字跟随鼠标的上下抖动

热门文章

  1. 解决Chrome浏览器中部分字体显示模糊的问题
  2. Python_BeautifulSoup4爬虫应用案例
  3. UML-类图-Composition(组合)和Aggregation(聚合)的区别
  4. 全球同服 游戏服务器架构设计
  5. python脚本开机自动运行
  6. (新的开始)4- Flask构建弹幕微电影网站-环境搭建
  7. 牛客网练习题 - 下厨房(Java)
  8. 上海的大学计算机专业高考,“传奇考生”确定就读上海海事大学计算机专业
  9. 蓝桥杯单片机零基础到国二经验分享
  10. 计算机导论学科性质,《计算机导论》教学大纲.doc