Libevent 源码学习笔记(1)event 与 event_base

目录

event

event_base

eventop

evcb_closure 

event_callback

event_changelist 

evsig_info

event_io_map 

event_iocp_port


event

struct event {
    // 事件回调  下文有注解
	struct event_callback ev_evcallback; 

	//超时管理
	union {
		TAILQ_ENTRY(event) ev_next_with_common_timeout;   // 事件队列
		int min_heap_idx;                 // 事件在最小堆中的index
	} ev_timeout_pos;
	evutil_socket_t ev_fd;                // socket 描述符

    // 下文有注解 
	struct event_base *ev_base;

	union {
		// 使用独写事件
		struct {
			LIST_ENTRY (event) ev_io_next; // 事件链表 ,链接下一个事件
			struct timeval ev_timeout;     // 事件超时时间
		} ev_io;

		// 使用信号事件
		struct {
			LIST_ENTRY (event) ev_signal_next; // 事件链表 ,链接下一个事件
			short ev_ncalls;                   // 回调数量
			short *ev_pncalls;                 // 允许在回调中删除  
		} ev_signal;
	} ev_;
    // ev_events : 
    // EV_TIMEOUT	0x01  超时
    // EV_READ		0x02  读
    // EV_WRITE	    0x04  写
    // EV_SIGNAL	0x08  信号
    // EV_PERSIST	0x10  持久事件 激活时不会自动删除,超时激活 超时重置为0
    // EV_ET		0x20  边缘触发
    // EV_FINALIZE  0x40  终止事件 event_del不会阻塞 ,需要使用 event_finalize 或
    // event_free_finalize 来保证线程安全
    // EV_CLOSED	0x80  连接关闭
	short ev_events;   
	short ev_res;	// 结果传递给事件回调
	struct timeval ev_timeout;                 // 事件超时时间
};

event_base

struct event_base {
    // 函数指针和其他数据来描述event_base的后端,也就是所谓的epoll iocp kqueue等
    // 下文有注解样例
	const struct eventop *evsel;
    // 指向后端特定数据指针,上面 evsel Init初始化后返回值赋值给 evbase
	void *evbase;
    // 事件变化列表 ,有变化的事件会进行下一次分发 下文有注解
	struct event_changelist changelist;
	// 用函数指针来描述event_base的后端,用于信号
	const struct eventop *evsigsel;
    // 处理通用信号数据 下文有注解
	struct evsig_info sig;
    // 虚拟事件数量
	int virtual_event_count;
    // 最大活跃虚拟事件数量
	int virtual_event_count_max;
	// 添加到此event_base的事件的数量
	int event_count;
	// 添加到此event_base的事件的最大数量
	int event_count_max;
	// 事件活跃数量
	int event_count_active;
    // 事件最大活跃数量
	int event_count_active_max;
    // 设置是否在完成事件处理后终止循环
	int event_gotterm;
	// 设置是否应该立即终止循环
	int event_break;
	// 设置是否立即开始一个新的循环实例
	int event_continue;
    // 当前正在运行事件的优先级
	int event_running_priority;
    // 设置我们是否正在运行 event_base_loop 函数,以防止可重入调用
	int running_loop;
    // 设置在循环,防饥饿标志
	int n_deferreds_queued;

    //此处用双向队列管理激活的事件
    // TAILQ_HEAD(evcallback_list, event_callback);

    //  #define TAILQ_HEAD(name, type)						\
    // struct name {								\
	//     struct type *tqh_first;	/* first element */			\
	//     struct type **tqh_last;	/* addr of last next element */		\
    // }
	struct evcallback_list *activequeues;
	// activequeues 链表长度
	int nactivequeues;
    // 下次激活时候处理 的 evcallback_list  
	struct evcallback_list active_later_queue;
    // 公共超时链表
	struct common_timeout_list **common_timeout_queues;
	// common_timeout_queues 队列中的数量
	int n_common_timeouts;
	// common_timeout_queues 的size
	int n_common_timeouts_allocated;
    // 事件读写Map看下文有注解 
	struct event_io_map io;
    // 信号到事件的映射
	struct event_signal_map sigmap;
    // 超时事件的优先队列
	struct min_heap timeheap;
    // 存储时间值,用于避免调用 gettimeofday/clock_gettime
	struct timeval tv_cache;
    // 系统启动以后流逝的时间
	struct evutil_monotonic_timer monotonic_timer;

