C-libev Learning Notes-Event Library Source Read 6-API-ev_default_loop(),ev_init()

Keywords: C++

ev_default_loop()

Declarations:

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 */

Author's note:

/* the default loop is the only one that handles signals and child watchers */
/* you can call this as often as you like */

The default loop is the only loop that handles signals and submonitors and can be invoked at any time.
It acts as a critical step, and the use of libev can be roughly divided into these steps:

1. Initialize struct ev_loop structure by calling ev_default_loop
2. Call ev_io_init to initialize the monitor. This macro (function) mainly calls ev_init and ev_io_set, mainly responsible for binding the monitor and callback functions
3. Call ev_io_start to start the monitor, which adds the monitor's file descriptor (Linux Everything Files) to the loop->anfds structure
4. Call ev_run to wait for the event to trigger

Our previous example had this sentence:

struct ev_loop *main_loop = ev_default_loop(0);//New Drive
ev_io_start(main_loop,&server_sock_w);//Bind Monitor to Drive - Register
ev_run(main_loop,0);//Usually set to 0, meaning that the drive does not stop until all monitors stop, or you can break manually

This main_loop is a main loop. All the sub-monitors need to be registered in the main loop. Here I call it'drive'. The advantage of using the main loop and sub-loop is that in concurrent programming, the monitors of each loop will not compete and interfere with each other.

This function has two definitions corresponding to different conditions:

#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 */

For EV_MULTIPLICITY:

#ifndef EV_MULTIPLICITY
# define EV_MULTIPLICITY EV_FEATURE_CONFIG
#endif

The EV_MULTIPLICITY macro is used to determine whether multiple loops are supported or not. A default loop structure, default_loop_struct, and a pointer to it, ev_default_loop_ptr, are provided.
If multiple loops are supported, default_loop_struct is a static struct ev_loop type structure that contains various members, such as ev_tstamp ev_rt_now;Int pendingpri;Ev_default_loop_ptr, for example, is a pointer to the struct ev_loop type. If multiple loops are not supported, the struct ev_loop structure described above no longer exists, its members are defined as static variables, and ev_default_loop_ptr is only an int variable to indicate whether the "loop" has been initialized successfully.

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

The return values of these two functions are an ev_loop* pointer and an int, which you can imagine how to use in a programming language without a pointer.
Their parameters are the same:

unsigned int flags EV_CPP (= 0);//unsigned int flags = 0, parameter with default value

Function Definition:

