|
|
|
@ -118,7 +118,256 @@ STATIC Percpu *OsFindIdleCpu(UINT16 *idleCpuID)
|
|
|
|
|
*idleCpuID = cpuID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpuID++;
|
|
|
|
|
cpuID++;/*
|
|
|
|
|
* 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); // 获取目标排序链表节点的过期时间
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} while (cpuID < LOSCFG_KERNEL_CORE_NUM);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|