los_sortlink.c 10.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
/*
 * 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"
38
/// 排序链表初始化
39 40
UINT32 OsSortLinkInit(SortLinkAttribute *sortLinkHeader)
{
41 42
    LOS_ListInit(&sortLinkHeader->sortLink);//初始化双向链表
    sortLinkHeader->nodeNum = 0;//nodeNum背后的含义是记录需要CPU工作的数量
43 44 45
    return LOS_OK;
}

46 47 48 49 50 51 52 53 54
/*!
 * @brief OsAddNode2SortLink 向链表中插入结点,并按时间顺序排列	
 *
 * @param sortLinkHeader 被插入的链表	
 * @param sortList	要插入的结点
 * @return	
 *
 * @see
 */
55 56
STATIC INLINE VOID OsAddNode2SortLink(SortLinkAttribute *sortLinkHeader, SortLinkList *sortList)
{
57
    LOS_DL_LIST *head = (LOS_DL_LIST *)&sortLinkHeader->sortLink; //获取双向链表 
58

59 60 61
    if (LOS_ListEmpty(head)) { //空链表,直接插入
        LOS_ListHeadInsert(head, &sortList->sortLinkNode);//插入结点
        sortLinkHeader->nodeNum++;//CPU的工作量增加了
62 63
        return;
    }
64
	//链表不为空时,插入分三种情况, responseTime 大于,等于,小于的处理
65
    SortLinkList *listSorted = LOS_DL_LIST_ENTRY(head->pstNext, SortLinkList, sortLinkNode);
66 67 68 69 70 71
    if (listSorted->responseTime > sortList->responseTime) {//如果要插入的节点 responseTime 最小 
        LOS_ListAdd(head, &sortList->sortLinkNode);//能跑进来说明是最小的,直接插入到第一的位置
        sortLinkHeader->nodeNum++;//CPU的工作量增加了
        return;//直接返回了
    } else if (listSorted->responseTime == sortList->responseTime) {//相等的情况
        LOS_ListAdd(head->pstNext, &sortList->sortLinkNode);//插到第二的位置
72 73
        sortLinkHeader->nodeNum++;
        return;
74
    }
75 76 77 78 79
	//处理大于链表中第一个responseTime的情况,需要遍历链表
    LOS_DL_LIST *prevNode = head->pstPrev;//注意这里用的前一个结点,也就是说前一个结点中的responseTime 是最大的
    do { // @note_good 这里写的有点妙,也是双向链表的魅力所在
        listSorted = LOS_DL_LIST_ENTRY(prevNode, SortLinkList, sortLinkNode);//一个个遍历,先比大的再比小的
        if (listSorted->responseTime <= sortList->responseTime) {//如果时间比你小,就插到后面
80 81 82 83 84
            LOS_ListAdd(prevNode, &sortList->sortLinkNode);
            sortLinkHeader->nodeNum++;
            break;
        }

85 86
        prevNode = prevNode->pstPrev;//再拿上一个更小的responseTime进行比较
    } while (1);//死循环
87
}
88
/// 从排序链表上摘除指定节点
89 90
VOID OsDeleteNodeSortLink(SortLinkAttribute *sortLinkHeader, SortLinkList *sortList)
{
91 92 93
    LOS_ListDelete(&sortList->sortLinkNode);//摘除工作量
    SET_SORTLIST_VALUE(sortList, OS_SORT_LINK_INVALID_TIME);//重置响应时间
    sortLinkHeader->nodeNum--;//cpu的工作量减少一份
94
}
95
/// 获取下一个结点的到期时间
96 97 98 99 100
STATIC INLINE UINT64 OsGetSortLinkNextExpireTime(SortLinkAttribute *sortHeader, UINT64 startTime)
{
    LOS_DL_LIST *head = &sortHeader->sortLink;
    LOS_DL_LIST *list = head->pstNext;

101
    if (LOS_ListEmpty(head)) {//链表为空
102
        return OS_SCHED_MAX_RESPONSE_TIME - OS_TICK_RESPONSE_PRECISION;
103 104
    }

105 106
    SortLinkList *listSorted = LOS_DL_LIST_ENTRY(list, SortLinkList, sortLinkNode);//获取结点实体
    if (listSorted->responseTime <= (startTime + OS_TICK_RESPONSE_PRECISION)) { //没看明白 @note_thinking 
107
        return startTime + OS_TICK_RESPONSE_PRECISION;
108 109
    }

110
    return listSorted->responseTime;
111
}
112
/// 根据函数的具体实现,这个函数应该是找出最空闲的CPU, 函数的实现有待优化, @note_thinking 
鸿蒙内核源码分析's avatar
鸿蒙内核源码分析 已提交
113
STATIC Percpu *OsFindIdleCpu(UINT16 *idleCpuID)
114
{
115
    Percpu *idleCpu = OsPercpuGetByID(0); //获取0号CPU,0号CPU也可称主核
鸿蒙内核源码分析's avatar
鸿蒙内核源码分析 已提交
116
    *idleCpuID = 0;
117

118
#ifdef LOSCFG_KERNEL_SMP //多核情况下
119
    UINT16 cpuID = 1;
120 121
    UINT32 nodeNum = idleCpu->taskSortLink.nodeNum + idleCpu->swtmrSortLink.nodeNum; //获取还未跑完的工作数量
	//cpu执行两种工作: 1.普通任务 2.软件定时器
122
    do {
123 124 125 126 127
        Percpu *cpu = OsPercpuGetByID(cpuID); //一个个cpu遍历
        UINT32 temp = cpu->taskSortLink.nodeNum + cpu->swtmrSortLink.nodeNum;//获取cpu的工作量
        if (nodeNum > temp) {//对工作量比较
            idleCpu = cpu;//取工作量最小的cpu实体
            *idleCpuID = cpuID;//获取cpu id
128 129
        }

130
        cpuID++;//下一个cpu id 
131 132 133 134 135
    } while (cpuID < LOSCFG_KERNEL_CORE_NUM);
#endif

    return idleCpu;
}
136
/// 向cpu的排序链表上添加指定节点
137 138 139 140 141 142 143 144
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;

