libevent源码学习1---创建event
libevent源码学习1—创建event
Libevent是一个用于开发可扩展性网络服务器的基于事件驱动(event-driven)模型的非阻塞网络库。安装请参考ubuntu下载安装libevent
event_base
使用 libevent
函数之前需要分配一个或者多个 event_base
结构体。每个 event_base
结构体持有一个事件集合,可以检测以确定哪个事件是激活的。
如果设置 event_base 使用锁,则可以安全地在多个线程中访问它 。然而,其事件循环只能运行在一个线程中。如果需要用多个线程检测 IO,则需要为每个线程使用一个 event_base。
每个 event_base
都有一种用于检测哪种事件已经就绪的 “方法”,或者说后端
1创建event_base:
1.1创建默认的event_base:
event_base_new() 函数分配并且返回一个新的具有默认设置的 event_base。函数会检测环境变量,返回一个到 event_base 的指针。如果发生错误,则返回 NULL。选择各种方法时,函数会选择 OS 支持的最快方法。
struct event_base *event_base_new(void);
也可以使用event_init(void)
来初始化一个event_base
。
两个函数实现:
struct event_base *
event_init(void)
{struct event_base *base = event_base_new_with_config(NULL);if (base == NULL) {event_errx(1, "%s: Unable to construct event_base", __func__);return NULL;}current_base = base;return (base);
}struct event_base *
event_base_new(void)
{struct event_base *base = NULL;struct event_config *cfg = event_config_new();if (cfg) {base = event_base_new_with_config(cfg);event_config_free(cfg);}return base;
}
event_base这个结构体源码实现(感兴趣可以看看):
struct event_base {/** Function pointers and other data to describe this event_base's* backend. */const struct eventop *evsel;/** Pointer to backend-specific data. */void *evbase;/** List of changes to tell backend about at next dispatch. Only used* by the O(1) backends. */struct event_changelist changelist;/** Function pointers used to describe the backend that this event_base* uses for signals */const struct eventop *evsigsel;/** Data to implement the common signal handler code. */struct evsig_info sig;/** Number of virtual events */int virtual_event_count;/** Maximum number of virtual events active */int virtual_event_count_max;/** Number of total events added to this event_base */int event_count;/** Maximum number of total events added to this event_base */int event_count_max;/** Number of total events active in this event_base */int event_count_active;/** Maximum number of total events active in this event_base */int event_count_active_max;/** Set if we should terminate the loop once we're done processing* events. */int event_gotterm;/** Set if we should terminate the loop immediately */int event_break;/** Set if we should start a new instance of the loop immediately. */int event_continue;/** The currently running priority of events */int event_running_priority;/** Set if we're running the event_base_loop function, to prevent* reentrant invocation. */int running_loop;/** Set to the number of deferred_cbs we've made 'active' in the* loop. This is a hack to prevent starvation; it would be smarter* to just use event_config_set_max_dispatch_interval's max_callbacks* feature */int n_deferreds_queued;/* Active event management. *//** An array of nactivequeues queues for active event_callbacks (ones* that have triggered, and whose callbacks need to be called). Low* priority numbers are more important, and stall higher ones.*/struct evcallback_list *activequeues;/** The length of the activequeues array */int nactivequeues;/** A list of event_callbacks that should become active the next time* we process events, but not this time. */struct evcallback_list active_later_queue;/* common timeout logic *//** An array of common_timeout_list* for all of the common timeout* values we know. */struct common_timeout_list **common_timeout_queues;/** The number of entries used in common_timeout_queues */int n_common_timeouts;/** The total size of common_timeout_queues. */int n_common_timeouts_allocated;/** Mapping from file descriptors to enabled (added) events */struct event_io_map io;/** Mapping from signal numbers to enabled (added) events. */struct event_signal_map sigmap;/** Priority queue of events with timeouts. */struct min_heap timeheap;/** Stored timeval: used to avoid calling gettimeofday/clock_gettime* too often. */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;/** Second in which we last updated tv_clock_diff, in monotonic time. */time_t last_updated_clock_diff;#ifndef EVENT__DISABLE_THREAD_SUPPORT/* threading support *//** The thread currently running the event_loop for this base */unsigned long th_owner_id;/** A lock to prevent conflicting accesses to this event_base */void *th_base_lock;/** A condition that gets signalled when we're done processing an* event with waiters on it. */void *current_event_cond;/** Number of threads blocking on current_event_cond. */int current_event_waiters;
#endif/** The event whose callback is executing right now */struct event_callback *current_event;#ifdef _WIN32/** IOCP support structure, if IOCP is enabled. */struct event_iocp_port *iocp;
#endif/** Flags that this base was configured with */enum event_base_config_flag flags;struct timeval max_dispatch_time;int max_dispatch_callbacks;int limit_callbacks_after_prio;/* Notify main thread to wake up break, etc. *//** True if the base already has a pending notify, and we don't need* to add any more. */int is_notify_pending;/** A socketpair used by some th_notify functions to wake up the main* thread. */evutil_socket_t th_notify_fd[2];/** An event used by some th_notify functions to wake up the main* thread. */struct event th_notify;/** A function used to wake up the main thread from another thread. */int (*th_notify_fn)(struct event_base *base);/** Saved seed for weak random number generator. Some backends use* this to produce fairness among sockets. Protected by th_base_lock. */struct evutil_weakrand_state weakrand_seed;/** List of event_onces that have not yet fired. */LIST_HEAD(once_event_list, event_once) once_events;
};
1.2 创建复杂的event_base
要对取得什么类型的 event_base 有更多的控制,就需要使用 event_config。
event_config 是一个容纳 event_base 配置信息的结构体。需要 event_base 时,将 event_config 传递给event_base_new_with_config ()。
/** Internal structure: describes the configuration we want for an event_base* that we're about to allocate. */
struct event_config {TAILQ_HEAD(event_configq, event_config_entry) entries;int n_cpus_hint;struct timeval max_dispatch_interval;int max_dispatch_callbacks;int limit_callbacks_after_prio;enum event_method_feature require_features;enum event_base_config_flag flags;
};
创建接口
struct event_config *event_config_new(void);
struct event_base *event_base_new_with_config(const struct event_config *cfg);
void event_config_free(struct event_config *cfg);
要使用这些函数分配 event_base
,先调用 event_config_new()
分配一个 event_config
。 然后,对 event_config
调用其它函数,设置所需要的 event_base
特征。最后,调用 event_base_new_with_config()
获取新的 event_base
。完成工作后,使用 event_config_free ()
释放 event_config
。
int event_config_avoid_method(struct event_config *cfg, const char *method);
enum event_method_feature {/** Require an event method that allows edge-triggered events with EV_ET. */EV_FEATURE_ET = 0x01,/** Require an event method where having one event triggered among* many is [approximately] an O(1) operation. This excludes (for* example) select and poll, which are approximately O(N) for N* equal to the total number of possible events. */EV_FEATURE_O1 = 0x02,/** Require an event method that allows file descriptors as well as* sockets. */EV_FEATURE_FDS = 0x04,/** Require an event method that allows you to use EV_CLOSED to detect* connection close without the necessity of reading all the pending data.** Methods that do support EV_CLOSED may not be able to provide support on* all kernel versions.**/EV_FEATURE_EARLY_CLOSE = 0x08
};int event_config_require_features(struct event_config *cfg,enum event_method_feature feature);enum event_base_config_flag {/** Do not allocate a lock for the event base, even if we havelocking set up.Setting this option will make it unsafe and nonfunctional to callfunctions on the base concurrently from multiple threads.*/EVENT_BASE_FLAG_NOLOCK = 0x01,/** Do not check the EVENT_* environment variables when configuringan event_base */EVENT_BASE_FLAG_IGNORE_ENV = 0x02,/** Windows only: enable the IOCP dispatcher at startupIf this flag is set then bufferevent_socket_new() andevconn_listener_new() will use IOCP-backed implementationsinstead of the usual select-based one on Windows.*/EVENT_BASE_FLAG_STARTUP_IOCP = 0x04,/** Instead of checking the current time every time the event loop isready to run timeout callbacks, check after each timeout callback.*/EVENT_BASE_FLAG_NO_CACHE_TIME = 0x08,/** If we are using the epoll backend, this flag says that it issafe to use Libevent's internal change-list code to batch upadds and deletes in order to try to do as few syscalls aspossible. Setting this flag can make your code run faster, butit may trigger a Linux bug: it is not safe to use this flagif you have any fds cloned by dup() or its variants. Doing sowill produce strange and hard-to-diagnose bugs.This flag can also be activated by setting theEVENT_EPOLL_USE_CHANGELIST environment variable.This flag has no effect if you wind up using a backend other thanepoll.*/EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10,/** Ordinarily, Libevent implements its time and timeout code usingthe fastest monotonic timer that we have. If this flag is set,however, we use less efficient more precise timer, assuming one ispresent.*/EVENT_BASE_FLAG_PRECISE_TIMER = 0x20
};int event_config_set_flag(struct event_config *cfg,enum event_base_config_flag flag);
调用 event_config_avoid_method ()
在配置中输入应避免的事件方法。这可用于避免不支持某些的事件机制文件描述符类型,或用于调试以避免某些事件机制。 应用程序可以利用多个事件基础来适应不兼容的文件描述符类型。
调用 event_config_require_feature ()
输入应用程序所需的事件方法功能。
调用 event_config_set_flag()
让 libevent 在创建 event_base
时设置一个或者多个将在下面介绍的运行时标志。
event_config_require_features()可识别的特征值有:
- EV_FEATURE_ET:要求支持边沿触发
- EV_FEATURE_O1:要求添加、删除单个事件,或者确定哪个事件激活的操作是 O(1)复杂度
- EV_FEATURE_FDS:要求支持任意文件描述符,而不仅仅是套接字
- EV_FEATURE_EARLY_CLOSE : 需要一个事件方法,该方法允许您使用 EV_CLOSED 来检测连接关闭,而无需读取所有挂起的数据。
event_config_set_flag()可识别的选项值有:
- EVENT_BASE_FLAG_NOLOCK:不要为 event_base 分配锁。设置这个选项可以 为 event_base 节省一点用于锁定和解锁的时间,但是让在多个线程中访问 event_base 成为不安全的。
- EVENT_BASE_FLAG_IGNORE_ENV:配置event_base时,请勿检查 EVENT_* 环境变量。使用这个标志需要三思:这会让用户更难调试你的程序与 libevent 的交互。
- EVENT_BASE_FLAG_STARTUP_IOCP:仅用于 Windows,让 libevent 在启动时就 启用任何必需的 IOCP 分发逻辑,而不是按需启用。
- EVENT_BASE_FLAG_NO_CACHE_TIME:不是在事件循环每次准备执行超时回调时 检测当前时间,而是在每次超时回调后进行检测。注意:这会消耗更多的 CPU时间。
- EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST:如果我们使用epoll后端,这个标志表示它是可以安全地使用Libevent的内部change-list代码进行批处理添加和删除,以便尽可能少地执行系统调用,设置此标志可以使代码运行得更快,但是它可能会触发一个Linux错误:使用这个标志是不安全的如果您有任何由dup()或其变体克隆的FDS。这样做会产生奇怪且难以诊断的bug。此标志也可以通过设置
EVENT_EPOLL_USE_CHANGELIST环境变量。如果您最终使用的后端不是epoll。
上述操作 event_config 的函数都在成功时返回0,失败时返回-1。
2 检查event_base后端
有时候需要检查 event_base 支持哪些特征,或者当前使用哪种方法。
接口1
const char **event_get_supported_methods(void);
event_get_supported_methods()函数返回一个指针 ,指向 libevent 支持的方法名字数组 。 这个数组的最后一个元素是 NULL。
实例:
const char **methods = event_get_supported_methods();
printf("Starting Libevent %s. Available methods are:\n", event_get_version());
for (int i = 0; methods[i] != NULL; ++i)
{printf("%s\n", methods[i]);
}
输出:
Starting Libevent 2.1.12-stable. Available methods are:
epoll
poll
select
接口2
const char *event_base_get_method(const struct event_base *base);
enum event_method_feature event_base_get_features(const struct event_base *base);
event_base_get_method()返回 event_base 正在使用的方法。
event_base_get_features ()返回 event_base 支持的特征的比特掩码。
实例:
struct event_base *base = event_base_new();
enum event_method_feature f;
if (!base)
{printf("Couldn't get an event_base!\n");
}
else
{printf("Using Libevent with backend method is %s.\n", event_base_get_method(base));f = (event_method_feature)event_base_get_features(base);if ((f & EV_FEATURE_ET))printf("Edge-triggered events are supported.\n");if ((f & EV_FEATURE_O1))printf("O(1) event notification is supported.\n");if ((f & EV_FEATURE_FDS))printf("All FD types are supported.\n");
}
本机输出结果:
Using Libevent with backend method is epoll.
Edge-triggered events are supported.
O(1) event notification is supported.
3 释放event_base
使用完 event_base 之后,使用 event_base_free()进行释放。
void event_base_free(struct event_base *base);
4 event_base优先级
libevent支持为事件设置多个优先级。然而, event_base默认只支持单个优先级。可以调用 event_base_priority_init()设置 event_base 的优先级数目。
int event_base_priority_init(struct event_base *base, int n_priorities);
成功时这个函数返回 0,失败时返回 -1。base 是要修改的 event_base,n_priorities 是要支持的优先级数目,这个数目至少是 1 。每个新的事件可用的优先级将从 0 (最高) 到 n_priorities-1(最低)。
常量 EVENT_MAX_PRIORITIES 表示 n_priorities 的上限。
// 源码
#define EVENT_MAX_PRIORITIES 256
5 event_base和fork
不是所有事件都在调用 fork()之后可以正确工作。所以,如果在使用 fork()或者其他相关系统调用启动新进程之后,希望在新进程中继续使用 event_base,就需要进行重新初始化。
int event_reinit(struct event_base *base);
未完待续。。。
收藏+关注,后续继续更新
相关文章:
libevent源码学习1---创建event
libevent源码学习1—创建event Libevent是一个用于开发可扩展性网络服务器的基于事件驱动(event-driven)模型的非阻塞网络库。安装请参考ubuntu下载安装libevent event_base 使用 libevent 函数之前需要分配一个或者多个 event_base 结构体。每个 event_base 结构体持有一个…...

