libevent源码学习3---事件event

libevent源码学习3—事件event

libevent 的基本操作单元是事件。每个事件代表一组条件的集合, 这些条件包括:

  • 文件描述符已经就绪, 可以读取或者写入
  • 文件描述符变为就绪状态,可以读取或者写入(仅对于边沿触发 IO)
  • 超时事件
  • 发生某信号
  • 用户触发事件
    所有事件具有相似的生命周期。调用 libevent 函数设置事件并且关联到 event_base 之后, 事件进入“已初始化(initialized)”状态。此时可以将事件添加到 event_base 中,这使之进入“未决(pending)” 状态。在未决状态下, 如果触发事件的条件发生(比如说,文件描述符的状态改变, 或者超时时间到达 ),则事件进入“激活(active)”状态,(用户提供的)事件回调函数将被执行。如果配置为“持久的(persistent)”, 事件将保持为未决状态。否则, 执行完回调后, 事件不再是未决的。删除操作可以让未决事件成为非未决(已初始化)的 ; 添加操作可以让非未决事件再次成为未决的。

ps:未决: 简单来说就是一个已经产生的信号,但是还没有传递给任何进程,此时该信号的状态就称为未决状态。

1.创建事件

1.1 生成新事件

使用 event_new()接口创建事件。

#define EV_TIMEOUT      0x01
#define EV_READ         0x02
#define EV_WRITE        0x04
#define EV_SIGNAL       0x08
#define EV_PERSIST      0x10
#define EV_ET           0x20
typedef void (*event_callback_fn)(evutil_socket_t, short, void *);
struct event *event_new(struct event_base *base, evutil_socket_t fd,short events, event_callback_fn cb, void *arg);
void event_free(struct event *event);

event_new()试图分配和构造一个用于 base 的新的事件。events参数是上述标志的集合。如果 fd 非负, 则它是将被观察其读写事件的文件。事件被激活时, libevent 将调用 cb 函数, 传递这些参数: 文件描述符 fd, 表示所有被触发事件的位字段 , 以及构造事件时的 arg 参数。发生内部错误, 或者传入无效参数时, event_new()将返回 NULL。

所有新创建的事件都处于已初始化和非未决状态 ,调用 event_add()可以使其成为未决的。

要释放事件, 调用 event_free()。对未决或者激活状态的事件调用 event_free()是安全的: 在释放事件之前, 函数将会使事件成为非激活和非未决的。

event_new()实现:

struct event *event_new(struct event_base *base, evutil_socket_t fd, short events, void (*cb)(evutil_socket_t, short, void *), void *arg)
{struct event *ev;ev = mm_malloc(sizeof(struct event));if (ev == NULL)return (NULL);if (event_assign(ev, base, fd, events, cb, arg) < 0){mm_free(ev);return (NULL);}return (ev);
}

event_add()实现:

int event_add(struct event *ev, const struct timeval *tv)
{int res;if (EVUTIL_FAILURE_CHECK(!ev->ev_base)){event_warnx("%s: event has no event_base set.", __func__);return -1;}EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);res = event_add_nolock_(ev, tv, 0);EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);return (res);
}

event结构体定义:

struct event {struct event_callback ev_evcallback;/* for managing timeouts */union {TAILQ_ENTRY(event) ev_next_with_common_timeout;int min_heap_idx;} ev_timeout_pos;evutil_socket_t ev_fd;struct event_base *ev_base;union {/* used for io events */struct {LIST_ENTRY (event) ev_io_next;struct timeval ev_timeout;} ev_io;/* used by signal events */struct {LIST_ENTRY (event) ev_signal_next;short ev_ncalls;/* Allows deletes in callback */short *ev_pncalls;} ev_signal;} ev_;short ev_events;short ev_res;		/* result passed to event callback */struct timeval ev_timeout;
};

1.2 事件标志

  • EV_TIMEOUT:这个标志表示某超时时间流逝后事件成为激活的。构造事件的时候, EV_TIMEOUT 标志是被忽略的: 可以在添加事件的时候设置超时, 也可以不设置。超时发生时,回调函数的 what 参数将带有这个标志。
  • EV_READ:表示指定的文件描述符已经就绪, 可以读取的时候, 事件将成为激活的。
  • EV_WRITE:表示指定的文件描述符已经就绪, 可以写入的时候, 事件将成为激活的。
  • EV_SIGNAL:用于实现信号检测
  • EV_PERSIST:表示事件是“持久的”
  • EV_ET:表示如果底层的 event_base 后端支持边沿触发事件(默认水平),则事件应该是边沿触发的。这个标志影响 EV_READ 和 EV_WRITE 的语义。