145 146
    if (OS_SCHEDULER_ACTIVE) {//当前CPU正在调度
        cpu = OsFindIdleCpu(&idleCpu);//找一个最空闲的CPU
147
    } else {
148
        idleCpu = ArchCurrCpuid();//使用当前cpu
149 150 151
        cpu = OsPercpuGet();
    }

152 153
    if (type == OS_SORT_LINK_TASK) {//任务类型
        sortLinkHeader = &cpu->taskSortLink; //获取任务链表
154
        spinLock = &cpu->taskSortLinkSpin;
155 156
    } else if (type == OS_SORT_LINK_SWTMR) {//软件定时器类型
        sortLinkHeader = &cpu->swtmrSortLink;//获取软件定时器链表
157 158 159 160 161 162
        spinLock = &cpu->swtmrSortLinkSpin;
    } else {
        LOS_Panic("Sort link type error : %u\n", type);
    }

    LOS_SpinLockSave(spinLock, &intSave);
163 164
    SET_SORTLIST_VALUE(node, startTime + (UINT64)waitTicks * OS_CYCLE_PER_TICK);//设置节点响应时间
    OsAddNode2SortLink(sortLinkHeader, node);//插入节点
165
#ifdef LOSCFG_KERNEL_SMP
166
    node->cpuid = idleCpu;
167 168
    if (idleCpu != ArchCurrCpuid()) { //如果插入的链表不是当前CPU的链表
        LOS_MpSchedule(CPUID_TO_AFFI_MASK(idleCpu));//核间中断,对该CPU发生一次调度申请
169 170 171 172
    }
