liteOS中双向循环链表的一些设计思想

基于华为LiteOS和NB-IoT的智慧楼宇消防系统 该项目是一个基于华为LiteOS的智慧楼宇消防系统,主要技术包含传感器,LiteOS, NB-IoT, 2G, 华为云等。基于小熊派智慧烟感案例进行开发。 阅读详情
1. 问题提出

看liteOS的源码,发现这些伙计们的水平还是高的。对于一个双向链表,一般我们的写法都是:

typedef struct Node {
	int data;
	struct Node *prev;
	struct Node *next;
} NODE

但是这就诞生了一个问题,节点Node中的数据类型是int时我们定义了一个链表类型NODE0,如果是float data又定义了一种链表类型NODE1,或者有多个业务变量时我们又定义了NODE2,这时候如果我们想写一个链表遍历函数,希望能够对所有的链表适用,怎么办呢?使用C++也许容易解决这个问题,模板嘛;但是C语言怎么办呢?

2. liteOS解决思路

liteOS提供了解决思路,把链表相关的单独剥离出来,如下所示,链表节点中什么业务数据都没有,只有前项节点指针和后项节点指针,显然,这时针对链表结构体的遍历、插入等操作就变得简单而广泛适用。

typedef struct LOS_DL_LIST {
    struct LOS_DL_LIST *pstPrev; /**< Current node's pointer to the previous node */
    struct LOS_DL_LIST *pstNext; /**< Current node's pointer to the next node */
} LOS_DL_LIST;

让我们简单看一个插入节点函数,这很容易理解,不做解释了。

LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListAdd(LOS_DL_LIST *list, LOS_DL_LIST *node)
{
    node->pstNext = list->pstNext;
    node->pstPrev = list;
    list->pstNext->pstPrev = node;
    list->pstNext = node;
}

当需要定义业务结构体时,则需要把上面定义的双向链表结构体作为成员变量,举个例子,下面是互斥锁结构体LosMuxCB定义,其中包含双向链表LOS_DL_LIST muxList作为成员变量:

typedef struct {
    LOS_DL_LIST muxList; /** 互斥锁的双向链表*/
    LosTaskCB *owner; /** 当前持有锁的任务TCB */
    UINT16 muxCount; /** 持有互斥锁的次数 */
    UINT8 muxStat; /** 互斥锁状态OS_MUX_UNUSED, OS_MUX_USED */
    UINT32 muxId; /** 互斥锁handler ID*/
} LosMuxCB;

在这里插入图片描述
新的问题就来了,虽然遍历、插入双向链表很容易了,但是我们在使用的时候肯定是对业务结构体进行遍历的啊,如何从链表遍历过渡到业务结构体的遍历呢?
问题的关键是计算出在一个业务结构体中,链表节点的地址相对于业务结构体起始地址的偏移,得到该偏移,我们就可以得到业务结构体指针,从而完成遍历。
业务结构体类型名称type、其中的双向链表成员变量名称member,下面这个宏定义就巧妙实现了求解链表节点地址在一个业务结构体中的地址偏移;(type *)0->member这一骚操作,很好,很喜欢。

#define LOS_OFF_SET_OF(type, member) ((UINTPTR)&((type *)0)->member)

下面这个宏定义更进一步,求出了业务结构体的实际内存地址,其中item是双向链表的实际内存地址。

#define LOS_DL_LIST_ENTRY(item, type, member) \
    ((type *)(VOID *)((CHAR *)(item) - LOS_OFF_SET_OF(type, member)))

再进一步,让我们开始愉快地遍历业务结构体吧,下面宏定义中,item代表逐个遍历的业务结构体地址,list代表双向链表指针,type和member同上。

#define LOS_DL_LIST_FOR_EACH_ENTRY(item, list, type, member)             \
    for (item = LOS_DL_LIST_ENTRY((list)->pstNext, type, member);        \
         &(item)->member != (list);                                      \
         item = LOS_DL_LIST_ENTRY((item)->member.pstNext, type, member))

到此,liteOS通过实现上述的宏定义/函数,实现了一套链表函数适用于所有的业务结构体,在C语言中写出了C++的风采,值得参考。

3. 参考
  1. liteOS源码:https://gitee.com/LiteOS/LiteOS/blob/master/kernel/include/los_list.h
  2. LiteOS内核源码分析系列一 盘点那些重要的数据结构 (1):https://bbs.huaweicloud.com/blogs/244926
