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 #ifndef _LOS_SCHED_PRI_H
33 #define _LOS_SCHED_PRI_H
34
35 #include "los_sortlink_pri.h"
36 #include "los_sys_pri.h"
37 #include "los_hwi.h"
38 #include "hal_timer.h"
39 #ifdef LOSCFG_SCHED_DEBUG
40 #include "los_stat_pri.h"
41 #endif
42 #include "los_stackinfo_pri.h"
43 #include "los_futex_pri.h"
44 #include "los_signal.h"
45 #ifdef LOSCFG_KERNEL_CPUP
46 #include "los_cpup_pri.h"
47 #endif
48 #ifdef LOSCFG_KERNEL_LITEIPC
49 #include "hm_liteipc.h"
50 #endif
51
52 #ifdef __cplusplus
53 #if __cplusplus
54 extern "C" {
55 #endif /* __cplusplus */
56 #endif /* __cplusplus */
57
58 #define OS_SCHED_MINI_PERIOD (OS_SYS_CLOCK / LOSCFG_BASE_CORE_TICK_PER_SECOND_MINI)
59 #define OS_TICK_RESPONSE_PRECISION (UINT32)((OS_SCHED_MINI_PERIOD * 75) / 100)
60 #define OS_SCHED_MAX_RESPONSE_TIME (UINT64)(((UINT64)-1) - 1U)
61
62 extern UINT32 g_taskScheduled;
63 #define OS_SCHEDULER_ACTIVE (g_taskScheduled & (1U << ArchCurrCpuid()))
64 #define OS_SCHEDULER_ALL_ACTIVE (g_taskScheduled == LOSCFG_KERNEL_CPU_MASK)
65
66 typedef BOOL (*SCHED_TL_FIND_FUNC)(UINTPTR, UINTPTR);
67
OsGetCurrSchedTimeCycle(VOID)68 STATIC INLINE UINT64 OsGetCurrSchedTimeCycle(VOID)
69 {
70 return HalClockGetCycles();
71 }
72
73 typedef enum {
74 INT_NO_RESCH = 0x0, /* no needs to schedule */
75 INT_PEND_RESCH = 0x1, /* pending schedule flag */
76 INT_PEND_TICK = 0x2, /* pending tick */
77 } SchedFlag;
78
79 typedef struct {
80 SortLinkAttribute taskSortLink; /* task sort link */
81 SortLinkAttribute swtmrSortLink; /* swtmr sort link */
82 UINT64 responseTime; /* Response time for current CPU tick interrupts */
83 UINT32 responseID; /* The response ID of the current CPU tick interrupt */
84 UINT32 idleTaskID; /* idle task id */
85 UINT32 taskLockCnt; /* task lock flag */
86 UINT32 swtmrTaskID; /* software timer task id */
87 UINT32 swtmrHandlerQueue; /* software timer timeout queue id */
88 UINT32 schedFlag; /* pending scheduler flag */
89 } SchedRunQue;
90
91 extern SchedRunQue g_schedRunQue[LOSCFG_KERNEL_CORE_NUM];
92
OsSchedRunQue(VOID)93 STATIC INLINE SchedRunQue *OsSchedRunQue(VOID)
94 {
95 return &g_schedRunQue[ArchCurrCpuid()];
96 }
97
OsSchedRunQueByID(UINT16 id)98 STATIC INLINE SchedRunQue *OsSchedRunQueByID(UINT16 id)
99 {
100 return &g_schedRunQue[id];
101 }
102
OsSchedLockCountGet(VOID)103 STATIC INLINE UINT32 OsSchedLockCountGet(VOID)
104 {
105 return OsSchedRunQue()->taskLockCnt;
106 }
107
OsSchedLockSet(UINT32 count)108 STATIC INLINE VOID OsSchedLockSet(UINT32 count)
109 {
110 OsSchedRunQue()->taskLockCnt = count;
111 }
112
OsSchedLock(VOID)113 STATIC INLINE VOID OsSchedLock(VOID)
114 {
115 OsSchedRunQue()->taskLockCnt++;
116 }
117
OsSchedUnlock(VOID)118 STATIC INLINE VOID OsSchedUnlock(VOID)
119 {
120 OsSchedRunQue()->taskLockCnt--;
121 }
122
OsSchedUnlockResch(VOID)123 STATIC INLINE BOOL OsSchedUnlockResch(VOID)
124 {
125 SchedRunQue *rq = OsSchedRunQue();
126 if (rq->taskLockCnt > 0) {
127 rq->taskLockCnt--;
128 if ((rq->taskLockCnt == 0) && (rq->schedFlag & INT_PEND_RESCH) && OS_SCHEDULER_ACTIVE) {
129 return TRUE;
130 }
131 }
132
133 return FALSE;
134 }
135
OsSchedIsLock(VOID)136 STATIC INLINE BOOL OsSchedIsLock(VOID)
137 {
138 return (OsSchedRunQue()->taskLockCnt != 0);
139 }
140
141 /* Check if preemptible with counter flag */
OsPreemptable(VOID)142 STATIC INLINE BOOL OsPreemptable(VOID)
143 {
144 SchedRunQue *rq = OsSchedRunQue();
145 /*
146 * Unlike OsPreemptableInSched, the int may be not disabled when OsPreemptable
147 * is called, needs manually disable interrupt, to prevent current task from
148 * being migrated to another core, and get the wrong preemptable status.
149 */
150 UINT32 intSave = LOS_IntLock();
151 BOOL preemptible = (rq->taskLockCnt == 0);
152 if (!preemptible) {
153 /* Set schedule flag if preemption is disabled */
154 rq->schedFlag |= INT_PEND_RESCH;
155 }
156 LOS_IntRestore(intSave);
157 return preemptible;
158 }
159
OsPreemptableInSched(VOID)160 STATIC INLINE BOOL OsPreemptableInSched(VOID)
161 {
162 BOOL preemptible = FALSE;
163 SchedRunQue *rq = OsSchedRunQue();
164
165 #ifdef LOSCFG_KERNEL_SMP
166 /*
167 * For smp systems, schedule must hold the task spinlock, and this counter
168 * will increase by 1 in that case.
169 */
170 preemptible = (rq->taskLockCnt == 1);
171
172 #else
173 preemptible = (rq->taskLockCnt == 0);
174 #endif
175 if (!preemptible) {
176 /* Set schedule flag if preemption is disabled */
177 rq->schedFlag |= INT_PEND_RESCH;
178 }
179
180 return preemptible;
181 }
182
OsSchedGetRunQueIdle(VOID)183 STATIC INLINE UINT32 OsSchedGetRunQueIdle(VOID)
184 {
185 return OsSchedRunQue()->idleTaskID;
186 }
187
OsSchedRunQuePendingSet(VOID)188 STATIC INLINE VOID OsSchedRunQuePendingSet(VOID)
189 {
190 OsSchedRunQue()->schedFlag |= INT_PEND_RESCH;
191 }
192
193 #ifdef LOSCFG_KERNEL_SMP
FindIdleRunQue(UINT16 * idleCpuID)194 STATIC INLINE VOID FindIdleRunQue(UINT16 *idleCpuID)
195 {
196 SchedRunQue *idleRq = OsSchedRunQueByID(0);
197 UINT32 nodeNum = OsGetSortLinkNodeNum(&idleRq->taskSortLink) + OsGetSortLinkNodeNum(&idleRq->swtmrSortLink);
198 UINT16 cpuID = 1;
199 do {
200 SchedRunQue *rq = OsSchedRunQueByID(cpuID);
201 UINT32 temp = OsGetSortLinkNodeNum(&rq->taskSortLink) + OsGetSortLinkNodeNum(&rq->swtmrSortLink);
202 if (nodeNum > temp) {
203 *idleCpuID = cpuID;
204 nodeNum = temp;
205 }
206 cpuID++;
207 } while (cpuID < LOSCFG_KERNEL_CORE_NUM);
208 }
209 #endif
210
OsSchedAddTask2TimeList(SortLinkList * node,UINT64 startTime,UINT32 waitTicks)211 STATIC INLINE VOID OsSchedAddTask2TimeList(SortLinkList *node, UINT64 startTime, UINT32 waitTicks)
212 {
213 UINT16 idleCpu = 0;
214 #ifdef LOSCFG_KERNEL_SMP
215 FindIdleRunQue(&idleCpu);
216 #endif
217 SchedRunQue *rq = OsSchedRunQueByID(idleCpu);
218 UINT64 responseTime = startTime + (UINT64)waitTicks * OS_CYCLE_PER_TICK;
219 OsAdd2SortLink(&rq->taskSortLink, node, responseTime, idleCpu);
220 }
221
OsSchedSwtmrHandlerQueueGet(VOID)222 STATIC INLINE UINT32 OsSchedSwtmrHandlerQueueGet(VOID)
223 {
224 return OsSchedRunQue()->swtmrHandlerQueue;
225 }
226
OsSchedDeTaskFromTimeList(SortLinkList * node)227 STATIC INLINE VOID OsSchedDeTaskFromTimeList(SortLinkList *node)
228 {
229 #ifdef LOSCFG_KERNEL_SMP
230 SchedRunQue *rq = OsSchedRunQueByID(node->cpuid);
231 #else
232 SchedRunQue *rq = OsSchedRunQueByID(0);
233 #endif
234 OsDeleteFromSortLink(&rq->taskSortLink, node);
235 }
236
OsSchedAddSwtmr2TimeList(SortLinkList * node,UINT64 startTime,UINT32 waitTicks)237 STATIC INLINE VOID OsSchedAddSwtmr2TimeList(SortLinkList *node, UINT64 startTime, UINT32 waitTicks)
238 {
239 UINT16 idleCpu = 0;
240 #ifdef LOSCFG_KERNEL_SMP
241 FindIdleRunQue(&idleCpu);
242 #endif
243 SchedRunQue *rq = OsSchedRunQueByID(idleCpu);
244 UINT64 responseTime = startTime + (UINT64)waitTicks * OS_CYCLE_PER_TICK;
245 OsAdd2SortLink(&rq->swtmrSortLink, node, responseTime, idleCpu);
246 }
247
OsSchedDeSwtmrFromTimeList(SortLinkList * node)248 STATIC INLINE VOID OsSchedDeSwtmrFromTimeList(SortLinkList *node)
249 {
250 #ifdef LOSCFG_KERNEL_SMP
251 SchedRunQue *rq = OsSchedRunQueByID(node->cpuid);
252 #else
253 SchedRunQue *rq = OsSchedRunQueByID(0);
254 #endif
255 OsDeleteFromSortLink(&rq->swtmrSortLink, node);
256 }
257
258 VOID OsSchedRunQueIdleInit(UINT32 idleTaskID);
259 VOID OsSchedRunQueSwtmrInit(UINT32 swtmrTaskID, UINT32 swtmrQueue);
260 VOID OsSchedRunQueInit(VOID);
261 BOOL OsSchedSwtmrTimeListFind(SCHED_TL_FIND_FUNC checkFunc, UINTPTR arg);
262
263 /**
264 * @ingroup los_sched
265 * Define a usable task priority.
266 *
267 * Highest task priority.
268 */
269 #define OS_TASK_PRIORITY_HIGHEST 0
270
271 /**
272 * @ingroup los_sched
273 * Define a usable task priority.
274 *
275 * Lowest task priority.
276 */
277 #define OS_TASK_PRIORITY_LOWEST 31
278
279 /**
280 * @ingroup los_sched
281 * Flag that indicates the task or task control block status.
282 *
283 * The task is init.
284 */
285 #define OS_TASK_STATUS_INIT 0x0001U
286
287 /**
288 * @ingroup los_sched
289 * Flag that indicates the task or task control block status.
290 *
291 * The task is ready.
292 */
293 #define OS_TASK_STATUS_READY 0x0002U
294
295 /**
296 * @ingroup los_sched
297 * Flag that indicates the task or task control block status.
298 *
299 * The task is running.
300 */
301 #define OS_TASK_STATUS_RUNNING 0x0004U
302
303 /**
304 * @ingroup los_sched
305 * Flag that indicates the task or task control block status.
306 *
307 * The task is suspended.
308 */
309 #define OS_TASK_STATUS_SUSPENDED 0x0008U
310
311 /**
312 * @ingroup los_sched
313 * Flag that indicates the task or task control block status.
314 *
315 * The task is blocked.
316 */
317 #define OS_TASK_STATUS_PENDING 0x0010U
318
319 /**
320 * @ingroup los_sched
321 * Flag that indicates the task or task control block status.
322 *
323 * The task is delayed.
324 */
325 #define OS_TASK_STATUS_DELAY 0x0020U
326
327 /**
328 * @ingroup los_sched
329 * Flag that indicates the task or task control block status.
330 *
331 * The time for waiting for an event to occur expires.
332 */
333 #define OS_TASK_STATUS_TIMEOUT 0x0040U
334
335 /**
336 * @ingroup los_sched
337 * Flag that indicates the task or task control block status.
338 *
339 * The task is pend for a period of time.
340 */
341 #define OS_TASK_STATUS_PEND_TIME 0x0080U
342
343 /**
344 * @ingroup los_sched
345 * Flag that indicates the task or task control block status.
346 *
347 * The task is exit.
348 */
349 #define OS_TASK_STATUS_EXIT 0x0100U
350
351 #define OS_TCB_NAME_LEN 32
352
353 typedef struct {
354 VOID *stackPointer; /**< Task stack pointer */
355 UINT16 taskStatus; /**< Task status */
356
357 /* The scheduling */
358 UINT16 basePrio;
359 UINT16 priority; /**< Task priority */
360 UINT16 policy;
361 UINT64 startTime; /**< The start time of each phase of task */
362 UINT64 irqStartTime; /**< Interrupt start time */
363 UINT32 irqUsedTime; /**< Interrupt consumption time */
364 UINT32 initTimeSlice; /**< Task init time slice */
365 INT32 timeSlice; /**< Task remaining time slice */
366 UINT32 waitTimes; /**< Task delay time, tick number */
367 SortLinkList sortList; /**< Task sortlink node */
368
369 UINT32 stackSize; /**< Task stack size */
370 UINTPTR topOfStack; /**< Task stack top */
371 UINT32 taskID; /**< Task ID */
372 TSK_ENTRY_FUNC taskEntry; /**< Task entrance function */
373 VOID *joinRetval; /**< pthread adaption */
374 VOID *taskMux; /**< Task-held mutex */
375 VOID *taskEvent; /**< Task-held event */
376 UINTPTR args[4]; /**< Parameter, of which the maximum number is 4 */
377 CHAR taskName[OS_TCB_NAME_LEN]; /**< Task name */
378 LOS_DL_LIST pendList; /**< Task pend node */
379 LOS_DL_LIST threadList; /**< thread list */
380 UINT32 eventMask; /**< Event mask */
381 UINT32 eventMode; /**< Event mode */
382 UINT32 priBitMap; /**< BitMap for recording the change of task priority,
383 the priority can not be greater than 31 */
384 #ifdef LOSCFG_KERNEL_CPUP
385 OsCpupBase taskCpup; /**< task cpu usage */
386 #endif
387 INT32 errorNo; /**< Error Num */
388 UINT32 signal; /**< Task signal */
389 sig_cb sig;
390 #ifdef LOSCFG_KERNEL_SMP
391 UINT16 currCpu; /**< CPU core number of this task is running on */
392 UINT16 lastCpu; /**< CPU core number of this task is running on last time */
393 UINT16 cpuAffiMask; /**< CPU affinity mask, support up to 16 cores */
394 #ifdef LOSCFG_KERNEL_SMP_TASK_SYNC
395 UINT32 syncSignal; /**< Synchronization for signal handling */
396 #endif
397 #ifdef LOSCFG_KERNEL_SMP_LOCKDEP
398 LockDep lockDep;
399 #endif
400 #endif
401 #ifdef LOSCFG_SCHED_DEBUG
402 SchedStat schedStat; /**< Schedule statistics */
403 #endif
404 #ifdef LOSCFG_KERNEL_VM
405 UINTPTR archMmu;
406 UINTPTR userArea;
407 UINTPTR userMapBase;
408 UINT32 userMapSize; /**< user thread stack size ,real size : userMapSize + USER_STACK_MIN_SIZE */
409 FutexNode futex;
410 #endif
411 UINT32 processID; /**< Which belong process */
412 LOS_DL_LIST joinList; /**< join list */
413 LOS_DL_LIST lockList; /**< Hold the lock list */
414 UINTPTR waitID; /**< Wait for the PID or GID of the child process */
415 UINT16 waitFlag; /**< The type of child process that is waiting, belonging to a group or parent,
416 a specific child process, or any child process */
417 #ifdef LOSCFG_KERNEL_LITEIPC
418 IpcTaskInfo *ipcTaskInfo;
419 #endif
420 #ifdef LOSCFG_KERNEL_PERF
421 UINTPTR pc;
422 UINTPTR fp;
423 #endif
424 } LosTaskCB;
425
OsTaskIsRunning(const LosTaskCB * taskCB)426 STATIC INLINE BOOL OsTaskIsRunning(const LosTaskCB *taskCB)
427 {
428 return ((taskCB->taskStatus & OS_TASK_STATUS_RUNNING) != 0);
429 }
430
OsTaskIsReady(const LosTaskCB * taskCB)431 STATIC INLINE BOOL OsTaskIsReady(const LosTaskCB *taskCB)
432 {
433 return ((taskCB->taskStatus & OS_TASK_STATUS_READY) != 0);
434 }
435
OsTaskIsInactive(const LosTaskCB * taskCB)436 STATIC INLINE BOOL OsTaskIsInactive(const LosTaskCB *taskCB)
437 {
438 return ((taskCB->taskStatus & (OS_TASK_STATUS_INIT | OS_TASK_STATUS_EXIT)) != 0);
439 }
440
OsTaskIsPending(const LosTaskCB * taskCB)441 STATIC INLINE BOOL OsTaskIsPending(const LosTaskCB *taskCB)
442 {
443 return ((taskCB->taskStatus & OS_TASK_STATUS_PENDING) != 0);
444 }
445
OsTaskIsSuspended(const LosTaskCB * taskCB)446 STATIC INLINE BOOL OsTaskIsSuspended(const LosTaskCB *taskCB)
447 {
448 return ((taskCB->taskStatus & OS_TASK_STATUS_SUSPENDED) != 0);
449 }
450
OsTaskIsBlocked(const LosTaskCB * taskCB)451 STATIC INLINE BOOL OsTaskIsBlocked(const LosTaskCB *taskCB)
452 {
453 return ((taskCB->taskStatus & (OS_TASK_STATUS_SUSPENDED | OS_TASK_STATUS_PENDING | OS_TASK_STATUS_DELAY)) != 0);
454 }
455
OsCurrTaskGet(VOID)456 STATIC INLINE LosTaskCB *OsCurrTaskGet(VOID)
457 {
458 return (LosTaskCB *)ArchCurrTaskGet();
459 }
460
OsCurrTaskSet(LosTaskCB * task)461 STATIC INLINE VOID OsCurrTaskSet(LosTaskCB *task)
462 {
463 ArchCurrTaskSet(task);
464 }
465
OsCurrUserTaskSet(UINTPTR thread)466 STATIC INLINE VOID OsCurrUserTaskSet(UINTPTR thread)
467 {
468 ArchCurrUserTaskSet(thread);
469 }
470
OsSchedIrqUpdateUsedTime(VOID)471 STATIC INLINE VOID OsSchedIrqUpdateUsedTime(VOID)
472 {
473 LosTaskCB *runTask = OsCurrTaskGet();
474 runTask->irqUsedTime = OsGetCurrSchedTimeCycle() - runTask->irqStartTime;
475 }
476
OsSchedIrqStartTime(VOID)477 STATIC INLINE VOID OsSchedIrqStartTime(VOID)
478 {
479 LosTaskCB *runTask = OsCurrTaskGet();
480 runTask->irqStartTime = OsGetCurrSchedTimeCycle();
481 }
482
483 /*
484 * Schedule flag, one bit represents one core.
485 * This flag is used to prevent kernel scheduling before OSStartToRun.
486 */
487 #define OS_SCHEDULER_SET(cpuid) do { \
488 g_taskScheduled |= (1U << (cpuid)); \
489 } while (0);
490
491 #define OS_SCHEDULER_CLR(cpuid) do { \
492 g_taskScheduled &= ~(1U << (cpuid)); \
493 } while (0);
494
495 VOID OsSchedSetIdleTaskSchedParam(LosTaskCB *idleTask);
496 VOID OsSchedResetSchedResponseTime(UINT64 responseTime);
497 VOID OsSchedUpdateExpireTime(VOID);
498 VOID OsSchedToUserReleaseLock(VOID);
499 VOID OsSchedTaskDeQueue(LosTaskCB *taskCB);
500 VOID OsSchedTaskEnQueue(LosTaskCB *taskCB);
501 UINT32 OsSchedTaskWait(LOS_DL_LIST *list, UINT32 timeout, BOOL needSched);
502 VOID OsSchedTaskWake(LosTaskCB *resumedTask);
503 BOOL OsSchedModifyTaskSchedParam(LosTaskCB *taskCB, UINT16 policy, UINT16 priority);
504 BOOL OsSchedModifyProcessSchedParam(UINT32 pid, UINT16 policy, UINT16 priority);
505 VOID OsSchedSuspend(LosTaskCB *taskCB);
506 BOOL OsSchedResume(LosTaskCB *taskCB);
507 VOID OsSchedDelay(LosTaskCB *runTask, UINT32 tick);
508 VOID OsSchedYield(VOID);
509 VOID OsSchedTaskExit(LosTaskCB *taskCB);
510 VOID OsSchedTick(VOID);
511 UINT32 OsSchedInit(VOID);
512 VOID OsSchedStart(VOID);
513
514 /*
515 * This function simply picks the next task and switches to it.
516 * Current task needs to already be in the right state or the right
517 * queues it needs to be in.
518 */
519 VOID OsSchedResched(VOID);
520 VOID OsSchedIrqEndCheckNeedSched(VOID);
521
522 /*
523 * This function inserts the runTask to the lock pending list based on the
524 * task priority.
525 */
526 LOS_DL_LIST *OsSchedLockPendFindPos(const LosTaskCB *runTask, LOS_DL_LIST *lockList);
527
528 #ifdef LOSCFG_SCHED_TICK_DEBUG
529 VOID OsSchedDebugRecordData(VOID);
530 #endif
531
532 UINT32 OsShellShowTickRespo(VOID);
533
534 UINT32 OsShellShowSchedParam(VOID);
535
536 #ifdef __cplusplus
537 #if __cplusplus
538 }
539 #endif /* __cplusplus */
540 #endif /* __cplusplus */
541
542 #endif /* _LOS_SCHED_PRI_H */
543