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