【鸿蒙内核分析】LiteOS-M内核源码分析系列: 数据结构-双向循环链表 第二个入参是要遍历的双向链表的起始节点,第三个入参是要获取的结构体类型名称,第四个入参是该结构体中的双向链表成员变量的名称。在链表的应用场景上,业务结构体包含双向链表作为成员,当知道双向链表成员变量的内存地址和相对于业务结构体的偏移时,就可以进一步获取业务结构体的内存地址,具体见下面。遍历双向链表,将每次循环获取的链表节点保存在第一个入参中,第二个入参是要遍历的双向链表的起始节点。如果双向链表的前驱/后继节点均为自身,只有一个链节点,没有挂载业务结构体的链表节点,称该链表为空链表。从所在的双向链表中删除。 阅读详情

相关推荐

【鸿蒙内核分析】LiteOS-M内核源码分析:数据结构-任务就绪队列

在文件中定义了和任务就绪队列相关的主要变量。其中⑴表示任务就绪队列,是一个双向链表数组,后文初始化该数组时会将数组长度设置为⑷处定义的;⑵表示优先级位图,标识了任务就绪队列中已挂载的就绪任务所在的优先级;⑶表示优先级为0的比特位;⑷表示任务就绪队列支持的优先级个数32,所以鸿蒙轻内核优先级的取值范围为0-31,数值越小优先级越大。优先级位图的bit位和优先级的关系为,优先级数组包含了个数组元素,每个数组元素都是一个双向链表,同一优先级的处于就绪状态的所有任务都会挂载到对应优先级的双向链表中。

2401_88547687的博客 911

LIST_ENTRY(item, type, member)详解

LIST_ENTRY(item, type, member)详解

j13879847881的博客 629

【鸿蒙内核分析】LiteOS-M内核源码分析:互斥锁Mutex

在文件定义的互斥锁控制块结构体LosMuxCB,源代码如下,结构体成员的解释见注释部分。/**< 互斥锁状态:OS_MUX_UNUSED, OS_MUX_USED *//**< 锁被持有的次数 *//**< 互斥锁Id *//**< 互斥锁双向链表 *//**< 当前持有锁的任务 *//**< 当前持有锁的任务的优先级,为避免优先级翻转,可能会更改任务的优先级,此时有备份的作用 */} LosMuxCB;系统支持创建多少互斥锁是根据开发板情况使用宏定义的,互斥锁muxId是UINT32类型的,

2401_88547687的博客 850

基于STM32F103移植华为LiteOS一双向链表

华为LiteOS双链表之宿舍信息操作实验

morecrazylove的博客 669

【鸿蒙内核分析】LiteOS-M内核源码分析: 信号量Semaphore

在文件定义的信号量控制块结构体为LosSemCB,结构体源代码如下。信号量状态.semStat取值,其他成员变量的注释见注释部分。/**< 信号量状态 *//**< 可用的信号量数量 *//**< 可用的信号量最大数量 *//**< 信号量Id *//**< 阻塞在该信号量的任务链表 */} LosSemCB;系统支持创建多少信号量是根据开发板情况使用宏定义的,每一个信号量semId是UINT32类型的,取值为,表示信号量池中各个的信号量的编号。

2401_88547687的博客 876

【鸿蒙内核分析】LiteOS-M内核源码分析:事件Event

在文件定义的事件控制块结构体为EVENT_CB_S,结构体源代码如下,结构体成员的解释见注释部分。/**< 事件ID,每一位标识一种事件类型 *//**< 读取事件的任务链表 */在读事件时,可以选择读取模式。读取模式由如下几个宏定义:所有事件():逻辑与,基于接口传入的事件类型掩码eventMask,只有这些事件都已经发生才能读取成功,否则该任务将阻塞等待或者返回错误码。任一事件():逻辑或,基于接口传入的事件类型掩码eventMask。

2401_88547687的博客 1088

华为LiteOS操作系统中的LOS_DL_LIST_ENTRY怎么理解?

一、引入介绍 在阅读华为LiteOS的源码过程中,经常可以看到LOS_DL_LIST_ENTRY这个东东,给它展开其实它就是这样的一个宏定义: #define LOS_DL_LIST_ENTRY(item, type, member) \ ((type *)(VOID *)((CHAR *)(item) - LOS_OFF_SET_OF(type, member))) 二、宏定义解读 首先,先告诉大家它的功能:返回item所在结构体的首地址,也就是这个结构体第一个成员的地址*。 再给大家解读下它的

weixin_46582567的博客 1258

【鸿蒙内核分析】LiteOS-M内核源码分析:信号量Semaphore

在文件定义的信号量控制块结构体为LosSemCB,结构体源代码如下。信号量状态.semStat取值,其他成员变量的注释见注释部分。/**< 信号量状态 *//**< 可用的信号量数量 *//**< 可用的信号量最大数量 *//**< 信号量Id *//**< 阻塞在该信号量的任务链表 */} LosSemCB;系统支持创建多少信号量是根据开发板情况使用宏定义的,每一个信号量semId是UINT32类型的,取值为,表示信号量池中各个的信号量的编号。

