Resolution of libev default event loop Initialization

Source: Internet
Author: User
Tags epoll

For the first time, libev enters the default event loop. Here, the default loop flow executed in the source code is parsed. To enter the event loop, the following example is used.

intmain (void){ // use the default event loop unless you have special needs struct ev_loop *loop = EV_DEFAULT; // initialise an io watcher, then start it // this one will watch for stdin to become readable ev_io_init (&stdin_watcher, stdin_cb, /*STDIN_FILENO*/ 0, EV_READ); ev_io_start (loop, &stdin_watcher); // initialise a timer watcher, then start it // simple non-repeating 5.5 second timeout ev_timer_init (&timeout_watcher, timeout_cb, 5.5, 0.); ev_timer_start (loop, &timeout_watcher); // now wait for events to arrive ev_run (loop, 0); // break was called, so exit return 0;}

Ev_loop has been introduced in the previous section. ev_default is a macro definition, and it is a function as follows:

struct ev_loop * ev_default_loop (unsigned int flags) EV_THROW{  if (!ev_default_loop_ptr)    {#if EV_MULTIPLICITY      EV_P = ev_default_loop_ptr = &default_loop_struct;#else      ev_default_loop_ptr = 1;#endif      loop_init (EV_A_ flags);      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;}

 

Execute struct ev_loop * main_loop = ev_default_loop (0). Follow the code in the ev_default_loop function. The main logic is that if the Global Object Pointer ev_default_loop_ptr is empty, that is, when a premade drive is not used, it is directed to the Global Object default_loop_struct, and the name "loop" is used in this function to indicate the pointer of the premade drive. And function parametersEV_PAndEV_A. Thenloop_init(Note that some of the backend and other variables in the init function are all defined as global variables, such as # define backend (loop)-> backend) initialize the pre-fabricated event drive. The function is called here.EV_A_This method is simplified. After initialization, if libev supports sub-processes in the configuration, the sub-process monitor is implemented through the signal monitor. You don't need to worry about it here. You just need to know what this code will do. Here, when defining the libev function, we will see the "ev_throw" thing. Here we can ignore it. It is for "try…" in CPP... Throw "support, andEV_CPP(extern "C" {)This unusual extern "C" is also a coding technique. Now we focus on the analysis and design ideas. After understanding the general information, you can sort out the coding skills. Otherwise, reading a piece of code will be very difficult and slow. Sometimes these "hackers" are not necessarily helpful.

Next, let's take a look at what has been done during the initialization of the drive. First, check whether the system's clock_gettime supports clock_realtime and clock_monotonic. The difference between the two time types is that the latter will not be modified because the system time is modified. For more information, see man page. Then determine the effect of environment variables on the drive. This is mentioned in manual, which affects the default Io reuse mechanism. Next is the assignment of a series of initial values, so you don't need to understand its function at first. You can see it later in the analysis process. Next, initialize the system based on the IO multiplexing mechanism supported by the system. Here you can go to "ev_epoll.c" and "ev_select.c" to check it out. Finally, it is determined that if the system requires a signal event, it will be implemented through a pipe I/O event. We don't need to worry about it now. After understanding the implementation of Io events, naturally, he knows what operations he has done here.

For "ev_epoll.c" and "ev_select.c ",xxx_initIn essence, it is consistent, just like plug-ins, following a format, and then flexible expansion. For epoll, an epoll_create * operation is performed (epoll_create1 supports epoll_cloexec ).

backend_mintime = 1e-3; /* epoll does sometimes return early, this is just to avoid the worst */backend_modify  = epoll_modify;backend_poll    = epoll_poll;

This can be regarded as a plug-in template. backend_modify will be called later when it is modified, and backend_poll will be called during poll to unify the operations.

epoll_eventmax = 64; /* initial number of events receivable per poll */epoll_events = (struct epoll_event *)ev_malloc (sizeof (struct epoll_event) * epoll_eventmax)

This is what is unique to each mechanism. If you are familiar with epoll, you don't need to mention it.

For select (on Linux)

backend_mintime = 1e-6;backend_modify  = select_modify;backend_poll    = select_poll;

Like above, this is equivalent to the plug-in Interface

vec_ri  = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_ri);vec_ro  = ev_malloc (sizeof (fd_set));vec_wi  = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_wi);vec_wo  = ev_malloc (sizeof (fd_set));

Similarly, this is exclusive to select, indicating the fd_set vector for reading and writing. Ri is used to hold the part that meets the conditions after the select return. Other ports such as poll, kqueue, and Solaris are similar. You can read them by yourself.

Ev_a _ and ev_p are defined as follows:

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                               /* a loop as sole argument to a function call */# define EV_A_ EV_A,                              /* a loop as first of multiple arguments */# define EV_DEFAULT_UC  ev_default_loop_uc_ ()    /* the default loop, if initialised, as sole arg */# define EV_DEFAULT_UC_ EV_DEFAULT_UC,            /* the default loop as first of multiple arguments */# define EV_DEFAULT  ev_default_loop (0)          /* the default loop as sole arg */# define EV_DEFAULT_ EV_DEFAULT,                  /* the default loop as first of multiple arguments */

 

In this way, ev_p can be passed in as a function parameter, for example, unsigned int ev_backend (ev_p) ev_throw, while ev_a can be passed in as a function call, ev_backend (ev_a ). This is also the author's skill. All in all, it is a global variable struct ev_loop * loop of the Operation and its parameters are assigned or initialized.

Resolution of libev default event loop Initialization

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.