Python类的设计
Python类的设计 # 定义一个闹钟类 class Clock:__cureen_keyNone # 私有成员不能改变和使用def __init__(self, id, price): # 类对象是立即自动执行self.id idself.price pricedef ring(self):import winsound # 内置声音方法winsound.Beep(2000,3000)clock1 Clock(…...

微信小程序的项目解构
视频链接 黑马程序员前端微信小程序开发教程,微信小程序从基础到发布全流程_企业级商城实战(含uni-app项目多端部署)_哔哩哔哩_bilibili 接口文档 https://www.escook.cn/docs-uni-shop/mds/1.start.html 1:微信小程序宿主环境 1:常见的宿…...

【Archaius技术专题】「Netflix原生态」动态化配置服务之微服务配置组件变色龙
前提介绍 如果要设计开发一套微服务基础架构,参数化配置是一个非常重要的点,而Netflix也开源了一个叫变色龙Archaius的配置中心客户端,而且Archaius可以说是比其他客户端具备更多生产级特性,也更灵活。*在NetflixOSS微服务技术栈…...

python条件分支和循环语句
python中没有{}的写法,一般时通过缩进的方式来确定分支和循环需要执行的代码块。 if 需要判断的条件表达式:条件成立时的动作 elif 需要判断的条件表达式:条件成立时的动作 else:动作for 变量 in 迭代对象:动作 示例: while 退出条件:动作...

