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初始化后返回值赋值给 evbasevoid *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 的sizeint n_common_timeouts_allocated;// 事件读写Map看下文有注解 struct event_io_map io;// 信号到事件的映射struct event_signal_map sigmap;// 超时事件的优先队列struct min_heap timeheap;// 存储时间值,用于避免调用 gettimeofday/clock_gettimestruct 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的线程IDunsigned 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.evbasevoid *(*init)(struct event_base *);// 激活一个给定的文件描述符或者信号上启动读/写,例 EV_READ,EV_WRITE,EV_SIGNAL, EV_ETint (*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_activeint (*dispatch)(struct event_base *, struct timeval *);// 清除和释放 event_basevoid (*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和delsize_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 charev_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_SIGACTIONstruct sigaction **sh_old; // 指针数组,存放信号处理函数
#elseev_sighandler_t **sh_old; // 指针数组,存放信号处理函数
#endif// 数组指针sizeint 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 来使用
#endifstruct 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;
};
个人理解,不一定都是对的,仅供参考
Libevent 源码学习笔记(1)event 与 event_base相关推荐
- Libevent源码学习笔记一:event2/event.h
一.libevent标准使用方法: 每个程序使用Libevent必须include <event2/event.h> 头文件,并 传给 -levent 链接器.如果只是想使用主要的eve ...
- Apache log4j-1.2.17源码学习笔记
(1)Apache log4j-1.2.17源码学习笔记 http://blog.csdn.net/zilong_zilong/article/details/78715500 (2)Apache l ...
- Java多线程之JUC包:Semaphore源码学习笔记
若有不正之处请多多谅解,并欢迎批评指正. 请尊重作者劳动成果,转载请标明原文链接: http://www.cnblogs.com/go2sea/p/5625536.html Semaphore是JUC ...
- RocketMQ 源码学习笔记 Producer 是怎么将消息发送至 Broker 的?
RocketMQ 源码学习笔记 Producer 是怎么将消息发送至 Broker 的? 文章目录 RocketMQ 源码学习笔记 Producer 是怎么将消息发送至 Broker 的? 前言 项目 ...
- Vuex 4源码学习笔记 - 通过Vuex源码学习E2E测试(十一)
在上一篇笔记中:Vuex 4源码学习笔记 - 做好changelog更新日志很重要(十) 我们学到了通过conventional-changelog来生成项目的Changelog更新日志,通过更新日志 ...
- Vuex 4源码学习笔记 - Vuex是怎么与Vue结合?(三)
在上一篇笔记中:Vuex源码学习笔记 - Vuex开发运行流程(二) 我们通过运行npm run dev命令来启动webpack,来开发Vuex,并在Vuex的createStore函数中添加了第一个 ...
- jquery源码学习笔记三:jQuery工厂剖析
jquery源码学习笔记二:jQuery工厂 jquery源码学习笔记一:总体结构 上两篇说过,query的核心是一个jQuery工厂.其代码如下 function( window, noGlobal ...
- 雷神FFMpeg源码学习笔记
雷神FFMpeg源码学习笔记 文章目录 雷神FFMpeg源码学习笔记 读取编码并依据编码初始化内容结构 每一帧的视频解码处理 读取编码并依据编码初始化内容结构 在开始编解码视频的时候首先第一步需要注册 ...
- PHP Yac cache 源码学习笔记
YAC 源码学习笔记 本文地址 http://blog.csdn.net/fanhengguang_php/article/details/54863955 config.m4 检测系统共享内存支持情 ...
最新文章
- 创建react应用程序_通过创建食谱应用程序来学习在React中使用API
- 城市大脑不仅是AI系统,更是结合人类智慧的混合智能巨系统
- 牛津大学入学面试就这?组队选个颜色?背后的逻辑水深得很
- python各个解释器的用途-Python解释器有哪些?Python解释器种类
- python 测试用例中设置执行时间_Python基于unittest实现测试用例执行
- hdu 6386 Age of Moyu (重边判断)
- SAP Spartacus B2B页面内容的动态注入
- eclipse中对于Java虚拟机参数的设置与思考
- Android 代码混淆(一)
- 读书笔记-泛型有限通配符
- MSCRM与MS人立方关系的集成
- 视频播放的时候不拦截OK键
- NVivo 12 Mac的大规模部署
- 颜色科学与计算机测色配色实用技术,颜色科学与计算机测色配色实用技术
- #PLC_梯形图简史(内含早期梯形图编程珍贵画面)
- [996]如何申请高德地图用户Key
- Simulink仿真设置和Scope示波器的使用[方案]
- git subtree pull 错误 Working tree has modifications
- Java 全角半角转换工具类
- 解决 Edge 浏览器 阻止下载
热门文章
- 普通设备能不能接入TSN时间敏感网络?
- 分享微信抽奖小程序制作步骤_微信抽奖小程序怎么开发
- 矩阵股份上市首日跌破发行价:振幅达10%,王冠为实际控制人
- 插入数据时异常 Unknown column ‘XXX‘ in ‘field list‘
- 微视狂砸千万补贴,却惨遭微信封杀,亲兄弟明算账
- 使用PIL为图片添加水印[python]
- 最全流媒体协议详细总结介绍(RTP/RTCP/RTSP/RTMP/MMS/HLS/HTTP/ HTTP-FLV(HDL) /SDP)
- 两波形相位差的计算值_光纤耦合器怎么计算
- 数据的统计量特征---懒得整理
- VisionPro文档 -- 在单个作业里的多相机采集