/*
* Copyright ( c ) 2013 - 2019 Huawei Technologies Co . , Ltd . All rights reserved .
* Copyright ( c ) 2020 - 2021 Huawei Device Co . , Ltd . All rights reserved .
*
* Redistribution and use in source and binary forms , with or without modification ,
* are permitted provided that the following conditions are met :
*
* 1. Redistributions of source code must retain the above copyright notice , this list of
* conditions and the following disclaimer .
*
* 2. Redistributions in binary form must reproduce the above copyright notice , this list
* of conditions and the following disclaimer in the documentation and / or other materials
* provided with the distribution .
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* " AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO ,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL ,
* EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO ,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ;
* OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY ,
* WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR
* OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# include "los_sortlink_pri.h"
# include "los_memory.h"
# include "los_exc.h"
# include "los_percpu_pri.h"
# include "los_sched_pri.h"
# include "los_mp.h"
UINT32 OsSortLinkInit ( SortLinkAttribute * sortLinkHeader )
{
LOS_ListInit ( & sortLinkHeader - > sortLink ) ; // 初始化排序链表头
sortLinkHeader - > nodeNum = 0 ; // 初始化节点数量为0
return LOS_OK ;
}
STATIC INLINE VOID OsAddNode2SortLink ( SortLinkAttribute * sortLinkHeader , SortLinkList * sortList )
{
LOS_DL_LIST * head = ( LOS_DL_LIST * ) & sortLinkHeader - > sortLink ; // 获取排序链表头指针
if ( LOS_ListEmpty ( head ) ) { // 如果链表为空
LOS_ListHeadInsert ( head , & sortList - > sortLinkNode ) ; // 将节点插入链表头
sortLinkHeader - > nodeNum + + ; // 节点数量加1
return ;
}
SortLinkList * listSorted = LOS_DL_LIST_ENTRY ( head - > pstNext , SortLinkList , sortLinkNode ) ; // 获取链表中的第一个节点
if ( listSorted - > responseTime > sortList - > responseTime ) { // 如果插入节点的响应时间小于第一个节点的响应时间
LOS_ListAdd ( head , & sortList - > sortLinkNode ) ; // 将节点插入链表头之前
sortLinkHeader - > nodeNum + + ; // 节点数量加1
return ;
} else if ( listSorted - > responseTime = = sortList - > responseTime ) { // 如果插入节点的响应时间等于第一个节点的响应时间
LOS_ListAdd ( head - > pstNext , & sortList - > sortLinkNode ) ; // 将节点插入第一个节点之后
sortLinkHeader - > nodeNum + + ; // 节点数量加1
return ;
}
LOS_DL_LIST * prevNode = head - > pstPrev ; // 获取链表中的最后一个节点
do {
listSorted = LOS_DL_LIST_ENTRY ( prevNode , SortLinkList , sortLinkNode ) ; // 获取当前节点
if ( listSorted - > responseTime < = sortList - > responseTime ) { // 如果插入节点的响应时间小于等于当前节点的响应时间
LOS_ListAdd ( prevNode , & sortList - > sortLinkNode ) ; // 将节点插入当前节点之前
sortLinkHeader - > nodeNum + + ; // 节点数量加1
break ;
}
prevNode = prevNode - > pstPrev ; // 继续向前遍历
} while ( 1 ) ;
}
/*OsSortLinkInit函数用于初始化排序链表头。在函数中, 它调用LOS_ListInit函数初始化排序链表头, 并将节点数量设置为0, 然后返回LOS_OK。
OsAddNode2SortLink 函 数 用 于 将 节 点 插 入 排 序 链 表 中 。 在 函 数 中 , 首 先 获 取 排 序 链 表 头 指 针 。 然 后 , 如 果 链 表 为 空 , 将 节 点 插 入 链 表 头 , 并 增 加 节 点 数 量 ,
然 后 返 回 。 如 果 链 表 不 为 空 , 获 取 链 表 中 的 第 一 个 节 点 , 并 比 较 插 入 节 点 的 响 应 时 间 与 第 一 个 节 点 的 响 应 时 间 。 如 果 插 入 节 点 的 响 应 时 间 小 于 第 一 个 节 点 的
响 应 时 间 , 将 节 点 插 入 链 表 头 之 前 , 并 增 加 节 点 数 量 , 然 后 返 回 。 如 果 插 入 节 点 的 响 应 时 间 等 于 第 一 个 节 点 的 响 应 时 间 , 将 节 点 插 入 第 一 个 节 点 之 后 ,
并 增 加 节 点 数 量 , 然 后 返 回 。 如 果 插 入 节 点 的 响 应 时 间 大 于 第 一 个 节 点 的 响 应 时 间 , 获 取 链 表 中 的 最 后 一 个 节 点 , 并 从 链 表 尾 部 向 前 遍 历 。 在 遍 历 过 程 中 ,
如 果 插 入 节 点 的 响 应 时 间 小 于 等 于 当 前 节 点 的 响 应 时 间 , 将 节 点 插 入 当 前 节 点 之 前 , 并 增 加 节 点 数 量 , 然 后 退 出 循 环 。 最 后 , 返 回 。 */
VOID OsDeleteNodeSortLink ( SortLinkAttribute * sortLinkHeader , SortLinkList * sortList )
{
LOS_ListDelete ( & sortList - > sortLinkNode ) ; // 从排序链表中删除节点
SET_SORTLIST_VALUE ( sortList , OS_SORT_LINK_INVALID_TIME ) ; // 将节点的响应时间设置为无效值
sortLinkHeader - > nodeNum - - ; // 节点数量减1
}
STATIC INLINE UINT64 OsGetSortLinkNextExpireTime ( SortLinkAttribute * sortHeader , UINT64 startTime )
{
LOS_DL_LIST * head = & sortHeader - > sortLink ; // 获取排序链表头指针
LOS_DL_LIST * list = head - > pstNext ; // 获取链表中的第一个节点
if ( LOS_ListEmpty ( head ) ) { // 如果链表为空
return OS_SCHED_MAX_RESPONSE_TIME - OS_TICK_RESPONSE_PRECISION ; // 返回最大响应时间减去精度
}
SortLinkList * listSorted = LOS_DL_LIST_ENTRY ( list , SortLinkList , sortLinkNode ) ; // 获取第一个节点
if ( listSorted - > responseTime < = ( startTime + OS_TICK_RESPONSE_PRECISION ) ) { // 如果第一个节点的响应时间小于等于(开始时间加上精度)
return startTime + OS_TICK_RESPONSE_PRECISION ; // 返回开始时间加上精度
}
return listSorted - > responseTime ; // 返回第一个节点的响应时间
}
STATIC Percpu * OsFindIdleCpu ( UINT16 * idleCpuID )
{
Percpu * idleCpu = OsPercpuGetByID ( 0 ) ; // 获取CPU 0 的PerCPU结构体指针
* idleCpuID = 0 ; // 将空闲CPU的ID设置为0
/*OsDeleteNodeSortLink函数用于从排序链表中删除节点。在函数中, 它调用LOS_ListDelete函数删除节点, 并将节点的响应时间设置为无效值, 然后将节点数量减1。
OsGetSortLinkNextExpireTime 函 数 用 于 获 取 排 序 链 表 中 下 一 个 即 将 到 期 的 节 点 的 响 应 时 间 。 在 函 数 中 , 首 先 获 取 排 序 链 表 头 指 针 和 链 表 中 的 第 一 个 节 点 。
然 后 , 如 果 链 表 为 空 , 返 回 最 大 响 应 时 间 减 去 精 度 。 如 果 第 一 个 节 点 的 响 应 时 间 小 于 等 于 ( 开 始 时 间 加 上 精 度 ) , 返 回 开 始 时 间 加 上 精 度 。 否 则 , 返 回 第 一 个 节 点 的 响 应 时 间 。
OsFindIdleCpu 函 数 用 于 查 找 空 闲 的 CPU 。 在 函 数 中 , 它 通 过 调 用 OsPercpuGetByID 函 数 获 取 CPU 0 的 PerCPU 结 构 体 指 针 , 并 将 空 闲 CPU 的 ID 设 置 为 0 。 */
# ifdef LOSCFG_KERNEL_SMP
UINT16 cpuID = 1 ; // 初始化CPU ID为1
UINT32 nodeNum = idleCpu - > taskSortLink . nodeNum + idleCpu - > swtmrSortLink . nodeNum ; // 获取当前CPU的任务排序链表和软件定时器排序链表的节点数量之和
do {
Percpu * cpu = OsPercpuGetByID ( cpuID ) ; // 获取指定CPU的PerCPU结构体指针
UINT32 temp = cpu - > taskSortLink . nodeNum + cpu - > swtmrSortLink . nodeNum ; // 获取指定CPU的任务排序链表和软件定时器排序链表的节点数量之和
if ( nodeNum > temp ) { // 如果当前CPU的节点数量之和大于指定CPU的节点数量之和
idleCpu = cpu ; // 更新空闲CPU指针
* idleCpuID = cpuID ; // 更新空闲CPU的ID
}
cpuID + + ; // 继续遍历下一个CPU
} while ( cpuID < LOSCFG_KERNEL_CORE_NUM ) ; // 遍历完所有的CPU
# endif
return idleCpu ; // 返回空闲CPU的指针
}
VOID OsAdd2SortLink ( SortLinkList * node , UINT64 startTime , UINT32 waitTicks , SortLinkType type )
{
UINT32 intSave ;
Percpu * cpu = NULL ;
SortLinkAttribute * sortLinkHeader = NULL ;
SPIN_LOCK_S * spinLock = NULL ;
UINT16 idleCpu ;
if ( OS_SCHEDULER_ACTIVE ) { // 如果调度器处于活动状态
cpu = OsFindIdleCpu ( & idleCpu ) ; // 查找空闲的CPU
} else {
idleCpu = ArchCurrCpuid ( ) ; // 获取当前CPU的ID
cpu = OsPercpuGet ( ) ; // 获取当前CPU的PerCPU结构体指针
}
if ( type = = OS_SORT_LINK_TASK ) {
sortLinkHeader = & cpu - > taskSortLink ; // 获取任务排序链表头指针
spinLock = & cpu - > taskSortLinkSpin ; // 获取任务排序链表自旋锁
} else if ( type = = OS_SORT_LINK_SWTMR ) {
sortLinkHeader = & cpu - > swtmrSortLink ; // 获取软件定时器排序链表头指针
spinLock = & cpu - > swtmrSortLinkSpin ; // 获取软件定时器排序链表自旋锁
} else {
LOS_Panic ( " Sort link type error : %u \n " , type ) ; // 报错,排序链表类型错误
}
LOS_SpinLockSave ( spinLock , & intSave ) ; // 保存自旋锁状态并禁止中断
SET_SORTLIST_VALUE ( node , startTime + ( UINT64 ) waitTicks * OS_CYCLE_PER_TICK ) ; // 设置节点的响应时间
OsAddNode2SortLink ( sortLinkHeader , node ) ; // 将节点插入排序链表中
# ifdef LOSCFG_KERNEL_SMP
node - > cpuid = idleCpu ; // 设置节点的CPU ID为空闲CPU的ID
if ( idleCpu ! = ArchCurrCpuid ( ) ) { // 如果空闲CPU的ID不等于当前CPU的ID
LOS_MpSchedule ( CPUID_TO_AFFI_MASK ( idleCpu ) ) ; // 调度空闲CPU执行任务
}
# endif
LOS_SpinUnlockRestore ( spinLock , intSave ) ; // 恢复自旋锁状态并允许中断
}
VOID OsDeleteSortLink ( SortLinkList * node , SortLinkType type )
{
UINT32 intSave ;
# ifdef LOSCFG_KERNEL_SMP
Percpu * cpu = OsPercpuGetByID ( node - > cpuid ) ; // 获取节点所在CPU的PerCPU结构体指针
# else
Percpu * cpu = OsPercpuGetByID ( 0 ) ; // 获取CPU 0 的PerCPU结构体指针
# endif
/*OsAdd2SortLink函数用于将节点插入排序链表中。在函数中, 首先根据调度器的活动状态选择空闲的CPU。
如 果 调 度 器 处 于 活 动 状 态 , 调 用 OsFindIdleCpu 函 数 查 找 空 闲 的 CPU ; 否 则 , 获 取 当 前 CPU 的 ID ,
并 通 过 OsPercpuGet 函 数 获 取 当 前 CPU 的 PerCPU 结 构 体 指 针 。 然 后 , 根 据 排 序 链 表 类 型 选 择 相 应 的 排 序 链 表 头 指 针 和 自 旋 锁 。
接 下 来 , 保 存 自 旋 锁 状 态 并 禁 止 中 断 , 设 置 节 点 的 响 应 时 间 , 将 节 点 插 入 排 序 链 表 中 , 根 据 SMP 配 置 设 置 节 点 的 CPU ID ,
并 如 果 空 闲 CPU 的 ID 不 等 于 当 前 CPU 的 ID , 调 度 空 闲 CPU 执 行 任 务 。 最 后 , 恢 复 自 旋 锁 状 态 并 允 许 中 断 。
OsDeleteSortLink 函 数 用 于 从 排 序 链 表 中 删 除 节 点 。 在 函 数 中 , 首 先 保 存 自 旋 锁 状 态 并 禁 止 中 断 。 如 果 SMP 配 置 开 启 ,
根 据 节 点 的 CPU ID 获 取 节 点 所 在 CPU 的 PerCPU 结 构 体 指 针 ; 否 则 , 获 取 CPU 0 的 PerCPU 结 构 体 指 针 。 */
SPIN_LOCK_S * spinLock = NULL ;
SortLinkAttribute * sortLinkHeader = NULL ;
if ( type = = OS_SORT_LINK_TASK ) {
sortLinkHeader = & cpu - > taskSortLink ; // 获取任务排序链表头指针
spinLock = & cpu - > taskSortLinkSpin ; // 获取任务排序链表自旋锁
} else if ( type = = OS_SORT_LINK_SWTMR ) {
sortLinkHeader = & cpu - > swtmrSortLink ; // 获取软件定时器排序链表头指针
spinLock = & cpu - > swtmrSortLinkSpin ; // 获取软件定时器排序链表自旋锁
} else {
LOS_Panic ( " Sort link type error : %u \n " , type ) ; // 报错,排序链表类型错误
}
LOS_SpinLockSave ( spinLock , & intSave ) ; // 保存自旋锁状态并禁止中断
if ( node - > responseTime ! = OS_SORT_LINK_INVALID_TIME ) { // 如果节点的响应时间不为无效时间
OsDeleteNodeSortLink ( sortLinkHeader , node ) ; // 从排序链表中删除节点
}
LOS_SpinUnlockRestore ( spinLock , intSave ) ; // 恢复自旋锁状态并允许中断
}
UINT64 OsGetNextExpireTime ( UINT64 startTime )
{
UINT32 intSave ;
Percpu * cpu = OsPercpuGet ( ) ; // 获取当前CPU的PerCPU结构体指针
SortLinkAttribute * taskHeader = & cpu - > taskSortLink ; // 获取任务排序链表头指针
SortLinkAttribute * swtmrHeader = & cpu - > swtmrSortLink ; // 获取软件定时器排序链表头指针
LOS_SpinLockSave ( & cpu - > taskSortLinkSpin , & intSave ) ; // 保存任务排序链表自旋锁状态并禁止中断
UINT64 taskExpirTime = OsGetSortLinkNextExpireTime ( taskHeader , startTime ) ; // 获取任务排序链表中下一个过期时间
LOS_SpinUnlockRestore ( & cpu - > taskSortLinkSpin , intSave ) ; // 恢复任务排序链表自旋锁状态并允许中断
LOS_SpinLockSave ( & cpu - > swtmrSortLinkSpin , & intSave ) ; // 保存软件定时器排序链表自旋锁状态并禁止中断
UINT64 swtmrExpirTime = OsGetSortLinkNextExpireTime ( swtmrHeader , startTime ) ; // 获取软件定时器排序链表中下一个过期时间
LOS_SpinUnlockRestore ( & cpu - > swtmrSortLinkSpin , intSave ) ; // 恢复软件定时器排序链表自旋锁状态并允许中断
return ( taskExpirTime < swtmrExpirTime ) ? taskExpirTime : swtmrExpirTime ; // 返回较小的过期时间
}
UINT32 OsSortLinkGetTargetExpireTime ( const SortLinkList * targetSortList )
{
UINT64 currTimes = OsGetCurrSchedTimeCycle ( ) ; // 获取当前调度时间
if ( currTimes > = targetSortList - > responseTime ) { // 如果当前时间大于等于目标排序链表节点的响应时间
return 0 ; // 返回0, 表示已经过期
}
return ( UINT32 ) ( targetSortList - > responseTime - currTimes ) / OS_CYCLE_PER_TICK ; // 计算剩余的滴答数
}
UINT32 OsSortLinkGetNextExpireTime ( const SortLinkAttribute * sortLinkHeader )
{
LOS_DL_LIST * head = ( LOS_DL_LIST * ) & sortLinkHeader - > sortLink ; // 获取排序链表头节点
if ( LOS_ListEmpty ( head ) ) { // 如果排序链表为空
return 0 ; // 返回0, 表示没有过期时间
}
SortLinkList * listSorted = LOS_DL_LIST_ENTRY ( head - > pstNext , SortLinkList , sortLinkNode ) ; // 获取排序链表中的第一个节点
return OsSortLinkGetTargetExpireTime ( listSorted ) ; // 获取目标排序链表节点的过期时间
}