#endif
    LOS_SpinUnlockRestore(spinLock, intSave);
}
173
/// 从cpu的排序链表上摘除指定节点
174 175 176
VOID OsDeleteSortLink(SortLinkList *node, SortLinkType type)
{
    UINT32 intSave;
177
#ifdef LOSCFG_KERNEL_SMP
178
    Percpu *cpu = OsPercpuGetByID(node->cpuid);//获取CPU
179 180 181 182 183 184
#else
    Percpu *cpu = OsPercpuGetByID(0);
#endif

    SPIN_LOCK_S *spinLock = NULL;
    SortLinkAttribute *sortLinkHeader = NULL;
185 186
    if (type == OS_SORT_LINK_TASK) {//当为任务时
        sortLinkHeader = &cpu->taskSortLink;//获取该CPU的任务链表
187 188
        spinLock = &cpu->taskSortLinkSpin;
    } else if (type == OS_SORT_LINK_SWTMR) {
189
        sortLinkHeader = &cpu->swtmrSortLink;//获取该CPU的定时器链表
190 191 192 193 194 195 196
        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) {
197
        OsDeleteNodeSortLink(sortLinkHeader, node);//从CPU的执行链表上摘除
198 199 200 201
    }
    LOS_SpinUnlockRestore(spinLock, intSave);
}

202 203 204 205 206 207 208 209
/*!
 * @brief OsGetNextExpireTime 获取下一个超时时间	
 *
 * @param startTime	
 * @return	
 *
 * @see
 */
210 211 212
UINT64 OsGetNextExpireTime(UINT64 startTime)
{
    UINT32 intSave;
213
    Percpu *cpu = OsPercpuGet();//获取当前CPU
214 215 216 217
    SortLinkAttribute *taskHeader = &cpu->taskSortLink;
    SortLinkAttribute *swtmrHeader = &cpu->swtmrSortLink;

    LOS_SpinLockSave(&cpu->taskSortLinkSpin, &intSave);
218
    UINT64 taskExpirTime = OsGetSortLinkNextExpireTime(taskHeader, startTime);//拿到下一个到期时间,注意此处拿到的一定是最短的时间
219 220 221 222 223 224
    LOS_SpinUnlockRestore(&cpu->taskSortLinkSpin, intSave);

    LOS_SpinLockSave(&cpu->swtmrSortLinkSpin, &intSave);
    UINT64 swtmrExpirTime = OsGetSortLinkNextExpireTime(swtmrHeader, startTime);
    LOS_SpinUnlockRestore(&cpu->swtmrSortLinkSpin, intSave);

225
    return (taskExpirTime < swtmrExpirTime) ? taskExpirTime : swtmrExpirTime;//比较返回更短的那个.
226 227
}

228 229 230 231 232 233 234 235
/*!
 * @brief OsSortLinkGetTargetExpireTime	
 * 返回离触发目标时间的tick数
 * @param targetSortList	
 * @return	
 *
 * @see
 */
236 237
UINT32 OsSortLinkGetTargetExpireTime(const SortLinkList *targetSortList)
{
238
    UINT64 currTimes = OsGetCurrSchedTimeCycle();
239 240 241 242
    if (currTimes >= targetSortList->responseTime) {
        return 0;
    }

243
    return (UINT32)(targetSortList->responseTime - currTimes) / OS_CYCLE_PER_TICK;//响应时间减去当前时间置算出剩余tick数
244 245 246 247 248 249 250 251 252 253 254 255 256 257
}

UINT32 OsSortLinkGetNextExpireTime(const SortLinkAttribute *sortLinkHeader)
{
    LOS_DL_LIST *head = (LOS_DL_LIST *)&sortLinkHeader->sortLink;

    if (LOS_ListEmpty(head)) {
        return 0;
    }

    SortLinkList *listSorted = LOS_DL_LIST_ENTRY(head->pstNext, SortLinkList, sortLinkNode);
    return OsSortLinkGetTargetExpireTime(listSorted);
}