[Libevent] Libevent study notes (three): event loop

00. Table of Contents

01. event_base_loop function

Once you have an event_base that has registered certain events (see note 4 for how to create and register events), you need to make libevent wait for the event and notify the occurrence of the event.

event_base_loop function

/**
  Wait for events to become active, and run their callbacks.

  This is a more flexible version of event_base_dispatch().

  By default, this loop will run the event base until either there are no more
  pending or active events, or until something calls event_base_loopbreak() or
  event_base_loopexit().  You can override this behavior with the 'flags'
  argument.

  @param eb the event_base structure returned by event_base_new() or
     event_base_new_with_config()
  @param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK
  @return 0 if successful, -1 if an error occurred, or 1 if we exited because
     no events were pending or active.
  @see event_base_loopexit(), event_base_dispatch(), EVLOOP_ONCE,
     EVLOOP_NONBLOCK
  */
int event_base_loop(struct event_base *base, int flag);  //while(1) { .... }
功能:
	等待事件被触发, 然后执行对应的回调函数
参数:
	base: event_base_new的返回值
	flag: 标志
返回值:
	成功: 0成功  1表示没有事件触发
	失败: -1

Cycle related signs:

/** @name Loop flags

    These flags control the behavior of event_base_loop().
 */
/**@{*/
/** Block until we have an active event, then exit once all active events
 * have had their callbacks run. */
#define EVLOOP_ONCE 0x01
/** Do not block: see which events are ready now, run the callbacks
 * of the highest-priority ones, then exit. */
#define EVLOOP_NONBLOCK 0x02
/**@}*/

By default, the event_base_loop() function runs event_base until there are no registered events. When the loop is executed, the function repeatedly checks whether any registered events are triggered (for example, the file descriptor of the read event is ready and can be read; or the timeout period of the timeout event is about to arrive). If an event is triggered, the function marks the triggered event as "active" and executes these events.

Setting one or more flags in the flags parameter can change the behavior of event_base_loop(). If EVLOOP_ONCE is set, the loop will wait for certain events to become active, execute the active event until there are no more events to execute, and then return. If EVLOOP_NONBLOCK is set, the loop will not wait for the event to be triggered: the loop will only detect whether an event is ready, and it can be triggered immediately, if so, the event callback will be executed.

After finishing the work, if it exits normally, event_base_loop() returns 0; if it exits because of some unhandled error in the backend, it returns -1.

To help everyone understand, here is a summary of the algorithm of event_base_loop ():