工具推荐:Wireshark网络协议分析工具(对比tcpdump)
文章首发地址 Wireshark是一款开源的网络协议分析工具,可以捕获网络数据包并对其进行详细的分析和解释。下面是Wireshark的详细介绍: Wireshark 工作原理 Wireshark通过捕获网络接口上的数据包,将其转换为可读的格式,并在界面…...

[OnWork.Tools]系列 04-快捷启动
简介 主要功能是将常用的软件拖动到软件中,实现快速点击启动,结合软件设置中的设置的快捷键,可以快速呼出对应的面板,使用快捷键快速启动应用 拖拽内容 拖拽快捷方式到面板,双击快速打开 拖拽文件方式到面板,双击快速打开 拖拽文件夹到面板双击快速打开 拖拽项目调整顺序 右…...
如何将项目挂后台运行?【nohup和tmux】
挂后台运行,防止霸屏。 线上的程序不会将日志输出到控制台,而是输出到日志文件,方便运维查阅信息。 一.nohup--挂后台运行的命令 //nohup--英文全称no hang up,可以后台运行指定命令 //hello.log是指将日志输出到hello.log文件 …...

什么是进程、线程、协程
什么是进程? 我们都知道计算机的核心是CPU,它承担了所有的计算任务;而操作系统是计算机的管理者,它负责任务的调度、资源的分配和管理,统领整个计算机硬件;应用程序则是具有某种功能的程序,程序…...
Python爬虫——selenium_访问元素信息
from selenium import webdriver# 创建浏览器对象 path files/chromedriver.exe browser webdriver.Chrome(path)# 访问地址 url https://www.baidu.com browser.get(url)input browser.find_element_by_id(su)获取元素属性 .get_attribute(class)print(input.get_attribu…...

