libevent - Macro function

TAILQ_INIT

/*
 * Tail queue functions.
 * 尾队列的头结点初始化为空队列。
 */
#define	TAILQ_INIT(head) do {						\
	(head)->tqh_first = NULL;					\
	(head)->tqh_last = &(head)->tqh_first;				\
} while (/*CONSTCOND*/0)

TAILQ_INIT 宏是一个用于初始化尾队列头部的工具,它通过将 tqh_first 设置为 NULL 并将 tqh_last 设置为指向 tqh_first 的地址,确保队列可以从空状态正确地过渡到非空状态。这个设计使用了二级指针的概念,使得尾部插入操作更为高效和直接。这种结构广泛应用于需要动态管理链表的系统编程场景中。
do { ... } while (0)

  • 这种结构确保了宏在使用时会像一个普通的语句一样执行,而不会引起语法错误。例如,用户可以安全地在 if 语句中使用这个宏,而不会因为缺少大括号导致错误

  • (head)->tqh_first = NULL;

    • 初始化 tqh_firstNULL,表示队列当前没有任何元素,是空的。
  • (head)->tqh_last = &(head)->tqh_first;

    • 初始化 tqh_last 使其指向 tqh_first 的地址。这样做的目的是为了方便在队列末尾进行插入操作。具体来说,如果队列是空的,tqh_last 会指向 tqh_first,这意味着下一次插入的元素将成为新的第一个元素

EVUTIL_ASSERT