2401_88547687的博客 360

LiteOS:盘点那些重要的数据结构

摘要:本文会给读者介绍下LiteOS源码中常用的几个数据结构,包括: 双向循环链表LOS_DL_LIST,优先级队列Priority Queue,排序链表SortLinkList等。 在学习Huawei LiteOS源代码的时候,常常会遇到一些数据结构的使用。如果没有掌握这它们的用法,阅读LiteOS源代码的时候会很费解、很吃力。本文会给读者介绍下LiteOS源码中常用的几个数据结构,包括: 双向循环链表LOS_DL_LIST,优先级队列Priority Queue,排序链表SortLinkList等..

华为云官方博客 2191

【鸿蒙南向开发】OpenHarmony内核对象事件之源码详解

这份鸿蒙(HarmonyOS NEXT)文档包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。

HarmonyOS_666的博客 1216

【OpenHarmony】鸿蒙南向开发保姆级知识点汇总~

OpenHarmony的技术架构和设计使得它能够适应不同的设备和场景,无论是,OpenHarmony都能提供一致的用户体验和开发体验。这使得开发者能够更加高效地开发适用于多种设备的软件,同时也为用户提供了更加统一和流畅的使用体验。于是小编下面针对了不同阶段的一些知识点做了一个简单的整理,希望能够帮助到大家!

MNxiaona666的博客 3558

鸿蒙LiteOS-M学习笔记-数据结构(1)双向循环列表

1.1 双向循环列表 双向链表LOS_DL_LIST的源代码在utils\los_list.h双向链表头文件中,包含LOS_DL_LIST结构体定义、inline内联函数LOS_ListXXX,还有相关的函数宏定义LOS_DLLLIST_XXXX。 1.1.1双向链表结构体: 1.1.2初始化双向链表: 有两种方法,第一种,调用初始化函数: 第二种,使用宏定义 1.1.3判断空链表: 1.1.4插入双向链表节点: 方法一:使用LOS_ListAdd函数,往链表节点list所在的双向链表中插入一个链表

weixin_40684073的博客 1014

基于LiteOS的智慧农业案例实验分享

LiteOSLiteOS源码GitHub仓库链接:其源码一级目录结构如下:其内核包括任务管理、内存管理、时间管理、通信机制、中断管理、队列管理、事件管理、定时器等操作系统基础组件,可以单独运行。Huawei LiteOS是一个支持多任务的操作系统。在Huawei LiteOS中,一个任务表示一个线程。其任务是抢占式调度机制,同时支持时间片轮转调度方式。高优先级的任务可打断低优先级任务,低优先级任务必须在高优先级任务阻塞或结束后才能得到调度。创建任务示例:左右滑动查看全部代码>>>

嵌入式技术开发 915

【鸿蒙内核分析】LiteOS-A内核源码分析:数据结构-双向循环链表

在学习OpenHarmony鸿蒙轻内核源代码的时候,常常会遇到一些数据结构的使用。如果没有掌握它们的用法,会导致阅读源代码时很费解、很吃力。本文会给读者介绍源码中重要的数据结构,双向循环链表Doubly Linked List。在讲解时,会结合数据结构相关绘图,培养读者们的数据结构的平面想象能力,帮助更好的学习和理解这些数据结构的用法。

2401_88547687的博客 1027

DisplayPort信号通道深度解析:从物理层到协议栈

DisplayPort(DP)是一种面向高速串行通信的数字显示接口标准,其核心在于嵌入式时钟、自适应均衡与链路训练三位一体的物理层架构。不同于HDMI依赖独立时钟的TMDS方案,DP通过差分主链路(Main Link)承载编码数据流,以8b/10b或128b/132b编码实现高带宽与强鲁棒性。该技术价值体现在多速率自适应、误码恢复能力及对PCB布线与阻抗控制的严苛要求,广泛应用于8K显示、工业视觉、GPU直连等高性能场景。本文聚焦DP信号通道的管脚级实现、三层协议解耦(物理层/数据链路层/事务层)及链路训练

weixin_34214500的博客 253

AJ-Report开源数据大屏存在远程命令执行漏洞

该平台可以通过post方式在validationRules参数对应值中进行命令执行,可以获得服务器权限,登陆管理后台接管大屏。如果被攻击者利用,危害后果十分严重。

swordheart的博客 387

鸿蒙轻内核A核源码分析系列一 数据结构-双向循环链表

