• memcached 基于libevent的事件处理


    1. libevent
    在 memcached 中 libevent 被用来处理网络事件(连接请求,读和写) 或者被用来实现定时器。 使用 libevent 需要包含头文件 event.h, 并且在 GCC 链接时需要使用选项 -levent

    相关函数的函数原型:

    /* before using any of the functions in the library, 
     * you must call event_init() or event_base_new() to 
     * perform one-time initialization of the libevent library. 
     */
    struct event_base* event_init();

    在所有其他库函数调用之前需要调用 event_init() 来初始化一个 event_base 结构。

    // Associate a event with a callback (event handler)
    void event_set(struct event *event, evutil_socket_t fd, short what /* the event flags */,
            void(*callback)(evutil_socket_t, short, void *), void *arg);
    /*
        The event flags used in memcached 
    
     *    EV_TIMEOUT (0)
            This flag indicates an event that becomes active after a timeout elapses.
    
            The EV_TIMEOUT flag is ignored when constructing an event: you
            can either set a timeout when you add the event, or not.  It is
            set in the 'what' argument to the callback function when a timeout
            has occurred.
    
     *    EV_READ
            This flag indicates an event that becomes active when the provided file descriptor is ready for reading.
    
     *    EV_WRITE
            This flag indicates an event that becomes active when the provided file descriptor is ready for writing.
    
     *    EV_PERSIST
            Indicates that the event is persistent. See "About Event Persistence" below.
     */

     调用 event_set() 来初始化一个 event 结构,并为其设置一个回调函数.

    // Associate a different event base with an event. 
    // The event to be associated must not be currently active or pending.
    // The return value is 0 on success, -1 on failure.
    int event_base_set(struct event_base *eb, struct event *ev) 

    调用 event_base_set() 将一个事件 与 一个 event_base 关联。

    /**
     *  Add an event to the set of pending events
     *  @param ev      : an event struct initialized via event_set()
     *  @param timeout : the maximum amount of time to wait for the event, or NULL to wait forever.
     *  @return         : 0 on success, -1 on failure.
     */
    int event_add(struct event *ev, struct timeval *timeout);

    将事件添加到监听事件集中

    /**
     *  Delete a event.
     *  @param ev : the event struct to be disabled
     *  @return   : 0 on success, -1 on failure.
     */
    int event_del(struct event *ev);

    将事件从监听事件集中移除

    /*  Loop to process events. In order to process events, 
     *  an application needs to call event_dispatch(). 
     *  event_base_dispatch() is threadsafe event dispatching loop.
     *  event_base_loop() is a more flexible version of event_base_dispatch(). 
     */
    
    /**
     * @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 on success, -1 on failure, or 1 if we exited because no events were pending or active
     */
    int event_base_loop(struct event_base* eb, int flags);
    /* 
        flags for event_base_loop :
    
     *    0
            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()
    
     *    EVLOOP_ONCE(1)
            Block until we have an active event, then exit once all active events have had their callbacks run. 
    
     *    EVLOOP_NONBLOCK(2)
             Do not block: see which events are ready now, run the callbacks of the highest-priority ones, then exit. 
     */

    事件处理循环

    // functions for libevent timers
    #define evtimer_set(ev, cb, arg)    event_set((ev), -1, 0, (cb), (arg))
    #define evtimer_add(ev, tv)        event_add((ev), (tv))
    #define evtimer_del(ev)            event_del(ev)

    References :
    [1] http://www.wangafu.net/~nickm/libevent-2.0/doxygen/html/event_8h.html#_details
    [2] http://www.wangafu.net/~nickm/libevent-book/

    2. libevent timer

    libevent can also be used to create timers that invoke a callback after a certain amount of time has expired.
    The evtimer_set() function prepares an event struct to be used as a timer. To activate the timer, call evtimer_add().
    Timers can be deactivated by calling evtimer_del(). (From http://www.monkey.org/~provos/libevent/doxygen-2.0.1/)

    大意是: libevent也能被用来创建定时器,当时间到期时,能够调用一个回调函数。调用 evtimer_set() 函数初始化 timer,调用 evtimer_add() 函数激活 timer,
    调用 evtimer_del() 函数删除 timer。这三个函数的定义见第1小节。

    下面源代码是从 memcached.c 中抽取出来的利用 libevent timer 来更新进程运行时间的代码。

    #include <event.h>        // libevent header
    #include <sys/time.h>        // for gettimeofday 
    #include <stdbool.h>        // for bool
    #include <stdlib.h>        // for time(), EXIT_SUCCESS and EXIT_FAILURE
    
    /** the code below is from memcached source **/
    
    typedef unsigned int rel_time_t; /** in memcached.h **/
    
    // ...
    time_t process_started;     /* when the process was started */
    // ...
    static struct event_base * main_base;
    // ...
    
    /*
     * We keep the current time of day in a global variable that's updated by a
     * timer event. This saves us a bunch of time() system calls (we really only
     * need to get the time once a second, whereas there can be tens of thousands
     * of requests a second) and allows us to use server-start-relative timestamps
     * rather than absolute UNIX timestamps, a space savings on systems where
     * sizeof(time_t) > sizeof(unsigned int).
     */
    volatile rel_time_t current_time; 
    static struct event clockevent;
    
    static void clock_handler(const int fd, const short which, void *arg) {
        struct timeval t = {.tv_sec = 1, .tv_usec = 0};
        static bool initialized = false;
    
        if (initialized) {
            /* only delete the event if it's actually there. */
            evtimer_del(&clockevent);
        } else {
            initialized = true;
        }
    
        evtimer_set(&clockevent, clock_handler, 0);
        event_base_set(main_base, &clockevent);
        evtimer_add(&clockevent, &t);
    
        struct timeval tv;
        gettimeofday(&tv, NULL);
        current_time = (rel_time_t) (tv.tv_sec - process_started);
    }
    
    // ...
    
    int main(int argc, char* argv[]) {
        // ...
        int retval = EXIT_SUCCESS;
        // ...
    
        main_base = event_init();
    
        #define ITEM_UPDATE_INTERVAL 60 /** originally in memcached.h **/
        process_started = time(0) - ITEM_UPDATE_INTERVAL - 2;  /** originally in stats_init() **/
    
        // ...
        clock_handler(0, 0, 0);
        // ...
    
        /* enter the event loop */
        if (event_base_loop(main_base, 0) != 0) {
            retval = EXIT_FAILURE;
        }
        
        // ...
        return retval;
    }

    memcached 实现中还利用 libevent timer 处理网络连接,具体在memcached网络通信(TODO: add a link here)中会有描述。

  • 相关阅读:
    攻城狮在路上(肆)How tomcat works(一) 简单的web服务器
    攻城狮在路上(肆)How tomcat works(零) 前言说明
    font-face使用备忘
    subversion安装使用
    判断一个类到底是从哪个jar包中调用的工具类
    JavaScript实例
    Nginx(一)
    PHP面向对象(七)
    PHP面向对象(六)
    PHP面向对象(五)
  • 原文地址:https://www.cnblogs.com/william-cheung/p/4801549.html
Copyright © 2020-2023  润新知