Linux 文件基本属性
Linux 文件基本属性 Linux 系统是一种典型的多用户系统,不同的用户处于不同的地位,拥有不同的权限。 为了保护系统的安全性,Linux 系统对不同的用户访问同一文件(包括目录文件)的权限做了不同的规定。 在 Linux 中我…...

CSS 盒模型是什么?它包含哪些属性?标准盒模型/怪异盒模型
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 盒模型⭐ 标准盒模型⭐ 怪异盒模型⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅!这个专栏是为那些对Web开发感…...
VB+SQL光盘信息管理系统设计与实现
摘 要 我的毕业设计课题为“光盘管理系统”,该系统完成光盘相关信息的输入、保存和维护、是按照方便用户、容易操作、确保数据一致完整的原则进行设计。这次毕业设计的开发工具是Visual Basic 6.0,操作平台是Windows2000 Professional中文版,选用的数据库后台是SQL server2…...

MySQL5.7数据库、Navicat Premium1.6可视化工具安装教程【详细教程】
文章目录 一、MySQL、Navicat、注册机地址二、安装(一)、MySQL安装(二)、Navicat Premium安装(三)、集活Navicat Premium 三、遇到的问题1、Are you sure your navicat has not beenpatched/modified befor…...

JVM 调优实例
点击下方关注我,然后右上角点击...“设为星标”,就能第一时间收到更新推送啦~~~ JVM提供了多种垃圾回收器,可以根据应用程序的需求选择最适合的垃圾回收器。例如,如果应用程序需要更快的响应时间,可以选择并行垃圾回收…...

