Libevent源码剖析(二)之数据结构

描述Libevent中出现的数据结构:

struct event_base :

事件处理集合

struct event_base {
    const struct eventop *evsel;        //对struct event对象的操作函数,以指针函数的方式提供
    void *evbase;        //指向特定数据的指针
    struct event_changelist changelist;        //记录事件变化的列表,仅由O(1)方式使用

    const struct eventop *evsigsel;        //对struct event signal对象的处理,以指针函数的方式进行注册
    struct evsig_info sig;        //实现通用信号处理程序的代码

    int virtual_event_count;        //虚拟事件数量
    int virtual_event_count_max;        //最大的活动虚拟事件数量
    int event_count;        //添加到struct event_base中的事件总数
    int event_count_max;        //允许添加到struct event_base中的最大的事件数量
    int event_count_active;        //目前活动的事件总数
    int event_count_active_max;        //允许的活动事件总数

    int event_gotterm;        //标志:是否需要在事件处理结束后终止事件循环
    int event_break;           //标志:是否应该立即终止循环
    int event_continue;       //标志:是否应该立即启动一个新的事件循环
    int event_running_priority;        //当前正在运行的事件的优先级
    int running_loop;        //标志:是否运行event_base_loop函数,以防止可重入调用
    int n_deferreds_queued;        //标志:防止饥饿的手段

        #define TAILQ_HEAD(name, type)          \
        struct name {                   \
            struct type *tqh_first;         \
            struct type **tqh_last;         \
        }
        //活动事件管理
    struct evcallback_list *activequeues;        //活动事件队列,so,evcallback_list很可能是使用了这种方式进行注册的
    int nactivequeues;        //活动事件队列的长度
    struct evcallback_list active_later_queue;        //下一次应该激活的事件队列

        //超时处理
    struct common_timeout_list **common_timeout_queues;        //常用的超时队列
    int n_common_timeouts;        //超时队列中的条目数
    int n_common_timeouts_allocated;        //超时队列占用的总大小

        //管理IO事件与信号事件,我就纳闷了,用红黑树管理不好吗?
    struct event_io_map io;        //从IO映射中添加的事件  
    struct event_signal_map sigmap;        //从信号映射中添加的事件
    
        struct min_heap timeheap;        //使用最小堆将超时事件组织起来
    struct timeval tv_cache;        //缓存系统时间,避免频繁的系统调用(gettimeofday,虽然说这个函数不陷入系统调用)
    struct evutil_monotonic_timer monotonic_timer;        //一个空的结构体,用途不明
    struct timeval tv_clock_diff;        //时钟差异(10ms?20ms?)
    time_t last_updated_clock_diff;        //最后一次更新事件的记录

    //多线程管理
    unsigned long th_owner_id;        //当前运行loop的thread id
    void *th_base_lock;        //线程锁,防止对event_base的访问冲突
    void *current_event_cond;        //条件变量,用于同步事件处理
    int current_event_waiters;        //阻塞在当前条件变量上的等待线程
    struct event_callback *current_event;        //正在执行的回调事件

    enum event_base_config_flag flags;        //这个event_base的配置标志

    struct timeval max_dispatch_time;        //一次事件循环的最大时间
    int max_dispatch_callbacks;        //一次事件循环中可以处理的最大 的回调函数
    int limit_callbacks_after_prio;        //回调函数中的优先级限制
        
        //通知主线程唤醒休息的线程
    int is_notify_pending;        //标志:struct event_base是否有等待处理的通知
    evutil_socket_t th_notify_fd[2];        //与主线程使用管道来进行交互,一般而言,会将主线程阻塞在read fd上
    struct event th_notify;        //使用事件处理的机制通知主线程,真的是:万物皆事件哇
    int (*th_notify_fn)(struct event_base *base);        //用于从子线程中唤醒主线程的回调函数

    struct evutil_weakrand_state weakrand_seed;        //随机数种子
    LIST_HEAD(once_event_list, event_once) once_events;        //保存目前尚未触发的通过event_once注册的事件
};

struct event

表示一个具体的事件对象,将IO,超时,信号三者统一起来

struct event {
    struct event_callback ev_evcallback;        //保存事件处理的回调函数,由必要的时候对这个事件进行填充,添加到合适的优先级队列

        //管理超时
    union {
        TAILQ_ENTRY(event) ev_next_with_common_timeout;        //我觉着这个有点复杂...直接标记在最小堆中的位置,岂不方便??
        int min_heap_idx;
    } ev_timeout_pos;
    evutil_socket_t ev_fd;        //关注的socket fd(int)
    struct event_base *ev_base;        //依赖的struct event_base对象

    union {
        struct {
            LIST_ENTRY (event) ev_io_next;        //在IO事件队列中的位置
            struct timeval ev_timeout;
        } ev_io;        //用于管理IO事件

        struct {
            LIST_ENTRY (event) ev_signal_next;        //在信号事件队列中的位置
            short ev_ncalls;        
            short *ev_pncalls;        //允许在回调中删除
        } ev_signal;        //用于管理超时事件
    } ev_;