1.3 关于事件持久性

默认情况下,每当未决事件成为激活的(fd 已经准备好读取或者写入,或者因为超时),事件将在其回调被执行前成为非未决的。如果想让事件再次成为未决的,可以在回调函数中再次对其调用 event_add()。

然而,如果设置了 EV_PERSIST 标志,事件就是持久的。这意味着即使其回调被激活,事件还是会保持为未决状态。 如果想在回调中让事件成为非未决的,可以对其调用 event_del()。

每次执行事件回调的时候,持久事件的超时值会被复位。因此,如果具有 EV_READ|EV_PERSIST 标志,以及5秒(你设置的值)的超时值,则事件将在以下情况下成为激活的:

  • 套接字已经准备好被读取的时候
  • 从最后一次成为激活的开始,已经过去5秒

1.4 信号事件

libevent 也可以监测 POSIX 风格的信号。要构造信号处理器

#define evsignal_new(b, x, cb, arg)				\event_new((b), (x), EV_SIGNAL|EV_PERSIST, (cb), (arg))

libevent 也提供了一组方便使用的宏用于处理信号事件:

#define evsignal_add(ev, tv)		event_add((ev), (tv))
#define evsignal_assign(ev, b, x, cb, arg)			\event_assign((ev), (b), (x), EV_SIGNAL|EV_PERSIST, cb, (arg))
#define evsignal_del(ev)		event_del(ev)
#define evsignal_pending(ev, tv)	event_pending((ev), EV_SIGNAL, (tv))
#define evsignal_initialized(ev)	event_initialized(ev)

2.事件的未决和非未决

构造事件之后,在将其添加到 event_base 之前实际上是不能对其做任何操作的。使用event_add()将事件添加到 event_base

2.1 设置未决事件

int event_add(struct event *ev, const struct timeval *tv);

在非未决的事件上调用 event_add()将使其在配置的 event_base 中成为未决的。成功时函数返回0, 失败时返回-1。

如果 tv 为 NULL, 添加的事件不会超时。否则, tv 以秒和微秒指定超时值。

如果对已经未决的事件调用 event_add(), 事件将保持未决状态, 并在指定的超时时间被重新调度。

2.2 设置非未决事件

int event_del(struct event *ev);

对已经初始化的事件调用 event_del()将使其成为非未决和非激活的。如果事件不是未决的或者激活的, 调用将没有效果。成功时函数返回 0, 失败时返回-1。

注意: 如果在事件激活后, 其回调被执行前删除事件, 回调将不会执行。

3.事件的优先级

int event_priority_set(struct event *ev, int pri)
{event_debug_assert_is_setup_(ev);if (ev->ev_flags & EVLIST_ACTIVE)return (-1);if (pri < 0 || pri >= ev->ev_base->nactivequeues)return (-1);ev->ev_pri = pri;return (0);
}

注意优先级的值的范围在第7行源码。相关数据结构释义:

/* 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;

4.检查事件状态

有时候需要了解事件是否已经添加,检查事件代表什么。libevent中有很多函数来获取不同的信息。

/**Checks if a specific event is pending or scheduled.@param ev an event struct previously passed to event_add()@param events the requested event type; any of EV_TIMEOUT|EV_READ|EV_WRITE|EV_SIGNAL@param tv if this field is not NULL, and the event has a timeout, this field is set to hold the time at which the timeout will expire.@return true if the event is pending on any of the events in 'what', (that is to say, it has been added), or 0 if the event is not added.*/
int event_pending(const struct event *ev, short events, struct timeval *tv);

event_pending()函数确定给定的事件是否是未决的或者激活的。如果是,·而且 events 参数设置了 EV_READ、EV_WRITE、EV_SIGNAL 或者 EV_TIMEOUT 等标志,则函数会返回事件当前为之未决或者激活的所有标志 。

/**Extract _all_ of arguments given to construct a given event.  The event_base is copied into *base_out, the fd is copied into *fd_out, and so on.If any of the "_out" arguments is NULL, it will be ignored.*/
void event_get_assignment(const struct event *event, struct event_base **base_out, evutil_socket_t *fd_out, short *events_out, event_callback_fn *callback_out, void **arg_out);

event_get_assignment()复制所有为事件分配的字段到提供的指针中。任何为 NULL 的参数会被忽略。

当然还有很多获取状态的函数,详情去源码event.c中查看。

5.一次触发事件

如果不需要多次添加一个事件,或者要在添加后立即删除事件,而事件又不需要是持久的 , 则可以使用 event_base_once()

