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

本文详细解析了libev库中的ev_default_loop函数,包括其作用、不同条件下的定义及实现方式,并介绍了与之相关的loop_init函数。libev是一个高效的事件库,被广泛应用于并发编程中。

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
    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

adce9

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

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

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

打赏作者

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

抵扣说明:

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

余额充值