#打卡不停更#OpenHarmony轻量系统中内核资源主要管理方式 原创
背景
OpenHarmony轻量系统主要用于计算和存储等性能相对弱一点的系统,针对每种类型的数据一般都不支持生成大量实例,本文以互斥锁为例来探究其内核资源的主要管理方式。类似的内核资源还有信号量,消息队列,事件,定时器等。
模块使能和容量
互斥锁软件模块是编译可裁剪模块,其由编译配置宏LOSCFG_BASE_IPC_MUX负责开启。系统支持的互斥锁数目由编译配置宏LOSCFG_BASE_IPC_MUX_LIMIT负责设置。
数据保存方式
由于容量较小,采用数组这种最简单和最原始的数据保存方式,在系统初始化的时候申请数组内存。如下
g_allMux = (LosMuxCB *)LOS_MemAlloc(m_aucSysMem0, (LOSCFG_BASE_IPC_MUX_LIMIT * sizeof(LosMuxCB)));
数据访问方式
由于轻量系统的计算资源相对受限,因此需要在算法上斤斤计较。目前提供了ID方式(数组下标访问)和链表访问2种方式,如下进行详细说明。
通过ID访问
#define GET_MUX(muxid) (((LosMuxCB *)g_allMux) + (muxid)) //通过数组下标获取互斥锁描述符
//获取描述符
muxPended = GET_MUX(muxHandle);
通过空闲链表访问
系统中当前正在使用的互斥锁数目是动态变化的。由于采用了数组存储以及内存预留的策略,所以需要标记每个数组元素是当前正在使用的互斥锁,还是空闲的互斥锁。在获取一个空闲的互斥锁时,为了快速的获取到空闲锁(避免遍历数组), 当前的实现是将所有空闲状态的互斥锁链接成一个链表,称为空闲互斥锁链表。这样,只需要取链表首元素即可获取到一个空闲互斥锁。最终,在链表上的互斥锁为空闲互斥锁,不在链表上的互斥锁为正在使用的互斥锁。
//创建互斥锁时,从空闲链表取下空闲状态的互斥锁
unusedMux = LOS_DL_LIST_FIRST(&(g_unusedMuxList));
LOS_ListDelete(unusedMux);
//释放互斥锁时,将互斥锁放入空闲链表
LOS_ListAdd(&g_unusedMuxList, &muxDeleted->muxList);
系统初始化的时候会将所有的互斥锁设置成空闲互斥锁,并存入空闲链表,如下。
for (index = 0; index < LOSCFG_BASE_IPC_MUX_LIMIT; index++) {
muxNode = ((LosMuxCB *)g_allMux) + index;
muxNode->muxID = index;
muxNode->owner = (LosTaskCB *)NULL;
muxNode->muxStat = OS_MUX_UNUSED;
LOS_ListTailInsert(&g_unusedMuxList, &muxNode->muxList);
}
健壮性考虑
空闲状态双保险
除了通过判断是否在空闲链表上来判断描述符是否空闲以外,在结构体中也保存了是否空闲的状态,这样可以增加空闲状态判断的健壮性。如下
if (muxPended->muxStat == OS_MUX_UNUSED) {
return LOS_ERRNO_MUX_INVALID;
}
中断上下文保护
IPC相关的处理(互斥锁为其中的一种)不允许允许在中断上下文(只能允许在任务上下文)。原因是中断上下文不允许阻塞当前执行流程。
任务切换保护
在任务执行的上下文中(非中断上下文),当临时关闭任务切换功能后,也不允许执行IPC相关的逻辑,因为IPC操作有一定概率需要切换任务(而当前任务切换又关闭了),发生了矛盾。代码如下
if (g_losTaskLock) {
PRINT_ERR(“!!!LOS_ERRNO_MUX_PEND_IN_LOCK!!!\n”);
return LOS_ERRNO_MUX_PEND_IN_LOCK;
}
关键任务不允许切换
一些系统关键任务运行后,不允许执行IPC逻辑,比如软件定时器任务:其监控多个定时器的超时。假定其执行IPC逻辑导致任务等待某资源比较长的时间,会导致部分定时器定时功能失效(不准确)。代码如下
if (g_losTask.runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {
return LOS_ERRNO_MUX_PEND_IN_SYSTEM_TASK;
}
总结
轻量系统中内核资源多采用数组与空闲链表相结合的方式,既保证了较高的内存访问效率(数组访问以及不含遍历的链表操作), 同时数组还有缓存命中率高的优势。另外,数组和链表这2种基本的数据结构对应的代码操作简单,易阅读和维护。