int event_base_once(struct event_base *, evutil_socket_t, short, event_callback_fn, void *, const struct timeval *);

除了不支持 EV_SIGNAL 或者 EV_PERSIST 之外,这个函数的接口与 event_new()相同。

6.手动激活事件

极少数情况下,需要在事件的条件没有触发的时候让事件成为激活的。

/* You can use this function on a pending or a non-pending event to make it active, so that its callback will be run by event_base_dispatch() or event_base_loop().One common use in multithreaded programs is to wake the thread running event_base_loop() from another thread.@param ev an event to make active.@param res a set of flags to pass to the event's callback.@param ncalls an obsolete argument: this is ignored.
*/
void event_active(struct event *ev, int res, short ncalls);

7.事件状态之间的转换

img

参考《libevent深入浅出》、libevent官方文档。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/58933.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度学习推荐系统(二)Deep Crossing及其在Criteo数据集上的应用

深度学习推荐系统(二)Deep Crossing及其在Criteo数据集上的应用 在2016年&#xff0c; 随着微软的Deep Crossing&#xff0c; 谷歌的Wide&Deep以及FNN、PNN等一大批优秀的深度学习模型被提出&#xff0c; 推荐系统全面进入了深度学习时代&#xff0c; 时至今日&#xff0c…

跨站请求伪造(CSRF)

文章目录 渗透测试漏洞原理跨站请求伪造&#xff08;CSRF&#xff09;1. CSRF概述1.1 基本概念1.1.1 关键点1.1.2 目标 1.2 CSRF场景1.2.1 银行账户转账1.2.2 构造虚假网站1.2.3 场景建模1.2.4 实验 1.3 CSRF类别1.3.1 POST方式 1.4 CSRF验证1.4.1 CSRF Poc generator 1.5 XSS与…

SpringAOP详解(下)

proxyFactory代理对象创建方式和代理对象调用方法过程&#xff1a; springaop创建动态代理对象和代理对象调用方法过程&#xff1a; 一、TargetSource的使用 Lazy注解&#xff0c;当加在属性上时&#xff0c;会产生一个代理对象赋值给这个属性&#xff0c;产生代理对象的代码为…

政府科技项目验收全流程分享

科技验收测试 &#xff08;验收申请→主管部门初审→科技厅审核→组织验收→归档备案→信用管理&#xff09;&#xff1a; &#xff08;一&#xff09;验收申请 项目承担单位通过省科技业务管理系统提交验收申请。 按期完成的项目&#xff0c;项目承担单位应当在项目合同书…

C 实现Window/DOS 键盘监听事件

今天是重新复习C语言实现的第一天&#xff0c;今天想编写C 对Windwos/Dos 键盘事件的学习。但是我在安装Visual Studio 2022 没有安装MFC 框架&#xff0c;今天记录下VS追加 MFC框架。 Visual Studio 2022 追加MFC 1、打开vs&#xff0c;点击创建新项目&#xff0c;右侧滑动框…

docker 学习-- 04 实践2 (lnpmr环境)

docker 学习 系列文章目录 docker 学习-- 01 基础知识 docker 学习-- 02 常用命令 docker 学习-- 03 环境安装 docker 学习-- 04 实践 1&#xff08;宝塔&#xff09; docker 学习-- 04 实践 2 &#xff08;lnpmr环境&#xff09; 文章目录 docker 学习 系列文章目录1. 配…

5G智能网关如何解决城市停车痛点难点

2023年上半年&#xff0c;我国汽车新注册登记1175万辆&#xff0c;同比增长5.8%&#xff0c;88个城市汽车保有量超过100万辆&#xff0c;北京、成都等24个城市超过300万辆。随着车辆保有量持续增加&#xff0c;停车难问题长期困扰城市居民&#xff0c;也导致城市路段违停普遍、…

制作鲜花商城小程序的详细步骤

如果你是一个新手商家&#xff0c;想要进入鲜花团购市场&#xff0c;但是不知道如何制作一个小程序商城&#xff0c;那么这篇文章就是为你准备的。以下是制作鲜花团购小程序商城的详细步骤&#xff1a; 1. 登录乔拓云平台后台&#xff0c;进入商城管理页面 首先&#xff0c;你需…

虚拟化技术:云计算发展的核心驱动力

文章目录 虚拟化技术的概念和作用虚拟化技术的优势虚拟化技术对未来发展的影响结论 &#x1f389;欢迎来到AIGC人工智能专栏~虚拟化技术&#xff1a;云计算发展的核心驱动力 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&#xff1a;IT陈寒的博客&#x1f388;该系…