	/** Difference between internal time (maybe from clock_gettime) and
	 * gettimeofday. */
	struct timeval tv_clock_diff; // 时钟差异
    // 上次更新tv_clock_diff的第二个时间
	time_t last_updated_clock_diff;

#ifndef EVENT__DISABLE_THREAD_SUPPORT  // 多线程管理
    // 当前loop的线程ID
	unsigned long th_owner_id;
	// event_base 的锁,针对多线程,处理同步
	void *th_base_lock;
	// 条件变量,处理同步
	void *current_event_cond;
	阻塞在 current_event_cond 上的线程数量
	int current_event_waiters;
#endif
	// 正在执行回调的事件 下文有详细注解
	struct event_callback *current_event;

#ifdef _WIN32
	// IOCP 支持结构 下文有详细注解
	struct event_iocp_port *iocp;
#endif
	// 配置标志
    /*
    enum event_base_config_flag 
    {
	    // 不给这个event_base分配锁,即使有锁设定,可以省去加锁解锁消耗,但多线程下不安全
	    EVENT_BASE_FLAG_NOLOCK = 0x01,
	    // 不检查 EVENT_* 环境变量
	    EVENT_BASE_FLAG_IGNORE_ENV = 0x02,
        // 仅对windows有效,启用Libevent时 bufferevent_socket_new() 和
        evconn_listener_new() 将使用 IOCP 支持的实现,而不是在需要时才使用
	    EVENT_BASE_FLAG_STARTUP_IOCP = 0x04,
        // 在每个超时回调后检测当前时间,而不是在超时回调前检测
    	EVENT_BASE_FLAG_NO_CACHE_TIME = 0x08,
        // 如果使用EPOLL后端,使用change-list 是安全的,可以让代码运行更快
    	EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10,
        // 使用效率低但更精准的计时器
	    EVENT_BASE_FLAG_PRECISE_TIMER = 0x20
    };
    */
	enum event_base_config_flag flags;
    // 事件循环的最大事件
	struct timeval max_dispatch_time;
	int max_dispatch_callbacks;   // 事件循环中可以处理最大的回调数量
	int limit_callbacks_after_prio;   // 回调函数优先级限制
	int is_notify_pending;   //通知主线程唤醒休息的线程
    // 一个socketpair, 使用 th_notify_fn 函数唤醒主线程
	evutil_socket_t th_notify_fd[2];
	// 事件触发的时候 使用 th_notify_fn 函数唤醒主线程
	struct event th_notify;
	// 子线程唤醒主线程的回调函数
	int (*th_notify_fn)(struct event_base *base);
    // 随机数种子 受 th_base_lock 保护
	struct evutil_weakrand_state weakrand_seed;
    // 尚未触发的通过event_once注册的事件链表
	LIST_HEAD(once_event_list, event_once) once_events;

};

eventop

struct eventop {
	/** 后端的名字. */
	const char *name;
	//初始化一个event_base 来使用这个后端函数,运行得到返回值会赋给event_base.evbase
	void *(*init)(struct event_base *);
	// 激活一个给定的文件描述符或者信号上启动读/写,例 EV_READ,EV_WRITE,EV_SIGNAL, EV_ET
	int (*add)(struct event_base *, evutil_socket_t fd, 
               short old, short events, void *fdinfo);
	// del和add相反
	int (*del)(struct event_base *, evutil_socket_t fd,
               short old, short events, void *fdinfo);
	// 事件循环核心函数 事件就绪时为每个事件调用event_active
	int (*dispatch)(struct event_base *, struct timeval *);
	// 清除和释放 event_base
	void (*dealloc)(struct event_base *);
	// 在fork后是否需要重新初始化event_base 
	int need_reinit;
    // 用于描述 event_base 提供了哪些功能的标志
event_config_require_features() 告诉 Libevent 仅在您的
    event_base 实现了一个给定的特性
    // event_base_get_features() 以查看哪些功能可用
    // event_config_require_features()输入应用程序要求的必需 event 方法功能
    // EV_FEATURE_ET = 0x01, 边缘触发
    // EV_FEATURE_O1 = 0x02, O(1)事件触发 不轮询 epoll,kqueue
    // EV_FEATURE_FDS = 0x04, 可以处理包括sockets在内的各种文件描述符
    // EV_FEATURE_EARLY_CLOSE = 0x08, 可以使用EV_CLOSED检测连接关闭,不需读完所有挂起数据
	enum event_method_feature features;
	// 文件描述符记录的信息长度,会作为参数传给上面的add和del
	size_t fdinfo_len;
};
 /* 例
    const struct eventop epollops = 
    {
	    "epoll",
	    epoll_init,
	    epoll_nochangelist_add,
	    epoll_nochangelist_del,
	    epoll_dispatch,
	    epoll_dealloc,
	    1, // need reinit 
	    EV_FEATURE_ET|EV_FEATURE_O1|EV_FEATURE_EARLY_CLOSE,
	    0
    };
 */

evcb_closure 

// 一个常规事件 使用 evcb_callback 回调
#define EV_CLOSURE_EVENT 0
// 一个信号事件 使用 evcb_callback 回调
#define EV_CLOSURE_EVENT_SIGNAL 1
// 一个持久的非信号事件 使用 evcb_callback 回调
#define EV_CLOSURE_EVENT_PERSIST 2
// 一个简单的回调 使用 evcb_selfcb 回调
#define EV_CLOSURE_CB_SELF 3
// 最终回调 使用 evcb_cbfinalize 回调
#define EV_CLOSURE_CB_FINALIZE 4
// 一个终止事件 使用 evcb_evfinalize 回调
#define EV_CLOSURE_EVENT_FINALIZE 5
// 结束后应该被释放的事件 使用 evcb_evfinalize 回调
#define EV_CLOSURE_EVENT_FINALIZE_FREE 6

event_callback