while (any events are registered with the loop) {
    
    
 
    if (EVLOOP_NONBLOCK was set, or any events are already active)
        If any registered events have triggered, mark them active.
    else
        Wait until at least one event has triggered, and mark it active.
 
    for (p = 0; p < n_priorities; ++p {
    
    
       if (any event with priority of p is active) {
    
    
          Run all active events with priority of p.
          break; /* Do not run any events of a less important priority */
       }
    }
 
    if (EVLOOP_ONCE was set or EVLOOP_NONBLOCK was set)
       break;
}

02. event_base_dispatch function

event_base_dispatch() is equivalent to event_base_loop() with no flag set. Therefore, event_base_dispatch() will run until there are no registered events, or event_base_loopbreak() or event_base_loopexit() is called.

/**
   Event dispatching loop

  This loop will run the event base until either there are no more pending or
  active, or until something calls event_base_loopbreak() or
  event_base_loopexit().

  @param base the event_base structure returned by event_base_new() or
     event_base_new_with_config()
  @return 0 if successful, -1 if an error occurred, or 1 if we exited because
     no events were pending or active.
  @see event_base_loop()
 */
int event_base_dispatch(struct event_base *base);
等价于没有设置标志的 event_base_loop函数

event_base_dispatch () will run until there are no registered events, or event_base_loopbreak () or event_base_loopexit () is called .

These functions are defined in *<event2/event.h> and have existed since libevent 1.0*.

03. event_base_loopexit function

/**
  Exit the event loop after the specified time

  The next event_base_loop() iteration after the given timer expires will
  complete normally (handling all queued events) then exit without
  blocking for events again.

  Subsequent invocations of event_base_loop() will proceed normally.

  @param eb the event_base structure returned by event_init()
  @param tv the amount of time after which the loop should terminate,
    or NULL to exit after running all currently active events.
  @return 0 if successful, or -1 if an error occurred
  @see event_base_loopbreak()
 */
int event_base_loopexit(struct event_base *base, const struct timeval *tv);
功能:
	让event_base在给定时间之后停止循环。
参数:
	base event_base_new的返回值
	tv 表示延时的时间,如果为NULL 立即停止循环,没有延时
		
返回值:
	成功: 0成功  
	失败: -1

note:

If event_base is currently executing any activation event callbacks, the callbacks will continue to run and will not exit until all activation event callbacks have been run.

04. event_base_loopbreak function

/**
  Abort the active event_base_loop() immediately.

  event_base_loop() will abort the loop after the next event is completed;
  event_base_loopbreak() is typically invoked from this event's callback.
  This behavior is analogous to the "break;" statement.

  Subsequent invocations of event_loop() will proceed normally.

  @param eb the event_base structure returned by event_init()
  @return 0 if successful, or -1 if an error occurred
  @see event_base_loopexit()
 */
int event_base_loopbreak(struct event_base *base);
功能:
	让event_base立即停止循环。
参数:
	base event_base_new的返回值		
返回值:
	成功: 0成功  
	失败: -1

These functions are declared in *<event2/event.h>*. The event_break_loopexit() function was implemented in libevent version 1.0c for the first time ; event_break_loopbreak() was implemented in libevent version 1.4.3 for the first time .

note:

event_base_loopbreak () makes event_base exit the loop immediately. It is different from event_base_loopexit ( base, NULL ) in that if event_base is currently executing the callback of the activation event, it will exit immediately after executing the event currently being processed.

The behavior of event_base_loopexit(base, NULL) and event_base_loopbreak(base) is different when the event loop is not running: the former arranges the next event loop to stop immediately after the next round of callback is completed (just like calling with EVLOOP_ONCE flag); the latter just stops The currently running loop has no effect if the event loop is not running.

Official reference example 1: Exit the loop immediately

#include <event2/event.h>
 
/* Here's a callback function that calls loopbreak */
void cb(int sock, short what, void *arg)
{
    
    
    struct event_base *base = arg;
    event_base_loopbreak(base);
}
 
void main_loop(struct event_base *base, evutil_socket_t watchdog_fd)
{
    
    
    struct event *watchdog_event;
 
    /* Construct a new event to trigger whenever there are any bytes to
       read from a watchdog socket.  When that happens, we'll call the
       cb function, which will make the loop exit immediately without
       running any other active events at all.
     */
    watchdog_event = event_new(base, watchdog_fd, EV_READ, cb, base);
 
    event_add(watchdog_event, NULL);
 
    event_base_dispatch(base);
}

Official Reference Example 2: Execute the event loop for 10 seconds, and then exit

#include <event2/event.h>
 
void run_base_with_ticks(struct event_base *base)
{
    
    
  struct timeval ten_sec;
 
  ten_sec.tv_sec = 10;
  ten_sec.tv_usec = 0;
 
  /* Now we run the event_base for a series of 10-second intervals, printing
     "Tick" after each.  For a much better way to implement a 10-second
     timer, see the section below about persistent timer events. */
  while (1) {
    
    
     /* This schedules an exit ten seconds from now. */
     event_base_loopexit(base, &ten_sec);
 
     event_base_dispatch(base);
     puts("Tick");
  }
}

Test code: output a string every 3 seconds

#include <stdio.h>
#include <event.h>

int main(void)
{
    
    
    struct event_base *base = NULL;
    struct timeval tmo = {
    
    3, 0}; 

    base = event_base_new();
    if (NULL == base)
    {
    
       
        printf("event_base_new failded...\n");
        return 1;
    }

    while(1)
    {
    
       
        //设置三秒钟退出事件循环
        event_base_loopexit(base, &tmo); 
        //进入事件循环
        event_base_dispatch(base);
        printf("hello itcast\n");
    }
    event_base_free(base);

    return 0;
}

05. event_base_got_exit function

Sometimes you need to know whether the call to event_base_dispatch() or event_base_loop() exited normally, or whether it exited because of calling event_base_loopexit() or event_base_break(). The following functions can be called to determine whether the loopexit or break function is called.

/**
  Checks if the event loop was told to exit by event_loopexit().

  This function will return true for an event_base at every point after
  event_loopexit() is called, until the event loop is next entered.

  @param eb the event_base structure returned by event_init()
  @return true if event_base_loopexit() was called on this event base,
    or 0 otherwise
  @see event_base_loopexit()
  @see event_base_got_break()
 */
int event_base_got_exit(struct event_base *base);
功能:
	判断循环是否因为调用event_base_loopexit()或者event_base_break()而退出的时候返回true,否则返回false。下次启动事件循环的时候,这些值会被重设。
参数:
	base event_base_new的返回值		
返回值:
	true 循环是因为调用对应的函数而退出
    0 其它情况

Reference example:

#include <stdio.h>
#include <event.h>

int main(void)
{
    
    
    struct event_base *base = NULL;
    struct timeval tmo = {
    
    3, 0}; 

    base = event_base_new();
    if (NULL == base)
    {
    
       
        printf("event_base_new failded...\n");
        return 1;
    }   

    while(1)
    {
    
       
        event_base_loopexit(base, &tmo);
        event_base_dispatch(base);
        printf("hello itcast\n");
        
        //如果事件循环因为event_base_loopexit而退出 返回true
        if (event_base_got_exit(base))
        {
    
    
            printf("event_base_got_exit return true\n");
        }
    }   
    event_base_free(base);

    return 0;
}

06. event_base_got_break function

Sometimes you need to know whether the call to event_base_dispatch() or event_base_loop() exited normally, or whether it exited because of calling event_base_loopexit() or event_base_break(). The following functions can be called to determine whether the loopexit or break function is called.

/**
  Checks if the event loop was told to abort immediately by event_loopbreak().

  This function will return true for an event_base at every point after
  event_loopbreak() is called, until the event loop is next entered.

  @param eb the event_base structure returned by event_init()
  @return true if event_base_loopbreak() was called on this event base,
    or 0 otherwise
  @see event_base_loopbreak()
  @see event_base_got_exit()
 */
int event_base_got_break(struct event_base *base);
功能:
	判断循环是否因为调用event_base_loopexit()或者event_base_break()而退出的时候返回true,否则返回false。下次启动事件循环的时候,这些值会被重设。
参数:
	base event_base_new的返回值		
返回值:
	true 循环是因为调用对应的函数而退出
    0 其它情况

07. event_base_dump_events function

Sometimes you need to get an approximate view of the current time in the event callback, but you don't want to call gettimeofday() (maybe because the OS implements *gettimeofday()* as a system call, and you try to avoid the overhead of the system call).

In the callback, you can request the current time view when libevent starts this round of callback.

void event_base_dump_events(struct event_base *, FILE *);

/** Sets 'tv' to the current time (as returned by gettimeofday()),
    looking at the cached value in 'base' if possible, and calling
    gettimeofday() or clock_gettime() as appropriate if there is no
    cached time.

    Generally, this value will only be cached while actually
    processing event callbacks, and may be very inaccuate if your
    callbacks take a long time to execute.

    Returns 0 on success, negative on failure.
 */
int event_base_gettimeofday_cached(struct event_base *base,
    struct timeval *tv);
如果event_base当前正在执行回调,event_base_gettimeofday_cached()函数设置tv_out参数的值为缓存的时间。否则,函数调用evutil_gettimeofday()获取真正的当前时间。成功时函数返回0,失败时返回负数。

返回值:
	成功 0
    失败 负数

note:

Note that because the time value of libevent is cached when it starts executing the callback, this value is at least a little imprecise. If the callback is executed for a long time, this value will be very inaccurate.

This function is newly introduced in libevent 2.0.4-alpha .

08. event_base_dump_events function

To help debug programs (or libevent), sometimes you may need a complete list of all events and their states that have been added to event_base. Call event_base_dump_events() to output this list to the specified file.

This list is human readable, and future versions of libevent will change its format.

void event_base_dump_events(struct event_base *base, FILE *file);
功能:
	转储event_base的状态到文件中。
参数:
	base event_base_new的返回值
	file FILE类型指针
		
返回值:

This function was introduced in libevent 2.0.1-alpha version.

09. Obsolete event loop function

As discussed earlier, older versions of libevent have the concept of "current" event_base .

Some of the event loop functions discussed in this article have variants that manipulate the current event_base . Except that there is no base parameter, these functions behave the same as the current new version functions.

Insert picture description here

Event_base before version 2.0 does not support locks, so these functions are not completely thread-safe: calling *_loopbreak() or _loopexit()* functions in threads other than the thread executing the event loop is not allowed .

10. Reference

Related books: http://www.wangafu.net/~nickm/libevent-book/Ref2_eventbase.html

Official reference website: https://www.monkey.org/~provos/libevent/doxygen-2.0.1/index.html

Guess you like

Origin blog.csdn.net/dengjin20104042056/article/details/90799225