WebGL矩阵变换库

目录 矩阵变换库&#xff1a; Matrix4对象所支持的方法和属性如表所示&#xff1a; 方法属性规范&#xff1a; 虽然平移、旋转、缩放等变换操作都可以用一个44的矩阵表示&#xff0c;但是在写WebGL程序的时候&#xff0c;手动计算每个矩阵很耗费时间。为了简化编程&#xf…

opencv 案例05-基于二值图像分析(简单缺陷检测)

缺陷检测&#xff0c;分为两个部分&#xff0c;一个部分是提取指定的轮廓&#xff0c;第二个部分通过对比实现划痕检测与缺角检测。本次主要搞定第一部分&#xff0c;学会观察图像与提取图像ROI对象轮廓外接矩形与轮廓。 下面是基于二值图像分析的大致流程 读取图像将图像转换…

Spring Cloud + Spring Boot 项目搭建结构层次示例讲解

Spring Cloud Spring Boot 项目搭建结构层次示例讲解 Spring Cloud 项目搭建结构层次示例Spring Cloud示例&#xff1a; Spring Boot 项目搭建结构层次讲解Spring Boot 项目通常按照一种常见的架构模式组织&#xff0c;可以分为以下几个主要层次&#xff1a;当构建一个 Spring…

【算法系列篇】位运算

文章目录 前言什么是位运算算法1.判断字符是否唯一1.1 题目要求1.2 做题思路1.3 Java代码实现 2. 丢失的数字2.1 题目要求2.2 做题思路2.3 Java代码实现 3. 两数之和3.1 题目要求3.2 做题思路3.3 Java代码实现 4. 只出现一次的数字4.1 题目要求4.2 做题思路4.3 Java代码实现 5.…

Ansible项目实战管理/了解项目环境/项目管理

一&#xff0c;项目环境 1.项目基础 项目过程 调研阶段 设计阶段 开发阶段 测试阶段 运营阶段 2.项目环境 个人开发环境 公司开发环境 项目测试环境 项目预发布环境 灰度环境&#xff1a;本身是生产环境&#xff0c;安装项目规划&#xff0c;最终所有的生产环境都发…

Python框架【模板继承 、继承模板实战、类视图 、类视图的好处 、类视图使用场景、基于调度方法的类视图】(四)

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱敲代码的小王&#xff0c;CSDN博客博主,Python小白 &#x1f4d5;系列专栏&#xff1a;python入门到实战、Python爬虫开发、Python办公自动化、Python数据分析、Python前后端开发 &#x1f4e7;如果文章知识点有错误…

CUDA小白 - NPP(2) -图像处理-算数和逻辑操作(2)

cuda小白 原始API链接 NPP GPU架构近些年也有不少的变化&#xff0c;具体的可以参考别的博主的介绍&#xff0c;都比较详细。还有一些cuda中的专有名词的含义&#xff0c;可以参考《详解CUDA的Context、Stream、Warp、SM、SP、Kernel、Block、Grid》 常见的NppStatus&#xf…

解压jar包并导入库环境

背景 因为各种历史原因&#xff0c;当初的maven依赖环境已下载不了了&#xff0c;所以需要从生产环境的jar包里&#xff0c;获取库环境来本地运行。 但是网上很多方法都是用mvn install命令&#xff0c;一个个jar包导入的&#xff0c;不符合我的需求&#xff08;需要导入280多…

R语言APRIORI关联规则、K-MEANS均值聚类分析中药专利复方治疗用药规律网络可视化...

全文链接&#xff1a;http://tecdat.cn/?p30605 应用关联规则、聚类方法等数据挖掘技术分析治疗的中药专利复方组方配伍规律&#xff08;点击文末“阅读原文”获取完整代码数据&#xff09;。 方法检索治疗中药专利复方&#xff0c;排除外用中药及中西药物合用的复方。最近我们…

CSS3D+动画

CSS3D 1.css3D 给父元素设置 perspective:景深:近大远小的效果900-1200px这个范围内 transform-style:是否设置3D环境 flat 2D环境 默认值 perserve-3D环境 3D功能函数 1.位移: translateZ()translate3D(x,y,z) <!DOCTYPE html> <html lang"en"><h…

linux下载安装jdk

1.java安装unzip,zip yum install -y unzip zip 2.安装vim yum -y install vim* Linux-jdk1.8下载地址点击下载 jdk1.8-linux 提取码&#xff1a;h40h 1、将安装包上传至Linux服务器 2、创建安装文件夹 创建install mkdir -p /export/install3、解压到install文件夹中 tar…