How to implement libevent timer

Keywords: C Linux network

1. How does the timer work?

In previous articles, we have said that the final processing of libevent is called the corresponding dispatch function in event_base_loop, and the timer is also processed in the dispatch function.

Or take epoll as an example. The epoll_dispatch function has the following code:

    if (tv != NULL) {
        timeout = evutil_tv_to_msec_(tv);
        if (timeout < 0 || timeout > MAX_EPOLL_TIMEOUT_MSEC) {
            /* Linux kernels can wait forever if the timeout is
             * too big; see comment on MAX_EPOLL_TIMEOUT_MSEC. */
            timeout = MAX_EPOLL_TIMEOUT_MSEC;
        }
    }

    epoll_apply_changes(base);
    event_changelist_remove_all_(&base->changelist, base);

    EVBASE_RELEASE_LOCK(base, th_base_lock);

    //The last parameter of epoll_wait is the timeout time.
    res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout);

    EVBASE_ACQUIRE_LOCK(base, th_base_lock);

    if (res == -1) {
        if (errno != EINTR) {
            event_warn("epoll_wait");
            return (-1);
        }

        return (0);
    }

From the above code, we can see that the timer is realized by the timeout mechanism of epoll_wait, so we can know that the timer is realized by utilizing the timeout mechanism of system functions such as select and epoll_wait.

In general, the timer is waiting for the network call timeout in the main loop of the event. After the timeout, the task is written to the queue, then the queue is processed, and the callback function is invoked, thus realizing the timer.

2. Timer Code Implementation

See the example in the libevent source code:

#include <sys/types.h>
#include <event2/event-config.h>
#include <sys/stat.h>
#include <time.h>
#ifdef EVENT__HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#include <event2/event.h>
#include <event2/event_struct.h>
#include <event2/util.h>

struct timeval lasttime;

int event_is_persistent;

static void
timeout_cb(evutil_socket_t fd, short event, void *arg)
{
    struct timeval newtime, difference;
    struct event *timeout = (struct event*)arg;
    double elapsed;

    evutil_gettimeofday(&newtime, NULL);
    evutil_timersub(&newtime, &lasttime, &difference);
    elapsed = difference.tv_sec +
        (difference.tv_usec / 1.0e6);

    printf("timeout_cb called at %d: %.3f seconds elapsed.\n",
        (int)newtime.tv_sec, elapsed);
    lasttime = newtime;

    if (! event_is_persistent) {
        struct timeval tv;
        evutil_timerclear(&tv);
        tv.tv_sec = 2;
        event_add(timeout, &tv);
    }
}

int
main(int argc, char **argv)
{
    struct event timeout;
    struct timeval tv;
    struct event_base *base;
    int flags;

    if (argc == 2 && !strcmp(argv[1], "-p")) {
        event_is_persistent = 1;
        flags = EV_PERSIST;
    } else {
        event_is_persistent = 0;
        flags = 0;
    }

    /* Initalize the event library */
    base = event_base_new();

    /* Initalize one event */
    event_assign(&timeout, base, -1, flags, timeout_cb, (void*) &timeout);

    evutil_timerclear(&tv);
    tv.tv_sec = 3;
    event_add(&timeout, &tv);

    evutil_gettimeofday(&lasttime, NULL);

    event_base_dispatch(base);

    return (0);
}

The callback function is called once in three seconds, and the results are as follows:

timeout_cb called at 1535528104: 3.001 seconds elapsed.
timeout_cb called at 1535528107: 3.000 seconds elapsed.
timeout_cb called at 1535528110: 3.001 seconds elapsed.
timeout_cb called at 1535528113: 2.999 seconds elapsed.
timeout_cb called at 1535528116: 3.000 seconds elapsed.
timeout_cb called at 1535528119: 3.002 seconds elapsed.
timeout_cb called at 1535528122: 2.999 seconds elapsed.
timeout_cb called at 1535528125: 3.001 seconds elapsed.
timeout_cb called at 1535528128: 3.000 seconds elapsed.
timeout_cb called at 1535528131: 3.000 seconds elapsed.
timeout_cb called at 1535528134: 2.999 seconds elapsed.
timeout_cb called at 1535528137: 3.000 seconds elapsed.
timeout_cb called at 1535528140: 3.000 seconds elapsed.
timeout_cb called at 1535528143: 3.000 seconds elapsed.
timeout_cb called at 1535528146: 3.000 seconds elapsed.
timeout_cb called at 1535528149: 3.002 seconds elapsed.

The article is published in cpp gas station (ID:xy13640954449) at the same time. Welcome to our attention!

Posted by moonshaden on Wed, 02 Oct 2019 14:43:10 -0700