struct event_callback {
	TAILQ_ENTRY(event_callback) evcb_active_next; // 下一个event_callback实例的指针
    /* evcb_flags 
    #define EVLIST_TIMEOUT	    0x01  // 超时,事件在time min_heap堆中
    #define EVLIST_INSERTED	    0x02  // 事件在已注册事件链表中
    #define EVLIST_SIGNAL	    0x04  // 信号,目前暂未使用
    #define EVLIST_ACTIVE	    0x08  // 事件在激活链表中
    #define EVLIST_INTERNAL	    0x10  // 内部使用标记
    #define EVLIST_ACTIVE_LATER 0x20  // 延迟激活,事件在下一次激活链表中
    #define EVLIST_FINALIZING   0x40  // 事件已终止
    #define EVLIST_INIT	    0x80      // 事件初始化完成

    #define EVLIST_ALL          0xff  // 判断合法性
    */
	short evcb_flags; // 选择回调类型

	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; 
};

event_changelist 


    struct event_changelist
    {
    	struct event_change *changes;
	    int n_changes; 
	    int changes_size;
    };

    struct event_change 
    {
	    // 改变事件的文件描述符或信号
	    evutil_socket_t fd;
	    // 更改前的旧事件
	    short old_events;

        // 更改标志 unsigned char
	    ev_uint8_t read_change;
	    ev_uint8_t write_change;
	    ev_uint8_t close_change;
    };
    

evsig_info

struct evsig_info {
	/* Event watching ev_signal_pair[1] */
	struct event ev_signal;
	/* Socketpair 从信号处理handler出发送通知*/
	evutil_socket_t ev_signal_pair[2];
	// 如果添加了 ev_signal 事件则为真
	int ev_signal_added;
	// 信号计数
	int ev_n_signals_added; 
#ifdef EVENT__HAVE_SIGACTION
	struct sigaction **sh_old;  // 指针数组,存放信号处理函数
#else
	ev_sighandler_t **sh_old;  // 指针数组,存放信号处理函数
#endif
	// 数组指针size
	int sh_old_max;
};

event_io_map 

#ifdef _WIN32    // 如果在win32中
#define EVMAP_USE_HT  // 则定义 EVMAP_USE_HT  
#endif

/* #define HT_CACHE_HASH_VALS */
#ifdef EVMAP_USE_HT   
#define HT_NO_CACHE_HASH_VALUES
#include "ht-internal.h"
struct event_map_entry;
HT_HEAD(event_io_map, event_map_entry);  // 如果在windows环节下,event_io_map会使用哈希结构
#else
#define event_io_map event_signal_map    // 否则当成 event_signal_map 来使用
#endif

struct event_signal_map 
{
	void **entries; // 二级指针,evmap_signal* 数组
	int nentries;   // evmap_signal* 个数
};
    
#ifdef HT_NO_CACHE_HASH_VALUES
#define HT_ENTRY(type)                          \
  struct {                                      \
    struct type *hte_next;                      \
  }
#else
#define HT_ENTRY(type)                          \
  struct {                                      \
    struct type *hte_next;                      \
    unsigned hte_hash;                          \
  }
#endif

#define HT_HEAD(name, type)                                             \
  struct name {                                                         \
    /* 哈希表,可当做数组. */                                        \
    struct type **hth_table;                                            \
    /* 哈希表 数组长度 */                                   \
    unsigned hth_table_length;                                          \
    /* 元素个数 */                     \
    unsigned hth_n_entries;                                             \
    /* 最大扩容限制 */ \
    unsigned hth_load_limit;                                            \
    /* 索引 */             \
    int hth_prime_idx;                                                  \
  }

#ifdef EVMAP_USE_HT
struct event_map_entry {
    /* 
    struct 
    {                                   
        struct type *hte_next;  // 构成链表
        #ifndef HT_NO_CACHE_HASH_VALUES             
        unsigned hte_hash;  // windows 下没有
        #endif    
    }map_node;
    
	HT_ENTRY(event_map_entry) map_node;
	evutil_socket_t fd; // 文件描述符
	union { 
        /*
        #define LIST_HEAD(name, type)						\
        struct name 
        {								\
	        struct type *lh_first;  /* first element */			\
	    }
        #endif /* !LIST_HEAD */
        struct evmap_io
        {
            // LIST_HEAD (event_dlist, event); 声明在上面
	        struct event_dlist events;
	        ev_uint16_t nread;
	        ev_uint16_t nwrite;
	        ev_uint16_t nclose;
        };
		struct evmap_io evmap_io; // 记录读写fd及数量
	} ent;
};

event_iocp_port

struct event_iocp_port {
	// 端口
	HANDLE port;
	// 临界区 锁
	CRITICAL_SECTION lock;
	// 线程数量
	short n_threads;
	// 关闭标志
	short shutdown;
	// 多久检查一次关闭和其他条件
	long ms;
	// 等待事件的线程
	HANDLE *threads;
	// 在当前端口上打开线程的数量
	short n_live_threads;
	// 完成关闭时发出的信号的信号量
	HANDLE *shutdownSemaphore;
};

个人理解,不一定都是对的,仅供参考

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值