#define EVUTIL_ASSERT(cond)						\
	do {								\
		if (EVUTIL_UNLIKELY(!(cond))) {				\
			event_errx(EVENT_ERR_ABORT_,			\
			    "%s:%d: Assertion %s failed in %s",		\
			    __FILE__,__LINE__,#cond,__func__);		\
			/* In case a user-supplied handler tries to */	\
			/* return control to us, log and abort here. */	\
			(void)fprintf(stderr,				\
			    "%s:%d: Assertion %s failed in %s",		\
			    __FILE__,__LINE__,#cond,__func__);		\
			abort();					\
		}							\
	} while (0)

EVUTIL_ASSERT 是一个用于断言条件的宏,在条件不满足时会中止程序运行,并打印相关的调试信息。

do { ... } while (0) 结构

  • 这是一个常见的宏包装技巧,用于确保宏在使用时能够像普通语句一样执行,不会因为缺少分号或其他语法问题导致错误。
    if (EVUTIL_UNLIKELY(!(cond))) { ... }

  • EVUTIL_UNLIKELY 是一个宏或函数,通常用于提示编译器某个条件不太可能发生,这可以帮助编译器优化代码。这里的意思是,如果条件 condfalse(即条件不满足),则执行后续代码。
    event_errx(EVENT_ERR_ABORT_, "%s:%d: Assertion %s failed in %s", __FILE__, __LINE__, #cond, __func__);

  • event_errx 是一个函数,用于打印错误信息并终止程序。它会输出文件名(__FILE__)、行号(__LINE__)、断言失败的条件(#cond),以及当前函数的名称(__func__)。

  • #cond 是将 cond 转换为字符串的预处理器操作,这样可以打印出具体的条件表达式。

  • EVENT_ERR_ABORT_ 通常是一个预定义的常量,用于指示错误类型,
    fprintf(stderr, "%s:%d: Assertion %s failed in %s", __FILE__, __LINE__, #cond, __func__);

  • 在调用 event_errx 后,再次使用 fprintf 将相同的错误信息输出到标准错误输出(stderr)。这是为了防止用户自定义的错误处理程序可能试图返回控制权,确保错误信息一定会被输出。
    最后,调用 abort() 函数立即终止程序的执行。abort() 会导致程序异常退出,并生成一个核心转储(如果系统配置允许)


void event_errx(int eval, const char *fmt, ...)
{
	va_list ap;
	// 初始化可变参数列表
	va_start(ap, fmt);
	// 使用可变参数列表将格式化的错误信息输出到日志
	event_logv_(EVENT_LOG_ERR, NULL, fmt, ap);
	va_end(ap);
	// 结束可变参数处理
	// 退出程序并返回指定的错误码
	event_exit(eval);
}

该函数是可变参函数,相关注解见: [[可变参数]]

void

event_logv_(int severity, const char *errstr, const char *fmt, va_list ap)

{

    char buf[1024];

    size_t len;

  

    if (severity == EVENT_LOG_DEBUG && !event_debug_get_logging_mask_())

        return;

  

    if (fmt != NULL)

        evutil_vsnprintf(buf, sizeof(buf), fmt, ap);

    else

        buf[0] = '\0';

  

    if (errstr) {

        len = strlen(buf);

        if (len < sizeof(buf) - 3) {

            evutil_snprintf(buf + len, sizeof(buf) - len, ": %s", errstr);

        }

    }

  

    event_log(severity, buf);

}

EVBASE_ACQUIRE_LOCK N_ACTIVE_CALLBACKS

/** Lock an event_base, if it is set up for locking.  Acquires the lock
    in the base structure whose field is named 'lockvar'. */
#define EVBASE_ACQUIRE_LOCK(base, lockvar) do {				\
		EVLOCK_LOCK((base)->lockvar, 0);			\
	} while (0)


#define N_ACTIVE_CALLBACKS(base)					\
	((base)->event_count_active) //最大事件数量

/** Largest number of priorities that Libevent can support. */
#define EVENT_MAX_PRIORITIES 256
  /**

Set the number of different event priorities

By default Libevent schedules all active events with the same priority.

However, some time it is desirable to process some events with a higher

priority than others.  For that reason, Libevent supports strict priority

queues.  Active events with a lower priority are always processed before

events with a higher priority.

The number of different priorities can be set initially with the

event_base_priority_init() function.  This function should be called

before the first call to event_base_dispatch().  The

event_priority_set() function can be used to assign a priority to an

event.  By default, Libevent assigns the middle priority to all events

unless their priority is explicitly set.

Note that urgent-priority events can starve less-urgent events: after

running all urgent-priority callbacks, Libevent checks for more urgent

events again, before running less-urgent events.  Less-urgent events

will not have their callbacks run until there are no events more urgent

than them that want to be active.

@param eb the event_base structure returned by event_base_new()

@param npriorities the maximum number of priorities

@return 0 if successful, or -1 if an error occurred

@see event_priority_set()

TAILQ_ENTRY

//通过使用 TAILQ_ENTRY 宏,可以为指定的数据类型创建一个双向链表的入口和出口结构体,方便在链表中进行插入、删除和遍历等操作。
#define	_TAILQ_ENTRY(type, qual)					\
struct {								\
	qual type *tqe_next;		/* next element */		\
	qual type *qual *tqe_prev;	/* address of previous next element */\
}
#define TAILQ_ENTRY(type)	_TAILQ_ENTRY(struct type,)

qual 用于指定链表结构体成员的修饰符(它可以是 constvolatile 或其他限定符。)

  • tqe_next:指向链表中下一个元素的指针。

  • tqe_prev:指向链表中上一个元素的指针的地址。这里使用了一个指向指针的指针,即二级指针,用于在删除元素时修改前一个元素的 tqe_next 指针。

TAILQ_HEAD

#define TAILQ_HEAD(name, type)          \
struct name {                          \
    struct type *tqh_first;            /* 指向链表的第一个元素 */ \
    struct type **tqh_last;            /* 指向链表的最后一个元素的指针的指针 */ \
}

TAILQ_HEAD 是用于定义双向链表头结构的宏,使得管理链表的操作更加简单

  • tqh_first: 指向链表的第一个元素。对于空链表,它是 NULL

  • tqh_last: 指向链表的最后一个元素的指针的指针。在链表的最后一个元素中,tqh_last 指向链表中最后一个元素的指针(也就是指向该元素的指针的指针)。对于空链表,它指向 &tqh_first,即链表头结构中的 tqh_first

EVBASE_NEED_NOTIFY

/** Return true iff we need to notify the base's main thread about changes to

 * its state, because it's currently running the main loop in another

 * thread. Requires lock. */

#define EVBASE_NEED_NOTIFY(base)             \

    (evthread_id_fn_ != NULL &&          \

        (base)->running_loop &&          \

        (base)->th_owner_id != evthread_id_fn_())
  • evthread_id_fn_: 一个函数指针,用于获取当前线程的 ID。它用于确定事件循环是否在另一个线程中运行。

  • (base)->running_loop: 表示事件基础是否正在运行主事件循环。如果为 true,表示主循环正在运行中。

  • (base)->th_owner_id: 存储主事件循环线程的 ID。这个 ID 是在事件循环开始时设置的。

  • evthread_id_fn_(): 调用 evthread_id_fn_ 函数来获取当前线程的 ID。


  • evthread_id_fn_ != NULL: 确保线程 ID 函数指针有效,这意味着线程 ID 函数已经设置并可用。

  • (base)->running_loop: 确保事件循环确实在运行中。

  • (base)->th_owner_id != evthread_id_fn_(): 确保当前线程的 ID 与事件循环主线程的 ID 不同,表明主循环在另一个线程中运行。


这个宏的作用是检查是否需要通知主线程关于状态的变化,因为事件基础的主线程可能在不同的线程中运行。如果条件满足(即事件循环在另一个线程中运行且当前线程不是主线程),则返回 true,表示需要通知主线程。否则返回 false

EVBASE_RELEASE_LOCK EVLOCK_UNLOCK

/** Unlock an event_base, if it is set up for locking. */

#define EVBASE_RELEASE_LOCK(base, lockvar) do {             \

        EVLOCK_UNLOCK((base)->lockvar, 0);          \

    } while (0)
/** Release a lock */

#define EVLOCK_UNLOCK(lockvar,mode)                 \

    do {                                \

        if (lockvar)                        \

            evthread_lock_fns_.unlock(mode, lockvar);   \

    } while (0)
  • lockvar: 具体的锁变量。这个变量是锁的实际对象,用于加锁和解锁。

  • mode: 解锁模式,这个参数通常用于指定解锁的方式,但在这段代码中它被设置为 0,具体模式取决于锁的实现。

  • evthread_lock_fns_.unlock: 这是一个函数指针,指向实际的解锁函数。evthread_lock_fns_ 是一个结构体,包含了各种锁操作的函数指针(例如加锁、解锁等)。

  • EVBASE_RELEASE_LOCK(base, lockvar): 这是一个高层次的宏,用于释放 event_base 的锁。它通过调用 EVLOCK_UNLOCK 实现具体的解锁操作。

  • EVLOCK_UNLOCK(lockvar, mode): 这是一个底层宏,实际执行解锁操作。它使用 evthread_lock_fns_.unlock 函数指针来解锁。mode 参数通常用于指定解锁的详细模式,但在这段代码中,它被设置为 0

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何选择数据库架构

选择合适的数据库架构是一个复杂的过程&#xff0c;它取决于多种因素&#xff0c;包括应用程序的需求、数据量的大小、并发访问量、数据一致性要求、预算以及技术团队的熟悉程度等。以下是一些关键的步骤和考虑因素&#xff0c;帮助你选择合适的数据库架构&#xff1a; 1. 分析…

JavaScript对象方法

对象方法 已经讨论过hasOwnProperty(),propertyIsEnumerable()和isPrototypeOf()三个方法。 以及静态函数&#xff0c;Object.create(),Object.getPrototypeOf()等。 toString()方法 无参数&#xff0c;返回一个表示调用这个方法的对象值的字符串。默认返回信息很少&#x…

基因组学的未来:DAP-seq技术如何塑造

在生物科学的探索之旅中&#xff0c;我们一直在寻找更高效、更精确的方法来揭示基因的秘密。今天&#xff0c;我们自豪地介绍一种革命性的技术——DAP-Seq&#xff0c;它正在改变我们对基因表达调控的理解。 什么是DAP-Seq&#xff1f; DAP-Seq&#xff0c;即DNA亲和纯化测序技…

DataWhale x南瓜书学习笔记 task04笔记

线性判别分析&#xff08;LDA&#xff09; 前提假设&#xff1a;各类样本的协方差矩阵相同且满秩LDA的思想&#xff1a;1.设法让训练样例集投影到一条直线上&#xff0c;2.同类样例的投影点尽可能接近&#xff0c;异类样例的投影点尽可能远离&#xff0c;3.在对新样本进行分类时…

C++语法—引用

引用变量 概念 简单理解就是对一个已存在的变量起别名&#xff0c;与那个已存在的变量共用一块内存空间。 用法&#xff1a;已存在变量的类型 & 引用变量名 &#xff08;引用实体&#xff09;已存在变量 int main() {int a 1;int& b a;return 0; }在上面这个示例…

Lab1:虚拟机kolla安装部署openstack,并创建实例

实验内容&#xff1a; 创建并配置虚拟机安装OpenStack创建镜像创建实例类型选择网络配置创建实例 1、选择一个适合你的系统的虚拟机管理软件&#xff1a; VirtualBox &#xff08;推荐&#xff09; VMWare 其他 2、下载 .iso 镜像文件 openstack S 版本 iso 链接&#xff1…

计算机视觉实战项目4(图像分类+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A*路径规划+单目测距与测速+行人车辆计数等)

往期热门项目回顾&#xff1a; 计算机视觉项目大集合 改进的yolo目标检测-测距测速 路径规划算法 图像去雨去雾目标检测测距项目 交通标志识别项目 yolo系列-重磅yolov9界面-最新的yolo 姿态识别-3d姿态识别 深度学习小白学习路线 AI健身教练-引体向上-俯卧撑计数…

网站设计中安全方面都需要有哪些考虑

网站设计中的安全性是一个多方面的问题&#xff0c;需要从多个角度进行考虑和实施。以下是一些关键的安全考虑因素&#xff1a; 数据加密&#xff1a; 使用SSL&#xff08;安全套接字层&#xff09;证书来建立加密连接&#xff0c;确保数据在传输过程中不被截获。定期更新SSL证…

保障电气安全的电气火灾监控系统主要组成有哪些?

电气火灾是什么&#xff1f; 电气火灾一般是指由于电气线路、用电设备、器具以及供配电设备出现故障性释放的热能&#xff1a;如高温、电弧、电火花以及非故障性释放的能量&#xff1b;如电热器具的炽热表面&#xff0c;在具备燃烧条件下引燃本体或其他可燃物而造成的火灾&…

动态规划入门题目->使用最小费用爬楼梯

1.题目&#xff1a; 2.解析&#xff1a; 做题模式&#xff1a; 步骤一&#xff1a;找状态转移方程 步骤二&#xff1a;初始化 步三&#xff1a;填表 步骤四&#xff1a;返回-> dp[n] dp[i]表示到达 i 位置最小花费 逻辑&#xff1a;要爬到楼顶先找到 i 位置 &#xff0c; 要…

如何在谷歌浏览器上玩大型多人在线游戏

在如今的数字时代&#xff0c;谷歌浏览器已经成为了许多人上网冲浪的首选工具。除了浏览网页、观看视频之外&#xff0c;你还可以在谷歌浏览器上畅玩各种大型多人在线游戏。本文将为你详细介绍如何在谷歌浏览器上玩大型多人在线游戏的步骤。 &#xff08;本文由https://chrome…

PTH原理 补丁+工具

顺着《域渗透攻防指南》4.9的总结记录下。 0x00 PTH简单说明 PTH在内网渗透中用于横向移动。由于NTLM && Kerberos都是采用用户密码的NTLM Hash&#xff0c;所以我们不需要非得拿用户明文口令&#xff0c;拿到hash一样可以。 拿到hash后&#xff0c;可以撞hash&…

【深度学习】03-神经网络01-4 神经网络的pytorch搭建和参数计算

# 计算模型参数,查看模型结构,我们要查看有多少参数&#xff0c;需要先安装包 pip install torchsummary import torch import torch.nn as nn from torchsummary import summary # 导入 summary 函数&#xff0c;用于计算模型参数和查看模型结构# 创建神经网络模型类 class Mo…

nginx+php+postgresql搭建漏洞靶场

经过我多番查找,最终得出一个结论,dvwa暂时不支持 postgresql 本文给大家提供一个思路,千万不要轻易模仿 更新系统包列表 首先,打开终端并更新你的系统包列表: sudo apt updatesudo apt upgrade -y安装必要的软件包 安装Nginx、PHP、PostgreSQL以及一些必要的PHP扩展:…

基于BeagleBone Black的网页LED控制功能(flask+gpiod)

目录 项目介绍硬件介绍项目设计开发环境功能实现控制LED外设构建Webserver 功能展示项目总结 &#x1f449; 【Funpack3-5】基于BeagleBone Black的网页LED控制功能 &#x1f449; Github: EmbeddedCamerata/BBB_led_flask_web_control 项目介绍 基于 BeagleBoard Black 开发板…

搜索引擎onesearch3实现解释和升级到Elasticsearch v8系列(四)-搜索

搜索 搜索内容比较多&#xff0c;onesearch分成两部分&#xff0c;第一部分&#xff0c;Query构建&#xff0c;其中包括搜索词设置&#xff0c;设置返回字段&#xff0c;filter&#xff0c;高亮&#xff1b;第二部分分页和排序。第一部分是映射引擎负责&#xff0c;映射通用表…

HAL+M4学习记录_2

一、Boot配置 内存地址是固定的&#xff0c;代码从0x0000 0000开始&#xff0c;而数据从0x2000 0000开始&#xff0c;F4支持三种不同的boot模式 复位芯片时&#xff0c;在SYSCLK的第4个上升沿BOOT引脚值被锁存&#xff0c;STM32F407通过此时BOOT[1:0]引脚值选择Boot模式 BOOT1…

深度学习(入门)03:监督学习

1、监督学习简介 监督学习&#xff08;Supervised Learning&#xff09;是一种重要的机器学习方法&#xff0c;它的目标是通过“已知输入特征”来预测对应的标签。在监督学习中&#xff0c;每一个“特征-标签”对被称为样本&#xff08;example&#xff09;&#xff0c;这些样…

物联网行业中模组的AT指令详解以及使用

01 概述 AT 命令&#xff08;AT Commands&#xff09;最早是由发明拨号调制解调器&#xff08;MODEM&#xff09;的贺氏公司&#xff08;Hayes&#xff09;为了控制 MODEM 而发明的控制协议。后来随着网络带宽的升级&#xff0c;速度很低的拨号 MODEM 基本退出一般使用市场&am…

【含文档】基于Springboot+Vue的高校师资管理系统(含源码+数据库+lw)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统定…