在学习鸿蒙轻内核源代码的时候,常常会遇到一些数据结构的使用。如果没有掌握它们的用法,会导致阅读源代码时很费解、很吃力。本文会给读者介绍源码中重要的数据结构,双向循环链表。在讲解时,会结合数据结构相关绘图,培养读者们的数据结构的平面想象能力,帮助更好的学习和理解这些数据结构的用法。本文中所涉及的源码,以内核为例,均可以在开源站点 https://gitee.com/openharmony/kernel_liteos_a 获取。

maniuT的博客 705

渗透测试实战—云渗透(AK/SK泄露)

渗透测试实战思路分享:getshell方法及横向移动方法,云安全(AK/SK泄露)

网安日记本的博客 4049

一文带你剖析LiteOS互斥锁Mutex源代码

摘要:多任务环境下会存在多个任务访问同一公共资源的场景,而有些公共资源是非共享的临界资源,只能被独占使用。LiteOS使用互斥锁来避免这种冲突,互斥锁是一种特殊的二值性信号量,用于实现对临界资源的独占式处理。

华为云官方博客 1647

Zabbix在Ubuntu 22.04上的性能优化与监控实战:从基础安装到高级配置

本文详细介绍了在Ubuntu 22.04系统上部署和优化Zabbix监控系统的完整流程,从基础安装到高级配置。内容包括MySQL数据库设置、Zabbix服务器与Web前端优化、性能调优策略以及实战监控场景应用,帮助用户构建高效的企业级监控解决方案。

sss66的博客 894

人形机器人五大核心零部件技术解析与国产化实况

人形机器人并非简单机械集成,而是物理、能量、感知、决策与执行五层系统毫秒级协同的复杂体。其性能瓶颈往往不在于整机算法,而深植于谐波减速器的刚度稳定性、无框力矩电机的功率密度与温升控制、六维力传感器的动态响应与温漂抑制、运动控制器的实时OS生态及灵巧手的多指协同精度等底层硬件能力。这些部件共同构成整机68.3%的成本,且国产化率差异显著——谐波减速器达72%,而高精度力矩传感器仍受制于日德厂商。本文聚焦‘谐波减速器’和‘六维力传感器’两大热词,从材料工艺、参数定义、失效模式到产线验证,揭示真正卡脖子的技术关卡

weixin_29065959的博客 406

鸿蒙LiteOS-M学习笔记-数据结构(2)任务就绪队列

1.2 任务就绪队列 在任务调度模块,就绪队列是个重要的数据结构。任务创建后即进入就绪态,并放入就绪队列。在鸿蒙轻内核中,就绪队列是一个双向循环链表数组,每个数组元素就是一个链表,相同优先级的任务放入同一个链表。 任务就绪队列Priority Queue主要供内部使用,用户进行业务开发时不涉及,所以并未对外提供接口。双向循环链表数组能够更加方便的支持任务基于优先级进行调度。任务就绪队列的核心代码在kernel\src\los_task.c文件中。 1.2.1 任务就绪队列的定义 (1)表示队列数量最多有3

weixin_40684073的博客 1010

用 SAML 2.0 Bearer Assertion 配置 ABAP OAuth 2.0 令牌交换

摘要: SAP系统集成中,身份跨系统传递是关键挑战。OAuth 2.0的SAML 2.0 Bearer Assertion grant机制通过SAML断言换取访问令牌,实现安全身份传递。配置核心在ABAP的SOAUTH2事务码,需绑定可信SAML身份提供商(IdP)并指定访问范围。实际应用中,需确保SSL加密传输,正确配置SAML IdP信任关系,并为OAuth客户端分配专用系统用户。常见问题包括证书不匹配、权限配置不当等,需分层控制权限边界以保障安全。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 835

聊聊LiteOS事件模块的结构体、初始化及常用操作

摘要:本文通过分析LiteOS事件模块的源码,深入掌握事件的使用。

华为云官方博客 1680

通过理解 sk_buff 深入掌握 Linux 内核自定义协议族的开发实现

在。

数字人生 458

【Spring Cloud Alibaba】Linux安装RocketMQ以及RocketMQ Dashboard可视化工具

在当今分布式架构的开发中,消息队列成为了一种常见的解决方案。RocketMQ是阿里巴巴开源的分布式消息中间件,具有高吞吐量、高可用性和强大的扩展性,因此在构建大规模、高可靠性的应用系统时备受推崇。而在使用RocketMQ时,为了更好地了解消息的流动和监控,RocketMQ Dashboard成为了一个不可或缺的可视化工具。本篇博客将带大家一步步在Linux系统中安装RocketMQ,并介绍如何配置和使用RocketMQ Dashboard。

编码人生 3382
上一篇: 内存管理01——链接脚本
下一篇: numba使用踩坑总结
隋边边
博客等级 码龄11年 304粉丝 91原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值