#if EV_MULTIPLICITY //Supports multiple loop s
ecb_cold
struct ev_loop * //Support function return value is ev_loop*
#else
int //Return value int is not supported
#endif
ev_default_loop (unsigned int flags) EV_THROW //flags defaults to 0
{
  if (!ev_default_loop_ptr) //If ev_default_loop_ptr is not defined
    {
#if EV_MULTIPLICITY
      EV_P = ev_default_loop_ptr = &default_loop_struct;
      //default_loop_struct is a structure
      //ev_default_loop_ptr is a structure pointer
      //# define EV_P  struct ev_loop *loop 
#else
      ev_default_loop_ptr = 1;
#endif

      loop_init (EV_A_ flags);//Initialization, parameters: struct ev_loop *loop, flags
      //A subsequent reanalysis of the loop_init() function, which initializes the main loop

      if (ev_backend (EV_A))//View backend lists and suggestions
        {
#if EV_CHILD_ENABLE //If subprocesses or threads are supported, follow-up analysis of the following functions
          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;//Return structure pointer
}

Structures and structure pointers are defined as follows:

#if EV_MULTIPLICITY
 //Support multiple loops
  struct ev_loop
  {
    ev_tstamp ev_rt_now;//double
    #define ev_rt_now ((loop)->ev_rt_now)
    //These predefinations are for uniform specification writing, where loop s do not exist by themselves, and other global variables ->ev_xxx are for specification writing
    //Defining the variable ev_rt_now before defining the macro does not replace the previously defined variable in the structure because the scope of the macro is from the beginning to the end of the scope
    //So what does it mean to define this macro?
    //This is undoubtedly a member variable in the structure pointer
    //After defining the structure pointer, we can use the macro definition directly
    //Instead of using loop->ev_xxx, just keep the code simple
    #define VAR(name,decl) decl
    //This macro definition is to simplify the code in ev_vars.h
      #include "ev_vars.h"
      //Here ev_vars.h is all a macro definition like VARxxx
    #undef VAR //Undefine macro for VAR later
  };
  #include "ev_wrap.h" 
  //ev_wrap.h is full of macro definitions like #define XXX ((loop) ->xxx)
  //In other words, everything in this header file is a variable in the loop structure
  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
  //Without a pointer, there would be no 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 */
// Notice the comma','
# define EV_A  loop 

The main function in this function is loop_init()

loop_init()

Function Definition:

/* initialise a loop structure, must be zero-initialised */
noinline ecb_cold
//This heavyweight function is generally not inlined

static void
loop_init (EV_P_ unsigned int flags) EV_THROW //EV_P_is struct ev_loop *loop,
{
  if (!backend)
  //#define backend ((loop)->backend)
    {
      origflags = flags;
      //#define origflags ((loop)->origflags)

//Macro definitions are used so much that if else statements can be cumbersome. Why? Because macro definitions are precompiled, they are faster?

#if EV_USE_REALTIME //calendar time
//#ifndef CLOCK_REALTIME
//# undef EV_USE_REALTIME
//# define EV_USE_REALTIME 0
//#endif
      if (!have_realtime)
        {
          struct timespec ts;
          //Structures in standard header file time.h

          if (!clock_gettime (CLOCK_REALTIME, &ts))
          //#  define clock_gettime(id, ts) syscall (SYS_clock_gettime, (id), (ts)) 
          //syscall system call
          //CLOCK_REALTIME System Call Parameters

            have_realtime = 1;
            //static EV_ATOMIC_T have_realtime;
            //# define EV_ATOMIC_T sig_atomic_t volatile
            //typedef int sig_atomic_t;
            // volatile keyword: Ensure that instructions are not omitted for optimization
        }
#endif

#if EV_USE_MONOTONIC //System Startup Time
      if (!have_monotonic)
        {
          struct timespec ts;

          if (!clock_gettime (CLOCK_MONOTONIC, &ts))
            have_monotonic = 1;
        }
#endif

      /* pid check not overridable via env */
      //pid check cannot be overwritten by env
#ifndef _WIN32
      if (flags & EVFLAG_FORKCHECK)
        curpid = getpid ();
        //#define curpid ((loop)->curpid)
        //EVFLAG_FORKCHECK = 0x02000000U, /* check for a fork in each iteration */Fork in the middle of each iteration
        //getpid() system call to get the process identifier, which many programs use to create temporary files to avoid problems caused by the same temporary files
#endif

      if (!(flags & EVFLAG_NOENV)
          && !enable_secure ()
          && getenv ("LIBEV_FLAGS"))
          //EVFLAG_NOENV     = 0x01000000U, /* do NOT consult environment */
        flags = atoi (getenv ("LIBEV_FLAGS"));
        //Involves three functions
        
      ev_rt_now          = ev_time ();
      // #define ev_rt_now((loop) ->ev_rt_now) to get the current calendar time
      mn_now             = get_clock ();
      //#define mn_now((loop) ->mn_now) to get the current system time
      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
//Feature Interface
//#define EV_FEATURE_API      ((EV_FEATURES) &  8)
      invoke_cb          = ev_invoke_pending;
      //#define invoke_cb ((loop) ->invoke_cb) function pointer
      //ev_invoke_pending is a function
#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;
//All of the above are initializations of loop members

#if EV_USE_INOTIFY
//Using Linux's inotify mechanism
      fs_fd              = flags & EVFLAG_NOINOTIFY ? -1 : -2;
#endif
#if EV_USE_SIGNALFD
//Using Linux signalfd mechanism
      sigfd              = flags & EVFLAG_SIGNALFD  ? -2 : -1;
#endif

      if (!(flags & EVBACKEND_MASK))
        flags |= ev_recommended_backends ();
        //flags = flags|ev_recommended_backends ()
        //backend types supported by the current system, such as select, poll... choose how to initialize based on the underlying mechanism
#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
//These are the initial choices for underlying IO


//Understand that this is a ready initialization
//Initialize ev_prepare Monitor pending_w
      ev_prepare_init (&pending_w, pendingcb);
      //#define pending_w ((loop)->pending_w)
      //The second parameter is the function pointer, pendingcb is a function, but it is an empty function, there is no statement in the body of the function, the return value is void, the author explained: /* dummy callback for pending events */
      //#define ev_prepare_init(ev,cb)               do { ev_init ((ev), (cb)); ev_prepare_set ((ev)); } while (0)
      //Similar to ev_io_init
      // Equals ev_init() and ev_xxx_set()
      //However, there are many events without the ev_xxx_set() function, but to keep the code simple and canonical, uniform..
      //The author uses a macro to define all ev_xxx_set() functions, which are empty if they do not exist.
      //Then add the following comment: /* nop, yes, this is a serious in-joke */
      //#define ev_prepare_set(ev)                   /* nop, yes, this is a serious in-joke */
//If signal ing or async is supported
#if EV_SIGNAL_ENABLE || EV_ASYNC_ENABLE
      ev_init (&pipe_w, pipecb);//Initialize Pipeline Monitor pipe_w
      ev_set_priority (&pipe_w, EV_MAXPRI);//Set Priority Function
      //# define ev_set_priority(ev,pri)             (   (ev_watcher *)(void *)(ev))->priority = (pri)
#endif
    }
}

Posted by seoreferrals on Mon, 20 Sep 2021 02:50:55 -0700