• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3  * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this list of
9  *    conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12  *    of conditions and the following disclaimer in the documentation and/or other materials
13  *    provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16  *    to endorse or promote products derived from this software without specific prior written
17  *    permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include "los_sched_pri.h"
33 #include "los_hw_pri.h"
34 #include "los_task_pri.h"
35 #include "los_swtmr_pri.h"
36 #include "los_process_pri.h"
37 #include "los_arch_mmu.h"
38 #include "los_hook.h"
39 #ifdef LOSCFG_KERNEL_CPUP
40 #include "los_cpup_pri.h"
41 #endif
42 #include "los_hw_tick_pri.h"
43 #include "los_tick_pri.h"
44 #ifdef LOSCFG_BASE_CORE_TSK_MONITOR
45 #include "los_stackinfo_pri.h"
46 #endif
47 #include "los_mp.h"
48 #ifdef LOSCFG_SCHED_DEBUG
49 #include "los_stat_pri.h"
50 #endif
51 #include "los_pm_pri.h"
52 
53 #define OS_32BIT_MAX               0xFFFFFFFFUL
54 #define OS_SCHED_FIFO_TIMEOUT      0x7FFFFFFF
55 #define OS_PRIORITY_QUEUE_NUM      32
56 #define PRIQUEUE_PRIOR0_BIT        0x80000000U
57 #define OS_SCHED_TIME_SLICES_MIN   ((5000 * OS_SYS_NS_PER_US) / OS_NS_PER_CYCLE)  /* 5ms */
58 #define OS_SCHED_TIME_SLICES_MAX   ((LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT * OS_SYS_NS_PER_US) / OS_NS_PER_CYCLE)
59 #define OS_SCHED_TIME_SLICES_DIFF  (OS_SCHED_TIME_SLICES_MAX - OS_SCHED_TIME_SLICES_MIN)
60 #define OS_SCHED_READY_MAX         30
61 #define OS_TIME_SLICE_MIN          (INT32)((50 * OS_SYS_NS_PER_US) / OS_NS_PER_CYCLE) /* 50us */
62 
63 #define OS_TASK_STATUS_BLOCKED     (OS_TASK_STATUS_INIT | OS_TASK_STATUS_PENDING | \
64                                     OS_TASK_STATUS_DELAY | OS_TASK_STATUS_PEND_TIME)
65 
66 typedef struct {
67     LOS_DL_LIST priQueueList[OS_PRIORITY_QUEUE_NUM];
68     UINT32      readyTasks[OS_PRIORITY_QUEUE_NUM];
69     UINT32      queueBitmap;
70 } SchedQueue;
71 
72 typedef struct {
73     SchedQueue queueList[OS_PRIORITY_QUEUE_NUM];
74     UINT32     queueBitmap;
75 } Sched;
76 
77 SchedRunQue g_schedRunQue[LOSCFG_KERNEL_CORE_NUM];
78 STATIC Sched g_sched;
79 
80 #ifdef LOSCFG_SCHED_TICK_DEBUG
81 #define OS_SCHED_DEBUG_DATA_NUM  1000
82 typedef struct {
83     UINT32 tickResporeTime[OS_SCHED_DEBUG_DATA_NUM];
84     UINT32 index;
85     UINT32 setTickCount;
86     UINT64 oldResporeTime;
87 } SchedTickDebug;
88 STATIC SchedTickDebug *g_schedTickDebug = NULL;
89 
OsSchedDebugInit(VOID)90 STATIC UINT32 OsSchedDebugInit(VOID)
91 {
92     UINT32 size = sizeof(SchedTickDebug) * LOSCFG_KERNEL_CORE_NUM;
93     g_schedTickDebug = (SchedTickDebug *)LOS_MemAlloc(m_aucSysMem0, size);
94     if (g_schedTickDebug == NULL) {
95         return LOS_ERRNO_TSK_NO_MEMORY;
96     }
97 
98     (VOID)memset_s(g_schedTickDebug, size, 0, size);
99     return LOS_OK;
100 }
101 
OsSchedDebugRecordData(VOID)102 VOID OsSchedDebugRecordData(VOID)
103 {
104     SchedTickDebug *schedDebug = &g_schedTickDebug[ArchCurrCpuid()];
105     if (schedDebug->index < OS_SCHED_DEBUG_DATA_NUM) {
106         UINT64 currTime = OsGetCurrSchedTimeCycle();
107         schedDebug->tickResporeTime[schedDebug->index] = currTime - schedDebug->oldResporeTime;
108         schedDebug->oldResporeTime = currTime;
109         schedDebug->index++;
110     }
111 }
112 
OsSchedDebugGet(VOID)113 SchedTickDebug *OsSchedDebugGet(VOID)
114 {
115     return g_schedTickDebug;
116 }
117 
OsShellShowTickRespo(VOID)118 UINT32 OsShellShowTickRespo(VOID)
119 {
120     UINT32 intSave;
121     UINT16 cpu;
122     UINT64 allTime;
123 
124     UINT32 tickSize = sizeof(SchedTickDebug) * LOSCFG_KERNEL_CORE_NUM;
125     SchedTickDebug *schedDebug = (SchedTickDebug *)LOS_MemAlloc(m_aucSysMem1, tickSize);
126     if (schedDebug == NULL) {
127         return LOS_NOK;
128     }
129 
130     UINT32 sortLinkNum[LOSCFG_KERNEL_CORE_NUM];
131     SCHEDULER_LOCK(intSave);
132     (VOID)memcpy_s((CHAR *)schedDebug, tickSize, (CHAR *)OsSchedDebugGet(), tickSize);
133     (VOID)memset_s((CHAR *)OsSchedDebugGet(), tickSize, 0, tickSize);
134     for (cpu = 0; cpu < LOSCFG_KERNEL_CORE_NUM; cpu++) {
135         SchedRunQue *rq = OsSchedRunQueByID(cpu);
136         sortLinkNum[cpu] = OsGetSortLinkNodeNum(&rq->taskSortLink) + OsGetSortLinkNodeNum(&rq->swtmrSortLink);
137     }
138     SCHEDULER_UNLOCK(intSave);
139 
140     for (cpu = 0; cpu < LOSCFG_KERNEL_CORE_NUM; cpu++) {
141         SchedTickDebug *schedData = &schedDebug[cpu];
142         PRINTK("cpu : %u sched data num : %u set time count : %u SortMax : %u\n",
143                cpu, schedData->index, schedData->setTickCount, sortLinkNum[cpu]);
144         UINT32 *data = schedData->tickResporeTime;
145         allTime = 0;
146         for (UINT32 i = 1; i < schedData->index; i++) {
147             allTime += data[i];
148             UINT32 timeUs = (data[i] * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US;
149             PRINTK("     %u(%u)", timeUs, timeUs / OS_US_PER_TICK);
150             if ((i != 0) && ((i % 5) == 0)) { /* A row of 5 data */
151                 PRINTK("\n");
152             }
153         }
154 
155         allTime = (allTime * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US;
156         PRINTK("\nTick Indicates the average response period: %llu(us)\n", allTime / (schedData->index - 1));
157     }
158 
159     (VOID)LOS_MemFree(m_aucSysMem1, schedDebug);
160     return LOS_OK;
161 }
162 
163 #else
164 
OsShellShowTickRespo(VOID)165 UINT32 OsShellShowTickRespo(VOID)
166 {
167     return LOS_NOK;
168 }
169 #endif
170 
171 #ifdef LOSCFG_SCHED_DEBUG
SchedDataGet(LosTaskCB * taskCB,UINT64 * runTime,UINT64 * timeSlice,UINT64 * pendTime,UINT64 * schedWait)172 STATIC VOID SchedDataGet(LosTaskCB *taskCB, UINT64 *runTime, UINT64 *timeSlice, UINT64 *pendTime, UINT64 *schedWait)
173 {
174     if (taskCB->schedStat.switchCount >= 1) {
175         UINT64 averRunTime = taskCB->schedStat.runTime / taskCB->schedStat.switchCount;
176         *runTime = (averRunTime * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US;
177     }
178 
179     if (taskCB->schedStat.timeSliceCount > 1) {
180         UINT64 averTimeSlice = taskCB->schedStat.timeSliceTime / (taskCB->schedStat.timeSliceCount - 1);
181         *timeSlice = (averTimeSlice * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US;
182     }
183 
184     if (taskCB->schedStat.pendCount > 1) {
185         UINT64 averPendTime = taskCB->schedStat.pendTime / taskCB->schedStat.pendCount;
186         *pendTime = (averPendTime * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US;
187     }
188 
189     if (taskCB->schedStat.waitSchedCount > 0) {
190         UINT64 averSchedWait = taskCB->schedStat.waitSchedTime / taskCB->schedStat.waitSchedCount;
191         *schedWait = (averSchedWait * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US;
192     }
193 }
194 
OsShellShowSchedParam(VOID)195 UINT32 OsShellShowSchedParam(VOID)
196 {
197     UINT64 averRunTime;
198     UINT64 averTimeSlice;
199     UINT64 averSchedWait;
200     UINT64 averPendTime;
201     UINT32 intSave;
202     UINT32 size = g_taskMaxNum * sizeof(LosTaskCB);
203     LosTaskCB *taskCBArray = LOS_MemAlloc(m_aucSysMem1, size);
204     if (taskCBArray == NULL) {
205         return LOS_NOK;
206     }
207 
208     SCHEDULER_LOCK(intSave);
209     (VOID)memcpy_s(taskCBArray, size, g_taskCBArray, size);
210     SCHEDULER_UNLOCK(intSave);
211     PRINTK("  Tid    AverRunTime(us)    SwitchCount  AverTimeSlice(us)    TimeSliceCount  AverReadyWait(us)  "
212            "AverPendTime(us)  TaskName \n");
213     for (UINT32 tid = 0; tid < g_taskMaxNum; tid++) {
214         LosTaskCB *taskCB = taskCBArray + tid;
215         if (OsTaskIsUnused(taskCB)) {
216             continue;
217         }
218 
219         averRunTime = 0;
220         averTimeSlice = 0;
221         averPendTime = 0;
222         averSchedWait = 0;
223 
224         SchedDataGet(taskCB, &averRunTime, &averTimeSlice, &averPendTime, &averSchedWait);
225 
226         PRINTK("%5u%19llu%15llu%19llu%18llu%19llu%18llu  %-32s\n", taskCB->taskID,
227                averRunTime, taskCB->schedStat.switchCount,
228                averTimeSlice, taskCB->schedStat.timeSliceCount - 1,
229                averSchedWait, averPendTime, taskCB->taskName);
230     }
231 
232     (VOID)LOS_MemFree(m_aucSysMem1, taskCBArray);
233 
234     return LOS_OK;
235 }
236 
237 #else
238 
OsShellShowSchedParam(VOID)239 UINT32 OsShellShowSchedParam(VOID)
240 {
241     return LOS_NOK;
242 }
243 #endif
244 
TimeSliceUpdate(LosTaskCB * taskCB,UINT64 currTime)245 STATIC INLINE VOID TimeSliceUpdate(LosTaskCB *taskCB, UINT64 currTime)
246 {
247     LOS_ASSERT(currTime >= taskCB->startTime);
248 
249     INT32 incTime = (currTime - taskCB->startTime - taskCB->irqUsedTime);
250 
251     LOS_ASSERT(incTime >= 0);
252 
253     if (taskCB->policy == LOS_SCHED_RR) {
254         taskCB->timeSlice -= incTime;
255 #ifdef LOSCFG_SCHED_DEBUG
256         taskCB->schedStat.timeSliceRealTime += incTime;
257 #endif
258     }
259     taskCB->irqUsedTime = 0;
260     taskCB->startTime = currTime;
261 
262 #ifdef LOSCFG_SCHED_DEBUG
263     taskCB->schedStat.allRuntime += incTime;
264 #endif
265 }
266 
GetNextExpireTime(SchedRunQue * rq,UINT64 startTime,UINT32 tickPrecision)267 STATIC INLINE UINT64 GetNextExpireTime(SchedRunQue *rq, UINT64 startTime, UINT32 tickPrecision)
268 {
269     SortLinkAttribute *taskHeader = &rq->taskSortLink;
270     SortLinkAttribute *swtmrHeader = &rq->swtmrSortLink;
271 
272     LOS_SpinLock(&taskHeader->spinLock);
273     UINT64 taskExpireTime = OsGetSortLinkNextExpireTime(taskHeader, startTime, tickPrecision);
274     LOS_SpinUnlock(&taskHeader->spinLock);
275 
276     LOS_SpinLock(&swtmrHeader->spinLock);
277     UINT64 swtmrExpireTime = OsGetSortLinkNextExpireTime(swtmrHeader, startTime, tickPrecision);
278     LOS_SpinUnlock(&swtmrHeader->spinLock);
279 
280     return (taskExpireTime < swtmrExpireTime) ? taskExpireTime : swtmrExpireTime;
281 }
282 
SchedSetNextExpireTime(UINT32 responseID,UINT64 taskEndTime,UINT32 oldResponseID)283 STATIC INLINE VOID SchedSetNextExpireTime(UINT32 responseID, UINT64 taskEndTime, UINT32 oldResponseID)
284 {
285     SchedRunQue *rq = OsSchedRunQue();
286     BOOL isTimeSlice = FALSE;
287     UINT64 currTime = OsGetCurrSchedTimeCycle();
288     UINT64 nextExpireTime = GetNextExpireTime(rq, currTime, OS_TICK_RESPONSE_PRECISION);
289 
290     rq->schedFlag &= ~INT_PEND_TICK;
291     if (rq->responseID == oldResponseID) {
292         /* This time has expired, and the next time the theory has expired is infinite */
293         rq->responseTime = OS_SCHED_MAX_RESPONSE_TIME;
294     }
295 
296     /* The current thread's time slice has been consumed, but the current system lock task cannot
297      * trigger the schedule to release the CPU
298      */
299     if ((nextExpireTime > taskEndTime) && ((nextExpireTime - taskEndTime) > OS_SCHED_MINI_PERIOD)) {
300         nextExpireTime = taskEndTime;
301         isTimeSlice = TRUE;
302     }
303 
304     if ((rq->responseTime <= nextExpireTime) ||
305         ((rq->responseTime - nextExpireTime) < OS_TICK_RESPONSE_PRECISION)) {
306         return;
307     }
308 
309     if (isTimeSlice) {
310         /* The expiration time of the current system is the thread's slice expiration time */
311         rq->responseID = responseID;
312     } else {
313         rq->responseID = OS_INVALID_VALUE;
314     }
315 
316     UINT64 nextResponseTime = nextExpireTime - currTime;
317     rq->responseTime = currTime + HalClockTickTimerReload(nextResponseTime);
318 
319 #ifdef LOSCFG_SCHED_TICK_DEBUG
320     SchedTickDebug *schedDebug = &g_schedTickDebug[ArchCurrCpuid()];
321     if (schedDebug->index < OS_SCHED_DEBUG_DATA_NUM) {
322         schedDebug->setTickCount++;
323     }
324 #endif
325 }
326 
OsSchedUpdateExpireTime(VOID)327 VOID OsSchedUpdateExpireTime(VOID)
328 {
329     UINT64 endTime;
330     LosTaskCB *runTask = OsCurrTaskGet();
331 
332     if (!OS_SCHEDULER_ACTIVE || OS_INT_ACTIVE) {
333         OsSchedRunQuePendingSet();
334         return;
335     }
336 
337     if (runTask->policy == LOS_SCHED_RR) {
338         LOS_SpinLock(&g_taskSpin);
339         INT32 timeSlice = (runTask->timeSlice <= OS_TIME_SLICE_MIN) ? runTask->initTimeSlice : runTask->timeSlice;
340         endTime = runTask->startTime + timeSlice;
341         LOS_SpinUnlock(&g_taskSpin);
342     } else {
343         endTime = OS_SCHED_MAX_RESPONSE_TIME - OS_TICK_RESPONSE_PRECISION;
344     }
345 
346     SchedSetNextExpireTime(runTask->taskID, endTime, runTask->taskID);
347 }
348 
SchedCalculateTimeSlice(UINT16 proPriority,UINT16 priority)349 STATIC INLINE UINT32 SchedCalculateTimeSlice(UINT16 proPriority, UINT16 priority)
350 {
351     UINT32 retTime;
352     UINT32 readyTasks;
353 
354     SchedQueue *queueList = &g_sched.queueList[proPriority];
355     readyTasks = queueList->readyTasks[priority];
356     if (readyTasks > OS_SCHED_READY_MAX) {
357         return OS_SCHED_TIME_SLICES_MIN;
358     }
359     retTime = ((OS_SCHED_READY_MAX - readyTasks) * OS_SCHED_TIME_SLICES_DIFF) / OS_SCHED_READY_MAX;
360     return (retTime + OS_SCHED_TIME_SLICES_MIN);
361 }
362 
SchedPriQueueEnHead(UINT32 proPriority,LOS_DL_LIST * priqueueItem,UINT32 priority)363 STATIC INLINE VOID SchedPriQueueEnHead(UINT32 proPriority, LOS_DL_LIST *priqueueItem, UINT32 priority)
364 {
365     SchedQueue *queueList = &g_sched.queueList[proPriority];
366     LOS_DL_LIST *priQueueList = &queueList->priQueueList[0];
367     UINT32 *bitMap = &queueList->queueBitmap;
368 
369     /*
370      * Task control blocks are inited as zero. And when task is deleted,
371      * and at the same time would be deleted from priority queue or
372      * other lists, task pend node will restored as zero.
373      */
374     LOS_ASSERT(priqueueItem->pstNext == NULL);
375 
376     if (*bitMap == 0) {
377         g_sched.queueBitmap |= PRIQUEUE_PRIOR0_BIT >> proPriority;
378     }
379 
380     if (LOS_ListEmpty(&priQueueList[priority])) {
381         *bitMap |= PRIQUEUE_PRIOR0_BIT >> priority;
382     }
383 
384     LOS_ListHeadInsert(&priQueueList[priority], priqueueItem);
385     queueList->readyTasks[priority]++;
386 }
387 
SchedPriQueueEnTail(UINT32 proPriority,LOS_DL_LIST * priqueueItem,UINT32 priority)388 STATIC INLINE VOID SchedPriQueueEnTail(UINT32 proPriority, LOS_DL_LIST *priqueueItem, UINT32 priority)
389 {
390     SchedQueue *queueList = &g_sched.queueList[proPriority];
391     LOS_DL_LIST *priQueueList = &queueList->priQueueList[0];
392     UINT32 *bitMap = &queueList->queueBitmap;
393 
394     /*
395      * Task control blocks are inited as zero. And when task is deleted,
396      * and at the same time would be deleted from priority queue or
397      * other lists, task pend node will restored as zero.
398      */
399     LOS_ASSERT(priqueueItem->pstNext == NULL);
400 
401     if (*bitMap == 0) {
402         g_sched.queueBitmap |= PRIQUEUE_PRIOR0_BIT >> proPriority;
403     }
404 
405     if (LOS_ListEmpty(&priQueueList[priority])) {
406         *bitMap |= PRIQUEUE_PRIOR0_BIT >> priority;
407     }
408 
409     LOS_ListTailInsert(&priQueueList[priority], priqueueItem);
410     queueList->readyTasks[priority]++;
411 }
412 
SchedPriQueueDelete(UINT32 proPriority,LOS_DL_LIST * priqueueItem,UINT32 priority)413 STATIC INLINE VOID SchedPriQueueDelete(UINT32 proPriority, LOS_DL_LIST *priqueueItem, UINT32 priority)
414 {
415     SchedQueue *queueList = &g_sched.queueList[proPriority];
416     LOS_DL_LIST *priQueueList = &queueList->priQueueList[0];
417     UINT32 *bitMap = &queueList->queueBitmap;
418 
419     LOS_ListDelete(priqueueItem);
420     queueList->readyTasks[priority]--;
421     if (LOS_ListEmpty(&priQueueList[priority])) {
422         *bitMap &= ~(PRIQUEUE_PRIOR0_BIT >> priority);
423     }
424 
425     if (*bitMap == 0) {
426         g_sched.queueBitmap &= ~(PRIQUEUE_PRIOR0_BIT >> proPriority);
427     }
428 }
429 
SchedEnTaskQueue(LosTaskCB * taskCB)430 STATIC INLINE VOID SchedEnTaskQueue(LosTaskCB *taskCB)
431 {
432     LOS_ASSERT(!(taskCB->taskStatus & OS_TASK_STATUS_READY));
433 
434     switch (taskCB->policy) {
435         case LOS_SCHED_RR: {
436             if (taskCB->timeSlice > OS_TIME_SLICE_MIN) {
437                 SchedPriQueueEnHead(taskCB->basePrio, &taskCB->pendList, taskCB->priority);
438             } else {
439                 taskCB->initTimeSlice = SchedCalculateTimeSlice(taskCB->basePrio, taskCB->priority);
440                 taskCB->timeSlice = taskCB->initTimeSlice;
441                 SchedPriQueueEnTail(taskCB->basePrio, &taskCB->pendList, taskCB->priority);
442 #ifdef LOSCFG_SCHED_DEBUG
443                 taskCB->schedStat.timeSliceTime = taskCB->schedStat.timeSliceRealTime;
444                 taskCB->schedStat.timeSliceCount++;
445 #endif
446             }
447             break;
448         }
449         case LOS_SCHED_FIFO: {
450             /* The time slice of FIFO is always greater than 0 unless the yield is called */
451             if ((taskCB->timeSlice > OS_TIME_SLICE_MIN) && (taskCB->taskStatus & OS_TASK_STATUS_RUNNING)) {
452                 SchedPriQueueEnHead(taskCB->basePrio, &taskCB->pendList, taskCB->priority);
453             } else {
454                 taskCB->initTimeSlice = OS_SCHED_FIFO_TIMEOUT;
455                 taskCB->timeSlice = taskCB->initTimeSlice;
456                 SchedPriQueueEnTail(taskCB->basePrio, &taskCB->pendList, taskCB->priority);
457             }
458             break;
459         }
460         case LOS_SCHED_IDLE:
461 #ifdef LOSCFG_SCHED_DEBUG
462             taskCB->schedStat.timeSliceCount = 1;
463 #endif
464             break;
465         default:
466             LOS_ASSERT(0);
467             break;
468     }
469 
470     taskCB->taskStatus &= ~OS_TASK_STATUS_BLOCKED;
471     taskCB->taskStatus |= OS_TASK_STATUS_READY;
472 }
473 
OsSchedTaskDeQueue(LosTaskCB * taskCB)474 VOID OsSchedTaskDeQueue(LosTaskCB *taskCB)
475 {
476     if (taskCB->taskStatus & OS_TASK_STATUS_READY) {
477         if (taskCB->policy != LOS_SCHED_IDLE) {
478             SchedPriQueueDelete(taskCB->basePrio, &taskCB->pendList, taskCB->priority);
479         }
480         taskCB->taskStatus &= ~OS_TASK_STATUS_READY;
481     }
482 }
483 
OsSchedTaskEnQueue(LosTaskCB * taskCB)484 VOID OsSchedTaskEnQueue(LosTaskCB *taskCB)
485 {
486 #ifdef LOSCFG_SCHED_DEBUG
487     if (!(taskCB->taskStatus & OS_TASK_STATUS_RUNNING)) {
488         taskCB->startTime = OsGetCurrSchedTimeCycle();
489     }
490 #endif
491     SchedEnTaskQueue(taskCB);
492 }
493 
OsSchedTaskExit(LosTaskCB * taskCB)494 VOID OsSchedTaskExit(LosTaskCB *taskCB)
495 {
496     if (taskCB->taskStatus & OS_TASK_STATUS_READY) {
497         OsSchedTaskDeQueue(taskCB);
498     } else if (taskCB->taskStatus & OS_TASK_STATUS_PENDING) {
499         LOS_ListDelete(&taskCB->pendList);
500         taskCB->taskStatus &= ~OS_TASK_STATUS_PENDING;
501     }
502 
503     if (taskCB->taskStatus & (OS_TASK_STATUS_DELAY | OS_TASK_STATUS_PEND_TIME)) {
504         OsSchedDeTaskFromTimeList(&taskCB->sortList);
505         taskCB->taskStatus &= ~(OS_TASK_STATUS_DELAY | OS_TASK_STATUS_PEND_TIME);
506     }
507 }
508 
OsSchedYield(VOID)509 VOID OsSchedYield(VOID)
510 {
511     LosTaskCB *runTask = OsCurrTaskGet();
512 
513     runTask->timeSlice = 0;
514 
515     runTask->startTime = OsGetCurrSchedTimeCycle();
516     OsSchedTaskEnQueue(runTask);
517     OsSchedResched();
518 }
519 
OsSchedDelay(LosTaskCB * runTask,UINT32 tick)520 VOID OsSchedDelay(LosTaskCB *runTask, UINT32 tick)
521 {
522     OsSchedTaskDeQueue(runTask);
523     runTask->taskStatus |= OS_TASK_STATUS_DELAY;
524     runTask->waitTimes = tick;
525 
526     OsSchedResched();
527 }
528 
OsSchedTaskWait(LOS_DL_LIST * list,UINT32 ticks,BOOL needSched)529 UINT32 OsSchedTaskWait(LOS_DL_LIST *list, UINT32 ticks, BOOL needSched)
530 {
531     LosTaskCB *runTask = OsCurrTaskGet();
532 
533     runTask->taskStatus |= OS_TASK_STATUS_PENDING;
534     LOS_ListTailInsert(list, &runTask->pendList);
535 
536     if (ticks != LOS_WAIT_FOREVER) {
537         runTask->taskStatus |= OS_TASK_STATUS_PEND_TIME;
538         runTask->waitTimes = ticks;
539     }
540 
541     if (needSched == TRUE) {
542         OsSchedResched();
543         if (runTask->taskStatus & OS_TASK_STATUS_TIMEOUT) {
544             runTask->taskStatus &= ~OS_TASK_STATUS_TIMEOUT;
545             return LOS_ERRNO_TSK_TIMEOUT;
546         }
547     }
548 
549     return LOS_OK;
550 }
551 
OsSchedTaskWake(LosTaskCB * resumedTask)552 VOID OsSchedTaskWake(LosTaskCB *resumedTask)
553 {
554     LOS_ListDelete(&resumedTask->pendList);
555     resumedTask->taskStatus &= ~OS_TASK_STATUS_PENDING;
556 
557     if (resumedTask->taskStatus & OS_TASK_STATUS_PEND_TIME) {
558         OsSchedDeTaskFromTimeList(&resumedTask->sortList);
559         resumedTask->taskStatus &= ~OS_TASK_STATUS_PEND_TIME;
560     }
561 
562     if (!(resumedTask->taskStatus & OS_TASK_STATUS_SUSPENDED)) {
563 #ifdef LOSCFG_SCHED_DEBUG
564         resumedTask->schedStat.pendTime += OsGetCurrSchedTimeCycle() - resumedTask->startTime;
565         resumedTask->schedStat.pendCount++;
566 #endif
567         OsSchedTaskEnQueue(resumedTask);
568     }
569 }
570 
OsSchedModifyTaskSchedParam(LosTaskCB * taskCB,UINT16 policy,UINT16 priority)571 BOOL OsSchedModifyTaskSchedParam(LosTaskCB *taskCB, UINT16 policy, UINT16 priority)
572 {
573     if (taskCB->policy != policy) {
574         taskCB->policy = policy;
575         taskCB->timeSlice = 0;
576     }
577 
578     if (taskCB->taskStatus & OS_TASK_STATUS_READY) {
579         OsSchedTaskDeQueue(taskCB);
580         taskCB->priority = priority;
581         OsSchedTaskEnQueue(taskCB);
582         return TRUE;
583     }
584 
585     taskCB->priority = priority;
586     OsHookCall(LOS_HOOK_TYPE_TASK_PRIMODIFY, taskCB, taskCB->priority);
587     if (taskCB->taskStatus & OS_TASK_STATUS_INIT) {
588         OsSchedTaskEnQueue(taskCB);
589         return TRUE;
590     }
591 
592     if (taskCB->taskStatus & OS_TASK_STATUS_RUNNING) {
593         return TRUE;
594     }
595 
596     return FALSE;
597 }
598 
OsSchedModifyProcessSchedParam(UINT32 pid,UINT16 policy,UINT16 priority)599 BOOL OsSchedModifyProcessSchedParam(UINT32 pid, UINT16 policy, UINT16 priority)
600 {
601     LosProcessCB *processCB = OS_PCB_FROM_PID(pid);
602     LosTaskCB *taskCB = NULL;
603     BOOL needSched = FALSE;
604     (VOID)policy;
605 
606     LOS_DL_LIST_FOR_EACH_ENTRY(taskCB, &processCB->threadSiblingList, LosTaskCB, threadList) {
607         if (taskCB->taskStatus & OS_TASK_STATUS_READY) {
608             SchedPriQueueDelete(taskCB->basePrio, &taskCB->pendList, taskCB->priority);
609             SchedPriQueueEnTail(priority, &taskCB->pendList, taskCB->priority);
610             needSched = TRUE;
611         } else if (taskCB->taskStatus & OS_TASK_STATUS_RUNNING) {
612             needSched = TRUE;
613         }
614         taskCB->basePrio = priority;
615     }
616 
617     return needSched;
618 }
619 
SchedFreezeTask(LosTaskCB * taskCB)620 STATIC VOID SchedFreezeTask(LosTaskCB *taskCB)
621 {
622     UINT64 responseTime;
623 
624     if (!OsIsPmMode()) {
625         return;
626     }
627 
628     if (!(taskCB->taskStatus & (OS_TASK_STATUS_PEND_TIME | OS_TASK_STATUS_DELAY))) {
629         return;
630     }
631 
632     responseTime = GET_SORTLIST_VALUE(&taskCB->sortList);
633     OsSchedDeTaskFromTimeList(&taskCB->sortList);
634     SET_SORTLIST_VALUE(&taskCB->sortList, responseTime);
635     taskCB->taskStatus |= OS_TASK_FLAG_FREEZE;
636     return;
637 }
638 
SchedUnfreezeTask(LosTaskCB * taskCB)639 STATIC VOID SchedUnfreezeTask(LosTaskCB *taskCB)
640 {
641     UINT64 currTime, responseTime;
642     UINT32 remainTick;
643 
644     if (!(taskCB->taskStatus & OS_TASK_FLAG_FREEZE)) {
645         return;
646     }
647 
648     taskCB->taskStatus &= ~OS_TASK_FLAG_FREEZE;
649     currTime = OsGetCurrSchedTimeCycle();
650     responseTime = GET_SORTLIST_VALUE(&taskCB->sortList);
651     if (responseTime > currTime) {
652         remainTick = ((responseTime - currTime) + OS_CYCLE_PER_TICK - 1) / OS_CYCLE_PER_TICK;
653         OsSchedAddTask2TimeList(&taskCB->sortList, currTime, remainTick);
654         return;
655     }
656 
657     SET_SORTLIST_VALUE(&taskCB->sortList, OS_SORT_LINK_INVALID_TIME);
658     if (taskCB->taskStatus & OS_TASK_STATUS_PENDING) {
659         LOS_ListDelete(&taskCB->pendList);
660     }
661     taskCB->taskStatus &= ~(OS_TASK_STATUS_DELAY | OS_TASK_STATUS_PEND_TIME | OS_TASK_STATUS_PENDING);
662     return;
663 }
664 
OsSchedSuspend(LosTaskCB * taskCB)665 VOID OsSchedSuspend(LosTaskCB *taskCB)
666 {
667     if (taskCB->taskStatus & OS_TASK_STATUS_READY) {
668         OsSchedTaskDeQueue(taskCB);
669     }
670 
671     SchedFreezeTask(taskCB);
672 
673     taskCB->taskStatus |= OS_TASK_STATUS_SUSPENDED;
674     OsHookCall(LOS_HOOK_TYPE_MOVEDTASKTOSUSPENDEDLIST, taskCB);
675     if (taskCB == OsCurrTaskGet()) {
676         OsSchedResched();
677     }
678 }
679 
OsSchedResume(LosTaskCB * taskCB)680 BOOL OsSchedResume(LosTaskCB *taskCB)
681 {
682     BOOL needSched = FALSE;
683 
684     SchedUnfreezeTask(taskCB);
685 
686     taskCB->taskStatus &= ~OS_TASK_STATUS_SUSPENDED;
687     if (!OsTaskIsBlocked(taskCB)) {
688         OsSchedTaskEnQueue(taskCB);
689         needSched = TRUE;
690     }
691 
692     return needSched;
693 }
694 
SchedScanSwtmrTimeList(SchedRunQue * rq)695 STATIC INLINE BOOL SchedScanSwtmrTimeList(SchedRunQue *rq)
696 {
697     BOOL needSched = FALSE;
698     SortLinkAttribute* swtmrSortLink = &rq->swtmrSortLink;
699     LOS_DL_LIST *listObject = &swtmrSortLink->sortLink;
700 
701     /*
702      * it needs to be carefully coped with, since the swtmr is in specific sortlink
703      * while other cores still has the chance to process it, like stop the timer.
704      */
705     LOS_SpinLock(&swtmrSortLink->spinLock);
706 
707     if (LOS_ListEmpty(listObject)) {
708         LOS_SpinUnlock(&swtmrSortLink->spinLock);
709         return FALSE;
710     }
711     SortLinkList *sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
712 
713     UINT64 currTime = OsGetCurrSchedTimeCycle();
714     while (sortList->responseTime <= currTime) {
715         sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
716         UINT64 startTime = GET_SORTLIST_VALUE(sortList);
717         OsDeleteNodeSortLink(swtmrSortLink, sortList);
718         LOS_SpinUnlock(&swtmrSortLink->spinLock);
719 
720         OsSwtmrWake(rq, startTime, sortList);
721         needSched = TRUE;
722 
723         LOS_SpinLock(&swtmrSortLink->spinLock);
724         if (LOS_ListEmpty(listObject)) {
725             break;
726         }
727 
728         sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
729     }
730 
731     LOS_SpinUnlock(&swtmrSortLink->spinLock);
732     return needSched;
733 }
734 
SchedSwtmrResponseTimeReset(SchedRunQue * rq,UINT64 startTime)735 STATIC INLINE VOID SchedSwtmrResponseTimeReset(SchedRunQue *rq, UINT64 startTime)
736 {
737     SortLinkAttribute* swtmrSortLink = &rq->swtmrSortLink;
738     LOS_DL_LIST *listHead = &swtmrSortLink->sortLink;
739     LOS_DL_LIST *listNext = listHead->pstNext;
740 
741     LOS_SpinLock(&swtmrSortLink->spinLock);
742     while (listNext != listHead) {
743         SortLinkList *sortList = LOS_DL_LIST_ENTRY(listNext, SortLinkList, sortLinkNode);
744         OsDeleteNodeSortLink(swtmrSortLink, sortList);
745         LOS_SpinUnlock(&swtmrSortLink->spinLock);
746 
747         OsSwtmrRestart(startTime, sortList);
748 
749         LOS_SpinLock(&swtmrSortLink->spinLock);
750         listNext = listNext->pstNext;
751     }
752     LOS_SpinUnlock(&swtmrSortLink->spinLock);
753 }
754 
SchedSwtmrRunQueFind(SortLinkAttribute * swtmrSortLink,SCHED_TL_FIND_FUNC checkFunc,UINTPTR arg)755 STATIC INLINE BOOL SchedSwtmrRunQueFind(SortLinkAttribute *swtmrSortLink, SCHED_TL_FIND_FUNC checkFunc, UINTPTR arg)
756 {
757     LOS_DL_LIST *listObject = &swtmrSortLink->sortLink;
758     LOS_DL_LIST *list = listObject->pstNext;
759 
760     LOS_SpinLock(&swtmrSortLink->spinLock);
761     while (list != listObject) {
762         SortLinkList *listSorted = LOS_DL_LIST_ENTRY(list, SortLinkList, sortLinkNode);
763         if (checkFunc((UINTPTR)listSorted, arg)) {
764             LOS_SpinUnlock(&swtmrSortLink->spinLock);
765             return TRUE;
766         }
767         list = list->pstNext;
768     }
769 
770     LOS_SpinUnlock(&swtmrSortLink->spinLock);
771     return FALSE;
772 }
773 
OsSchedSwtmrTimeListFind(SCHED_TL_FIND_FUNC checkFunc,UINTPTR arg)774 BOOL OsSchedSwtmrTimeListFind(SCHED_TL_FIND_FUNC checkFunc, UINTPTR arg)
775 {
776     for (UINT16 cpuid = 0; cpuid < LOSCFG_KERNEL_CORE_NUM; cpuid++) {
777         SchedRunQue *rq = OsSchedRunQueByID(cpuid);
778         SortLinkAttribute *swtmrSortLink = &rq->swtmrSortLink;
779         if (SchedSwtmrRunQueFind(swtmrSortLink, checkFunc, arg)) {
780             return TRUE;
781         }
782     }
783     return FALSE;
784 }
785 
SchedWakePendTimeTask(UINT64 currTime,LosTaskCB * taskCB,BOOL * needSchedule)786 STATIC INLINE VOID SchedWakePendTimeTask(UINT64 currTime, LosTaskCB *taskCB, BOOL *needSchedule)
787 {
788 #ifndef LOSCFG_SCHED_DEBUG
789     (VOID)currTime;
790 #endif
791 
792     LOS_SpinLock(&g_taskSpin);
793     UINT16 tempStatus = taskCB->taskStatus;
794     if (tempStatus & (OS_TASK_STATUS_PENDING | OS_TASK_STATUS_DELAY)) {
795         taskCB->taskStatus &= ~(OS_TASK_STATUS_PENDING | OS_TASK_STATUS_PEND_TIME | OS_TASK_STATUS_DELAY);
796         if (tempStatus & OS_TASK_STATUS_PENDING) {
797             taskCB->taskStatus |= OS_TASK_STATUS_TIMEOUT;
798             LOS_ListDelete(&taskCB->pendList);
799             taskCB->taskMux = NULL;
800             OsTaskWakeClearPendMask(taskCB);
801         }
802 
803         if (!(tempStatus & OS_TASK_STATUS_SUSPENDED)) {
804 #ifdef LOSCFG_SCHED_DEBUG
805             taskCB->schedStat.pendTime += currTime - taskCB->startTime;
806             taskCB->schedStat.pendCount++;
807 #endif
808             OsSchedTaskEnQueue(taskCB);
809             *needSchedule = TRUE;
810         }
811     }
812 
813     LOS_SpinUnlock(&g_taskSpin);
814 }
815 
SchedScanTaskTimeList(SchedRunQue * rq)816 STATIC INLINE BOOL SchedScanTaskTimeList(SchedRunQue *rq)
817 {
818     BOOL needSchedule = FALSE;
819     SortLinkAttribute *taskSortLink = &rq->taskSortLink;
820     LOS_DL_LIST *listObject = &taskSortLink->sortLink;
821     /*
822      * When task is pended with timeout, the task block is on the timeout sortlink
823      * (per cpu) and ipc(mutex,sem and etc.)'s block at the same time, it can be waken
824      * up by either timeout or corresponding ipc it's waiting.
825      *
826      * Now synchronize sortlink procedure is used, therefore the whole task scan needs
827      * to be protected, preventing another core from doing sortlink deletion at same time.
828      */
829     LOS_SpinLock(&taskSortLink->spinLock);
830 
831     if (LOS_ListEmpty(listObject)) {
832         LOS_SpinUnlock(&taskSortLink->spinLock);
833         return needSchedule;
834     }
835 
836     SortLinkList *sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
837     UINT64 currTime = OsGetCurrSchedTimeCycle();
838     while (sortList->responseTime <= currTime) {
839         LosTaskCB *taskCB = LOS_DL_LIST_ENTRY(sortList, LosTaskCB, sortList);
840         OsDeleteNodeSortLink(taskSortLink, &taskCB->sortList);
841         LOS_SpinUnlock(&taskSortLink->spinLock);
842 
843         SchedWakePendTimeTask(currTime, taskCB, &needSchedule);
844 
845         LOS_SpinLock(&taskSortLink->spinLock);
846         if (LOS_ListEmpty(listObject)) {
847             break;
848         }
849 
850         sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
851     }
852 
853     LOS_SpinUnlock(&taskSortLink->spinLock);
854 
855     return needSchedule;
856 }
857 
OsSchedTick(VOID)858 VOID OsSchedTick(VOID)
859 {
860     SchedRunQue *rq = OsSchedRunQue();
861     BOOL needSched = FALSE;
862 
863     if (rq->responseID == OS_INVALID_VALUE) {
864 
865         needSched |= SchedScanSwtmrTimeList(rq);
866         needSched |= SchedScanTaskTimeList(rq);
867 
868         if (needSched) {
869             LOS_MpSchedule(OS_MP_CPU_ALL);
870             rq->schedFlag |= INT_PEND_RESCH;
871         }
872     }
873     rq->schedFlag |= INT_PEND_TICK;
874     rq->responseTime = OS_SCHED_MAX_RESPONSE_TIME;
875 }
876 
OsSchedSetIdleTaskSchedParam(LosTaskCB * idleTask)877 VOID OsSchedSetIdleTaskSchedParam(LosTaskCB *idleTask)
878 {
879     idleTask->basePrio = OS_TASK_PRIORITY_LOWEST;
880     idleTask->policy = LOS_SCHED_IDLE;
881     idleTask->initTimeSlice = OS_SCHED_FIFO_TIMEOUT;
882     idleTask->timeSlice = idleTask->initTimeSlice;
883     OsSchedTaskEnQueue(idleTask);
884 }
885 
OsSchedResetSchedResponseTime(UINT64 responseTime)886 VOID OsSchedResetSchedResponseTime(UINT64 responseTime)
887 {
888     OsSchedRunQue()->responseTime = responseTime;
889 }
890 
OsSchedRunQueInit(VOID)891 VOID OsSchedRunQueInit(VOID)
892 {
893     if (ArchCurrCpuid() != 0) {
894         return;
895     }
896 
897     for (UINT16 index = 0; index < LOSCFG_KERNEL_CORE_NUM; index++) {
898         SchedRunQue *rq = OsSchedRunQueByID(index);
899         OsSortLinkInit(&rq->taskSortLink);
900         OsSortLinkInit(&rq->swtmrSortLink);
901         rq->responseTime = OS_SCHED_MAX_RESPONSE_TIME;
902     }
903 }
904 
OsSchedRunQueSwtmrInit(UINT32 swtmrTaskID,UINT32 swtmrQueue)905 VOID OsSchedRunQueSwtmrInit(UINT32 swtmrTaskID, UINT32 swtmrQueue)
906 {
907     SchedRunQue *rq = OsSchedRunQue();
908     rq->swtmrTaskID = swtmrTaskID;
909     rq->swtmrHandlerQueue = swtmrQueue;
910 }
911 
OsSchedRunQueIdleInit(UINT32 idleTaskID)912 VOID OsSchedRunQueIdleInit(UINT32 idleTaskID)
913 {
914     SchedRunQue *rq = OsSchedRunQue();
915     rq->idleTaskID = idleTaskID;
916 }
917 
OsSchedInit(VOID)918 UINT32 OsSchedInit(VOID)
919 {
920     for (UINT16 index = 0; index < OS_PRIORITY_QUEUE_NUM; index++) {
921         SchedQueue *queueList = &g_sched.queueList[index];
922         LOS_DL_LIST *priList = &queueList->priQueueList[0];
923         for (UINT16 pri = 0; pri < OS_PRIORITY_QUEUE_NUM; pri++) {
924             LOS_ListInit(&priList[pri]);
925         }
926     }
927 
928 #ifdef LOSCFG_SCHED_TICK_DEBUG
929     UINT32 ret = OsSchedDebugInit();
930     if (ret != LOS_OK) {
931         return ret;
932     }
933 #endif
934     return LOS_OK;
935 }
936 
GetTopTask(SchedRunQue * rq)937 STATIC LosTaskCB *GetTopTask(SchedRunQue *rq)
938 {
939     UINT32 priority, processPriority;
940     UINT32 bitmap;
941     LosTaskCB *newTask = NULL;
942     UINT32 processBitmap = g_sched.queueBitmap;
943 #ifdef LOSCFG_KERNEL_SMP
944     UINT32 cpuid = ArchCurrCpuid();
945 #endif
946 
947     while (processBitmap) {
948         processPriority = CLZ(processBitmap);
949         SchedQueue *queueList = &g_sched.queueList[processPriority];
950         bitmap = queueList->queueBitmap;
951             while (bitmap) {
952                 priority = CLZ(bitmap);
953                 LOS_DL_LIST_FOR_EACH_ENTRY(newTask, &queueList->priQueueList[priority], LosTaskCB, pendList) {
954 #ifdef LOSCFG_KERNEL_SMP
955                     if (newTask->cpuAffiMask & (1U << cpuid)) {
956 #endif
957                         goto FIND_TASK;
958 #ifdef LOSCFG_KERNEL_SMP
959                     }
960 #endif
961                 }
962             bitmap &= ~(1U << (OS_PRIORITY_QUEUE_NUM - priority - 1));
963         }
964         processBitmap &= ~(1U << (OS_PRIORITY_QUEUE_NUM - processPriority - 1));
965     }
966 
967     newTask = OS_TCB_FROM_TID(rq->idleTaskID);
968 
969 FIND_TASK:
970     OsSchedTaskDeQueue(newTask);
971     return newTask;
972 }
973 
OsSchedStart(VOID)974 VOID OsSchedStart(VOID)
975 {
976     UINT32 cpuid = ArchCurrCpuid();
977     UINT32 intSave;
978 
979     PRINTK("cpu %d entering scheduler\n", cpuid);
980 
981     SCHEDULER_LOCK(intSave);
982 
983     if (cpuid == 0) {
984         OsTickStart();
985     }
986 
987     SchedRunQue *rq = OsSchedRunQue();
988     LosTaskCB *newTask = GetTopTask(rq);
989     newTask->taskStatus |= OS_TASK_STATUS_RUNNING;
990 
991 #ifdef LOSCFG_KERNEL_SMP
992     /*
993      * attention: current cpu needs to be set, in case first task deletion
994      * may fail because this flag mismatch with the real current cpu.
995      */
996     newTask->currCpu = cpuid;
997 #endif
998 
999     OsCurrTaskSet((VOID *)newTask);
1000 
1001     newTask->startTime = OsGetCurrSchedTimeCycle();
1002 
1003     SchedSwtmrResponseTimeReset(rq, newTask->startTime);
1004 
1005     /* System start schedule */
1006     OS_SCHEDULER_SET(cpuid);
1007 
1008     rq->responseID = OS_INVALID;
1009     SchedSetNextExpireTime(newTask->taskID, newTask->startTime + newTask->timeSlice, OS_INVALID);
1010     OsTaskContextLoad(newTask);
1011 }
1012 
1013 #ifdef LOSCFG_KERNEL_SMP
OsSchedToUserReleaseLock(VOID)1014 VOID OsSchedToUserReleaseLock(VOID)
1015 {
1016     /* The scheduling lock needs to be released before returning to user mode */
1017     LOCKDEP_CHECK_OUT(&g_taskSpin);
1018     ArchSpinUnlock(&g_taskSpin.rawLock);
1019 
1020     OsSchedUnlock();
1021 }
1022 #endif
1023 
1024 #ifdef LOSCFG_BASE_CORE_TSK_MONITOR
TaskStackCheck(LosTaskCB * runTask,LosTaskCB * newTask)1025 STATIC VOID TaskStackCheck(LosTaskCB *runTask, LosTaskCB *newTask)
1026 {
1027     if (!OS_STACK_MAGIC_CHECK(runTask->topOfStack)) {
1028         LOS_Panic("CURRENT task ID: %s:%d stack overflow!\n", runTask->taskName, runTask->taskID);
1029     }
1030 
1031     if (((UINTPTR)(newTask->stackPointer) <= newTask->topOfStack) ||
1032         ((UINTPTR)(newTask->stackPointer) > (newTask->topOfStack + newTask->stackSize))) {
1033         LOS_Panic("HIGHEST task ID: %s:%u SP error! StackPointer: %p TopOfStack: %p\n",
1034                   newTask->taskName, newTask->taskID, newTask->stackPointer, newTask->topOfStack);
1035     }
1036 }
1037 #endif
1038 
SchedSwitchCheck(LosTaskCB * runTask,LosTaskCB * newTask)1039 STATIC INLINE VOID SchedSwitchCheck(LosTaskCB *runTask, LosTaskCB *newTask)
1040 {
1041 #ifdef LOSCFG_BASE_CORE_TSK_MONITOR
1042     TaskStackCheck(runTask, newTask);
1043 #endif /* LOSCFG_BASE_CORE_TSK_MONITOR */
1044     OsHookCall(LOS_HOOK_TYPE_TASK_SWITCHEDIN, newTask, runTask);
1045 }
1046 
SchedTaskSwitch(LosTaskCB * runTask,LosTaskCB * newTask)1047 STATIC VOID SchedTaskSwitch(LosTaskCB *runTask, LosTaskCB *newTask)
1048 {
1049     UINT64 endTime;
1050 
1051     SchedSwitchCheck(runTask, newTask);
1052 
1053     runTask->taskStatus &= ~OS_TASK_STATUS_RUNNING;
1054     newTask->taskStatus |= OS_TASK_STATUS_RUNNING;
1055 
1056 #ifdef LOSCFG_KERNEL_SMP
1057     /* mask new running task's owner processor */
1058     runTask->currCpu = OS_TASK_INVALID_CPUID;
1059     newTask->currCpu = ArchCurrCpuid();
1060 #endif
1061 
1062     OsCurrTaskSet((VOID *)newTask);
1063 #ifdef LOSCFG_KERNEL_VM
1064     if (newTask->archMmu != runTask->archMmu) {
1065         LOS_ArchMmuContextSwitch((LosArchMmu *)newTask->archMmu);
1066     }
1067 #endif
1068 
1069 #ifdef LOSCFG_KERNEL_CPUP
1070     OsCpupCycleEndStart(runTask->taskID, newTask->taskID);
1071 #endif
1072 
1073 #ifdef LOSCFG_SCHED_DEBUG
1074     UINT64 waitStartTime = newTask->startTime;
1075 #endif
1076     if (runTask->taskStatus & OS_TASK_STATUS_READY) {
1077         /* When a thread enters the ready queue, its slice of time is updated */
1078         newTask->startTime = runTask->startTime;
1079     } else {
1080         /* The currently running task is blocked */
1081         newTask->startTime = OsGetCurrSchedTimeCycle();
1082         /* The task is in a blocking state and needs to update its time slice before pend */
1083         TimeSliceUpdate(runTask, newTask->startTime);
1084 
1085         if (runTask->taskStatus & (OS_TASK_STATUS_PEND_TIME | OS_TASK_STATUS_DELAY)) {
1086             OsSchedAddTask2TimeList(&runTask->sortList, runTask->startTime, runTask->waitTimes);
1087         }
1088     }
1089 
1090     if (newTask->policy == LOS_SCHED_RR) {
1091         endTime = newTask->startTime + newTask->timeSlice;
1092     } else {
1093         endTime = OS_SCHED_MAX_RESPONSE_TIME - OS_TICK_RESPONSE_PRECISION;
1094     }
1095     SchedSetNextExpireTime(newTask->taskID, endTime, runTask->taskID);
1096 
1097 #ifdef LOSCFG_SCHED_DEBUG
1098     newTask->schedStat.waitSchedTime += newTask->startTime - waitStartTime;
1099     newTask->schedStat.waitSchedCount++;
1100     runTask->schedStat.runTime = runTask->schedStat.allRuntime;
1101     runTask->schedStat.switchCount++;
1102 #endif
1103     /* do the task context switch */
1104     OsTaskSchedule(newTask, runTask);
1105 }
1106 
OsSchedIrqEndCheckNeedSched(VOID)1107 VOID OsSchedIrqEndCheckNeedSched(VOID)
1108 {
1109     SchedRunQue *rq = OsSchedRunQue();
1110     LosTaskCB *runTask = OsCurrTaskGet();
1111 
1112     TimeSliceUpdate(runTask, OsGetCurrSchedTimeCycle());
1113     if (runTask->timeSlice <= OS_TIME_SLICE_MIN) {
1114         rq->schedFlag |= INT_PEND_RESCH;
1115     }
1116 
1117     if (OsPreemptable() && (rq->schedFlag & INT_PEND_RESCH)) {
1118         rq->schedFlag &= ~INT_PEND_RESCH;
1119 
1120         LOS_SpinLock(&g_taskSpin);
1121 
1122         OsSchedTaskEnQueue(runTask);
1123 
1124         LosTaskCB *newTask = GetTopTask(rq);
1125         if (runTask != newTask) {
1126             SchedTaskSwitch(runTask, newTask);
1127             LOS_SpinUnlock(&g_taskSpin);
1128             return;
1129         }
1130 
1131         LOS_SpinUnlock(&g_taskSpin);
1132     }
1133 
1134     if (rq->schedFlag & INT_PEND_TICK) {
1135         OsSchedUpdateExpireTime();
1136     }
1137 }
1138 
OsSchedResched(VOID)1139 VOID OsSchedResched(VOID)
1140 {
1141     LOS_ASSERT(LOS_SpinHeld(&g_taskSpin));
1142     SchedRunQue *rq = OsSchedRunQue();
1143 #ifdef LOSCFG_KERNEL_SMP
1144     LOS_ASSERT(rq->taskLockCnt == 1);
1145 #else
1146     LOS_ASSERT(rq->taskLockCnt == 0);
1147 #endif
1148 
1149     rq->schedFlag &= ~INT_PEND_RESCH;
1150     LosTaskCB *runTask = OsCurrTaskGet();
1151     LosTaskCB *newTask = GetTopTask(rq);
1152     if (runTask == newTask) {
1153         return;
1154     }
1155 
1156     SchedTaskSwitch(runTask, newTask);
1157 }
1158 
LOS_Schedule(VOID)1159 VOID LOS_Schedule(VOID)
1160 {
1161     UINT32 intSave;
1162     LosTaskCB *runTask = OsCurrTaskGet();
1163 
1164     if (OS_INT_ACTIVE) {
1165         OsSchedRunQuePendingSet();
1166         return;
1167     }
1168 
1169     if (!OsPreemptable()) {
1170         return;
1171     }
1172 
1173     /*
1174      * trigger schedule in task will also do the slice check
1175      * if necessary, it will give up the timeslice more in time.
1176      * otherwise, there's no other side effects.
1177      */
1178     SCHEDULER_LOCK(intSave);
1179 
1180     TimeSliceUpdate(runTask, OsGetCurrSchedTimeCycle());
1181 
1182     /* add run task back to ready queue */
1183     OsSchedTaskEnQueue(runTask);
1184 
1185     /* reschedule to new thread */
1186     OsSchedResched();
1187 
1188     SCHEDULER_UNLOCK(intSave);
1189 }
1190 
OsSchedLockPendFindPosSub(const LosTaskCB * runTask,const LOS_DL_LIST * lockList)1191 STATIC INLINE LOS_DL_LIST *OsSchedLockPendFindPosSub(const LosTaskCB *runTask, const LOS_DL_LIST *lockList)
1192 {
1193     LosTaskCB *pendedTask = NULL;
1194     LOS_DL_LIST *node = NULL;
1195 
1196     LOS_DL_LIST_FOR_EACH_ENTRY(pendedTask, lockList, LosTaskCB, pendList) {
1197         if (pendedTask->priority < runTask->priority) {
1198             continue;
1199         } else if (pendedTask->priority > runTask->priority) {
1200             node = &pendedTask->pendList;
1201             break;
1202         } else {
1203             node = pendedTask->pendList.pstNext;
1204             break;
1205         }
1206     }
1207 
1208     return node;
1209 }
1210 
OsSchedLockPendFindPos(const LosTaskCB * runTask,LOS_DL_LIST * lockList)1211 LOS_DL_LIST *OsSchedLockPendFindPos(const LosTaskCB *runTask, LOS_DL_LIST *lockList)
1212 {
1213     LOS_DL_LIST *node = NULL;
1214 
1215     if (LOS_ListEmpty(lockList)) {
1216         node = lockList;
1217     } else {
1218         LosTaskCB *pendedTask1 = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(lockList));
1219         LosTaskCB *pendedTask2 = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_LAST(lockList));
1220         if (pendedTask1->priority > runTask->priority) {
1221             node = lockList->pstNext;
1222         } else if (pendedTask2->priority <= runTask->priority) {
1223             node = lockList;
1224         } else {
1225             node = OsSchedLockPendFindPosSub(runTask, lockList);
1226         }
1227     }
1228 
1229     return node;
1230 }
1231 
1232