    short ev_events;        //关注的事件
    short ev_res;          //实际发生的事件 
    struct timeval ev_timeout;            //超时时间
};

struct eventop

struct event_base的操作

struct eventop {
    const char *name;        //这个后端的名称
    void *(*init)(struct event_base *);        //初始化struct event_base对象
    int (*add)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo);        //将struct event对象添加到struct event_base对象中
    int (*del)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo);        //将struct event对象从struct event_base中移除
    int (*dispatch)(struct event_base *, struct timeval *);        //将控制权提交给事件控制函数
    void (*dealloc)(struct event_base *);        //清理struct event_base中的对象
    int need_reinit;        //标志:是否需要在调用fork()函数后重新初始化事件库
    enum event_method_feature features;        //提供可以支持struct event_method_feature位数组的
    size_t fdinfo_len;        //为每一个fd维护的信息的长度
};

struct event_changelist

事件变化的列表,仅由O(1)方法使用

struct event_changelist {
    struct event_change *changes;        //链表
    int n_changes;        
    int changes_size;
};

struct event_change

struct event_change {
    evutil_socket_t fd;        //Libevent对socketfd,signal,timer的封装,(int)
    short old_events;        //fd之前上启用的事件

    ev_uint8_t read_change;    //此次改变发生的读事件
    ev_uint8_t write_change;    //此次改变发生的写事件
    ev_uint8_t close_change;    //此次改变发生的关闭事件
};

struct event_method_feature

enum event_method_feature {
    EV_FEATURE_ET = 0x01,
    EV_FEATURE_O1 = 0x02,
    EV_FEATURE_FDS = 0x04,
    EV_FEATURE_EARLY_CLOSE = 0x08
};

struct evsig_info

为信号处理函数提供事件

struct evsig_info {
    struct event ev_signal;        //为信号事件注册的一个struct event对象
    evutil_socket_t ev_signal_pair[2];        //使用进程间管道的方式处理信号事件
    int ev_signal_added;        //判断信号事件是否已经被添加
    int ev_n_signals_added;        //我们目前正在关注的信号数量
    struct sigaction **sh_old;        //保存一系列信号处理对象
    int sh_old_max;        //保存的信号处理对象的个数
}

struct common_timeout_list

处理超时事件

struct common_timeout_list {
    struct event_list events;        //当前队列中正在等待的事件列表
    struct timeval duration;        //表示事件的持续时间
    struct event timeout_event;        //每个队列都为超时时间准备了一个struct event对象
    struct event_base *base;        //这个struct event对象占用的
};

struct event_io_map

#define event_io_map event_signal_map
struct event_signal_map {
    void **entries;        //一个二维数据,数组中会维护一些信息
    int nentries;        //数组中的条目总数
};

struct event_callback

回调函数的封装

#ifndef TAILQ_ENTRY
#define EVENT_DEFINED_TQENTRY_
#define TAILQ_ENTRY(type)                       \
struct {                                \
    struct type *tqe_next;  /* next element */          \
    struct type **tqe_prev; /* address of previous next element */  \
}
#endif 

struct event_callback {
    TAILQ_ENTRY(event_callback) evcb_active_next;        //回调事件队列中的一个成员
    short evcb_flags;    //根据flag选择合适的回调函数进行处理
    ev_uint8_t evcb_pri;    //标志这个事件的优先级
    ev_uint8_t evcb_closure;        
        union {
        void (*evcb_callback)(evutil_socket_t, short, void *);
        void (*evcb_selfcb)(struct event_callback *, void *);
        void (*evcb_evfinalize)(struct event *, void *);
        void (*evcb_cbfinalize)(struct event_callback *, void *);
    } evcb_cb_union;        //具体的回调函数
    void *evcb_arg;        //回调函数使用的参数
};

struct event_config

为struct event_base提供配置对象

#define TAILQ_HEAD(name, type)          \
struct name {                   \
    struct type *tqh_first;         \
    struct type **tqh_last;         \
}

struct event_config {
    TAILQ_HEAD(event_configq, event_config_entry) entries;        //双向链表

    int n_cpus_hint;        //cpus数量
    struct timeval max_dispatch_interval;        //最大的循环时间
    int max_dispatch_callbacks;        //最多的callbacks的调用
    int limit_callbacks_after_prio;        //优先级限制
    enum event_method_feature require_features;        //目前struct event_base支持的一些方法
    enum event_base_config_flag flags;
};

全局数据结构:eventops

static const struct eventop *eventops[] = {
#ifdef EVENT__HAVE_EVENT_PORTS
    &evportops,
#endif
#ifdef EVENT__HAVE_WORKING_KQUEUE
    &kqops,
#endif
#ifdef EVENT__HAVE_EPOLL
    &epollops,
#endif
#ifdef EVENT__HAVE_DEVPOLL
    &devpollops,
#endif
#ifdef EVENT__HAVE_POLL
    &pollops,
#endif
#ifdef EVENT__HAVE_SELECT
    &selectops,
#endif
#ifdef _WIN32
    &win32ops,
#endif
    NULL
};

猜你喜欢

转载自www.cnblogs.com/ukernel/p/9191077.html