Python numpy中的correlate相关性详解
看代码看见这个方法,记录一下,这个是人家官网的链接np.correlate 云里雾里的,其实就是两个数组点乘,不同模式就是错位点乘,直接看代码 a是原本的数组,v就是滤波器,对应相乘 import numpy as …...
用python实现xmind用例转换为excel/csv用例
from xmindparser import xmind_to_dict from openpyxl import Workbook# 解析XMind文件 xmind_file path/to/xmind/file.xmind xmind_data xmind_to_dict(xmind_file)# 创建Excel文件 excel_file path/to/excel/file.xlsx wb Workbook() ws wb.active# 定义用例表格的列名…...

论文浅尝 | 面向多步推理任务专业化较小语言模型
笔记整理:张沈昱,东南大学硕士,研究方向为自然语言处理 链接:https://github.com/FranxYao/FlanT5-CoT-Specialization 动机 本文的动机是探索如何在多步推理任务中通过大型语言模型提升较小的语言模型的性能。作者认为࿰…...

基于Java的新闻全文搜索引擎的设计与实现
中文摘要 本文以学术研究为目的,针对新闻行业迫切需求和全文搜索引擎技术的优越性,设计并实现了一个针对新闻领域的全文搜索引擎。该搜索引擎通过Scrapy网络爬虫工具获取新闻页面,将新闻内容存储在分布式存储系统HBase中,并利用倒…...

golang 自定义exporter - 端口连接数 portConnCount_exporter
需求: 1、计算当前6379 、3306 服务的连接数 2、可prometheus 语法查询 下面代码可直接使用: 注: 1、windows 与linux的区分 第38行代码 localAddr : fields[1] //windows为fields[1] , linux为fields[3] 2、如需求 增加/修改/删除…...

【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...

MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...

大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...

JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...
API网关Kong的鉴权与限流:高并发场景下的核心实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 引言 在微服务架构中,API网关承担着流量调度、安全防护和协议转换的核心职责。作为云原生时代的代表性网关,Kong凭借其插件化架构…...