• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification,
5  * are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice, this list of
8  *    conditions and the following disclaimer.
9  *
10  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11  *    of conditions and the following disclaimer in the documentation and/or other materials
12  *    provided with the distribution.
13  *
14  * 3. Neither the name of the copyright holder nor the names of its contributors may be used
15  *    to endorse or promote products derived from this software without specific prior written
16  *    permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "los_sched_pri.h"
32 #include "los_task_pri.h"
33 #include "los_process_pri.h"
34 #include "los_hook.h"
35 #include "los_tick_pri.h"
36 #include "los_sys_pri.h"
37 
38 STATIC EDFRunqueue g_schedEDF;
39 
40 STATIC VOID EDFDequeue(SchedRunqueue *rq, LosTaskCB *taskCB);
41 STATIC VOID EDFEnqueue(SchedRunqueue *rq, LosTaskCB *taskCB);
42 STATIC UINT64 EDFWaitTimeGet(LosTaskCB *taskCB);
43 STATIC UINT32 EDFWait(LosTaskCB *runTask, LOS_DL_LIST *list, UINT32 ticks);
44 STATIC VOID EDFWake(LosTaskCB *resumedTask);
45 STATIC BOOL EDFSchedParamModify(LosTaskCB *taskCB, const SchedParam *param);
46 STATIC UINT32 EDFSchedParamGet(const LosTaskCB *taskCB, SchedParam *param);
47 STATIC UINT32 EDFDelay(LosTaskCB *runTask, UINT64 waitTime);
48 STATIC VOID EDFYield(LosTaskCB *runTask);
49 STATIC VOID EDFExit(LosTaskCB *taskCB);
50 STATIC UINT32 EDFSuspend(LosTaskCB *taskCB);
51 STATIC UINT32 EDFResume(LosTaskCB *taskCB, BOOL *needSched);
52 STATIC UINT64 EDFTimeSliceGet(const LosTaskCB *taskCB);
53 STATIC VOID EDFTimeSliceUpdate(SchedRunqueue *rq, LosTaskCB *taskCB, UINT64 currTime);
54 STATIC INT32 EDFParamCompare(const SchedPolicy *sp1, const SchedPolicy *sp2);
55 STATIC VOID EDFPriorityInheritance(LosTaskCB *owner, const SchedParam *param);
56 STATIC VOID EDFPriorityRestore(LosTaskCB *owner, const LOS_DL_LIST *list, const SchedParam *param);
57 
58 const STATIC SchedOps g_deadlineOps = {
59     .dequeue = EDFDequeue,
60     .enqueue = EDFEnqueue,
61     .waitTimeGet = EDFWaitTimeGet,
62     .wait = EDFWait,
63     .wake = EDFWake,
64     .schedParamModify = EDFSchedParamModify,
65     .schedParamGet = EDFSchedParamGet,
66     .delay = EDFDelay,
67     .yield = EDFYield,
68     .start = EDFDequeue,
69     .exit = EDFExit,
70     .suspend = EDFSuspend,
71     .resume = EDFResume,
72     .deadlineGet = EDFTimeSliceGet,
73     .timeSliceUpdate = EDFTimeSliceUpdate,
74     .schedParamCompare = EDFParamCompare,
75     .priorityInheritance = EDFPriorityInheritance,
76     .priorityRestore = EDFPriorityRestore,
77 };
78 
EDFTimeSliceUpdate(SchedRunqueue * rq,LosTaskCB * taskCB,UINT64 currTime)79 STATIC VOID EDFTimeSliceUpdate(SchedRunqueue *rq, LosTaskCB *taskCB, UINT64 currTime)
80 {
81     SchedEDF *sched = (SchedEDF *)&taskCB->sp;
82 
83     LOS_ASSERT(currTime >= taskCB->startTime);
84 
85     if (taskCB->timeSlice <= 0) {
86         taskCB->irqUsedTime = 0;
87         return;
88     }
89 
90     INT32 incTime = (currTime - taskCB->startTime - taskCB->irqUsedTime);
91     LOS_ASSERT(incTime >= 0);
92 
93 #ifdef LOSCFG_SCHED_EDF_DEBUG
94     taskCB->schedStat.timeSliceRealTime += incTime;
95     taskCB->schedStat.allRuntime += (currTime - taskCB->startTime);
96 #endif
97 
98     taskCB->timeSlice -= incTime;
99     taskCB->irqUsedTime = 0;
100     taskCB->startTime = currTime;
101 
102     if ((sched->finishTime > currTime) && (taskCB->timeSlice > 0)) {
103         return;
104     }
105 
106     rq->schedFlag |= INT_PEND_RESCH;
107     if (sched->finishTime <= currTime) {
108 #ifdef LOSCFG_SCHED_EDF_DEBUG
109         EDFDebugRecord((UINTPTR *)taskCB, sched->finishTime);
110 #endif
111 
112         taskCB->timeSlice = 0;
113         PrintExcInfo("EDF task %u is timeout, runTime: %d us period: %llu us\n", taskCB->taskID,
114                      (INT32)OS_SYS_CYCLE_TO_US((UINT64)sched->runTime), OS_SYS_CYCLE_TO_US(sched->period));
115     }
116 }
117 
EDFTimeSliceGet(const LosTaskCB * taskCB)118 STATIC UINT64 EDFTimeSliceGet(const LosTaskCB *taskCB)
119 {
120     SchedEDF *sched = (SchedEDF *)&taskCB->sp;
121     UINT64 endTime = taskCB->startTime + taskCB->timeSlice;
122     return (endTime > sched->finishTime) ? sched->finishTime : endTime;
123 }
124 
DeadlineQueueInsert(EDFRunqueue * rq,LosTaskCB * taskCB)125 STATIC VOID DeadlineQueueInsert(EDFRunqueue *rq, LosTaskCB *taskCB)
126 {
127     LOS_DL_LIST *root = &rq->root;
128     if (LOS_ListEmpty(root)) {
129         LOS_ListTailInsert(root, &taskCB->pendList);
130         return;
131     }
132 
133     LOS_DL_LIST *list = root->pstNext;
134     do {
135         LosTaskCB *readyTask = LOS_DL_LIST_ENTRY(list, LosTaskCB, pendList);
136         if (EDFParamCompare(&readyTask->sp, &taskCB->sp) > 0) {
137             LOS_ListHeadInsert(list, &taskCB->pendList);
138             return;
139         }
140         list = list->pstNext;
141     } while (list != root);
142 
143     LOS_ListHeadInsert(list, &taskCB->pendList);
144 }
145 
EDFEnqueue(SchedRunqueue * rq,LosTaskCB * taskCB)146 STATIC VOID EDFEnqueue(SchedRunqueue *rq, LosTaskCB *taskCB)
147 {
148     LOS_ASSERT(!(taskCB->taskStatus & OS_TASK_STATUS_READY));
149 
150     EDFRunqueue *erq = rq->edfRunqueue;
151     SchedEDF *sched = (SchedEDF *)&taskCB->sp;
152     if (taskCB->timeSlice <= 0) {
153 #ifdef LOSCFG_SCHED_EDF_DEBUG
154         UINT64 oldFinish = sched->finishTime;
155 #endif
156         UINT64 currTime = OsGetCurrSchedTimeCycle();
157         if (sched->flags == EDF_INIT) {
158             sched->finishTime = currTime;
159         } else if (sched->flags != EDF_NEXT_PERIOD) {
160             /* The start time of the next period */
161             sched->finishTime = (sched->finishTime - sched->deadline) + sched->period;
162         }
163 
164         /* Calculate the start time of the next period */
165         while (1) {
166             /* The deadline of the next period */
167             UINT64 finishTime = sched->finishTime + sched->deadline;
168             if ((finishTime <= currTime) || ((sched->finishTime + sched->runTime) > finishTime)) {
169                 /* This period cannot meet the minimum running time, so it is migrated to the next period */
170                 sched->finishTime += sched->period;
171                 continue;
172             }
173             break;
174         }
175 
176         if (sched->finishTime > currTime) {
177             /* Wait for the next period to start */
178             LOS_ListTailInsert(&erq->waitList, &taskCB->pendList);
179             taskCB->waitTime = OS_SCHED_MAX_RESPONSE_TIME;
180             if (!OsTaskIsRunning(taskCB)) {
181                 OsSchedTimeoutQueueAdd(taskCB, sched->finishTime);
182             }
183 #ifdef LOSCFG_SCHED_EDF_DEBUG
184             if (oldFinish != sched->finishTime) {
185                 EDFDebugRecord((UINTPTR *)taskCB, oldFinish);
186                 taskCB->schedStat.allRuntime = 0;
187                 taskCB->schedStat.timeSliceRealTime = 0;
188                 taskCB->schedStat.pendTime = 0;
189             }
190 #endif
191             taskCB->taskStatus |= OS_TASK_STATUS_PEND_TIME;
192             sched->flags = EDF_NEXT_PERIOD;
193             return;
194         }
195 
196         sched->finishTime += sched->deadline;
197         taskCB->timeSlice = sched->runTime;
198         sched->flags = EDF_UNUSED;
199     }
200 
201     DeadlineQueueInsert(erq, taskCB);
202     taskCB->taskStatus &= ~(OS_TASK_STATUS_BLOCKED | OS_TASK_STATUS_TIMEOUT);
203     taskCB->taskStatus |= OS_TASK_STATUS_READY;
204 }
205 
EDFDequeue(SchedRunqueue * rq,LosTaskCB * taskCB)206 STATIC VOID EDFDequeue(SchedRunqueue *rq, LosTaskCB *taskCB)
207 {
208     (VOID)rq;
209     LOS_ListDelete(&taskCB->pendList);
210     taskCB->taskStatus &= ~OS_TASK_STATUS_READY;
211 }
212 
EDFExit(LosTaskCB * taskCB)213 STATIC VOID EDFExit(LosTaskCB *taskCB)
214 {
215     if (taskCB->taskStatus & OS_TASK_STATUS_READY) {
216         EDFDequeue(OsSchedRunqueue(), taskCB);
217     } else if (taskCB->taskStatus & OS_TASK_STATUS_PENDING) {
218         LOS_ListDelete(&taskCB->pendList);
219         taskCB->taskStatus &= ~OS_TASK_STATUS_PENDING;
220     }
221     if (taskCB->taskStatus & (OS_TASK_STATUS_DELAY | OS_TASK_STATUS_PEND_TIME)) {
222         OsSchedTimeoutQueueDelete(taskCB);
223         taskCB->taskStatus &= ~(OS_TASK_STATUS_DELAY | OS_TASK_STATUS_PEND_TIME);
224     }
225 }
226 
EDFYield(LosTaskCB * runTask)227 STATIC VOID EDFYield(LosTaskCB *runTask)
228 {
229     SchedRunqueue *rq = OsSchedRunqueue();
230     runTask->timeSlice = 0;
231 
232     runTask->startTime = OsGetCurrSchedTimeCycle();
233     EDFEnqueue(rq, runTask);
234     OsSchedResched();
235 }
236 
EDFDelay(LosTaskCB * runTask,UINT64 waitTime)237 STATIC UINT32 EDFDelay(LosTaskCB *runTask, UINT64 waitTime)
238 {
239     runTask->taskStatus |= OS_TASK_STATUS_DELAY;
240     runTask->waitTime = waitTime;
241     OsSchedResched();
242     return LOS_OK;
243 }
244 
EDFWaitTimeGet(LosTaskCB * taskCB)245 STATIC UINT64 EDFWaitTimeGet(LosTaskCB *taskCB)
246 {
247     const SchedEDF *sched = (const SchedEDF *)&taskCB->sp;
248     if (sched->flags != EDF_WAIT_FOREVER) {
249         taskCB->waitTime += taskCB->startTime;
250     }
251     return (taskCB->waitTime >= sched->finishTime) ? sched->finishTime : taskCB->waitTime;
252 }
253 
EDFWait(LosTaskCB * runTask,LOS_DL_LIST * list,UINT32 ticks)254 STATIC UINT32 EDFWait(LosTaskCB *runTask, LOS_DL_LIST *list, UINT32 ticks)
255 {
256     SchedEDF *sched = (SchedEDF *)&runTask->sp;
257     runTask->taskStatus |= (OS_TASK_STATUS_PENDING | OS_TASK_STATUS_PEND_TIME);
258     LOS_ListTailInsert(list, &runTask->pendList);
259 
260     if (ticks != LOS_WAIT_FOREVER) {
261         runTask->waitTime = OS_SCHED_TICK_TO_CYCLE(ticks);
262     } else {
263         sched->flags = EDF_WAIT_FOREVER;
264         runTask->waitTime = OS_SCHED_MAX_RESPONSE_TIME;
265     }
266 
267     if (OsPreemptableInSched()) {
268         OsSchedResched();
269         if (runTask->taskStatus & OS_TASK_STATUS_TIMEOUT) {
270             runTask->taskStatus &= ~OS_TASK_STATUS_TIMEOUT;
271             return LOS_ERRNO_TSK_TIMEOUT;
272         }
273     }
274 
275     return LOS_OK;
276 }
277 
EDFWake(LosTaskCB * resumedTask)278 STATIC VOID EDFWake(LosTaskCB *resumedTask)
279 {
280     LOS_ListDelete(&resumedTask->pendList);
281     resumedTask->taskStatus &= ~OS_TASK_STATUS_PENDING;
282 
283     if (resumedTask->taskStatus & OS_TASK_STATUS_PEND_TIME) {
284         OsSchedTimeoutQueueDelete(resumedTask);
285         resumedTask->taskStatus &= ~OS_TASK_STATUS_PEND_TIME;
286     }
287 
288     if (!(resumedTask->taskStatus & OS_TASK_STATUS_SUSPENDED)) {
289 #ifdef LOSCFG_SCHED_EDF_DEBUG
290         resumedTask->schedStat.pendTime += OsGetCurrSchedTimeCycle() - resumedTask->startTime;
291         resumedTask->schedStat.pendCount++;
292 #endif
293         EDFEnqueue(OsSchedRunqueue(), resumedTask);
294     }
295 }
296 
EDFSchedParamModify(LosTaskCB * taskCB,const SchedParam * param)297 STATIC BOOL EDFSchedParamModify(LosTaskCB *taskCB, const SchedParam *param)
298 {
299     SchedRunqueue *rq = OsSchedRunqueue();
300     SchedEDF *sched = (SchedEDF *)&taskCB->sp;
301 
302     taskCB->timeSlice = 0;
303     sched->runTime = (INT32)OS_SYS_US_TO_CYCLE(param->runTimeUs);
304     sched->period = OS_SYS_US_TO_CYCLE(param->periodUs);
305 
306     if (taskCB->taskStatus & OS_TASK_STATUS_READY) {
307         EDFDequeue(rq, taskCB);
308         sched->deadline = OS_SYS_US_TO_CYCLE(param->deadlineUs);
309         EDFEnqueue(rq, taskCB);
310         return TRUE;
311     }
312 
313     sched->deadline = OS_SYS_US_TO_CYCLE(param->deadlineUs);
314     if (taskCB->taskStatus & OS_TASK_STATUS_INIT) {
315         EDFEnqueue(rq, taskCB);
316         return TRUE;
317     }
318 
319     if (taskCB->taskStatus & OS_TASK_STATUS_RUNNING) {
320         return TRUE;
321     }
322 
323     return FALSE;
324 }
325 
EDFSchedParamGet(const LosTaskCB * taskCB,SchedParam * param)326 STATIC UINT32 EDFSchedParamGet(const LosTaskCB *taskCB, SchedParam *param)
327 {
328     SchedEDF *sched = (SchedEDF *)&taskCB->sp;
329     param->policy = sched->policy;
330     param->runTimeUs = (INT32)OS_SYS_CYCLE_TO_US((UINT64)sched->runTime);
331     param->deadlineUs = OS_SYS_CYCLE_TO_US(sched->deadline);
332     param->periodUs = OS_SYS_CYCLE_TO_US(sched->period);
333     return LOS_OK;
334 }
335 
EDFSuspend(LosTaskCB * taskCB)336 STATIC UINT32 EDFSuspend(LosTaskCB *taskCB)
337 {
338     return LOS_EOPNOTSUPP;
339 }
340 
EDFResume(LosTaskCB * taskCB,BOOL * needSched)341 STATIC UINT32 EDFResume(LosTaskCB *taskCB, BOOL *needSched)
342 {
343     return LOS_EOPNOTSUPP;
344 }
345 
EDFParamCompare(const SchedPolicy * sp1,const SchedPolicy * sp2)346 STATIC INT32 EDFParamCompare(const SchedPolicy *sp1, const SchedPolicy *sp2)
347 {
348     const SchedEDF *param1 = (const SchedEDF *)sp1;
349     const SchedEDF *param2 = (const SchedEDF *)sp2;
350 
351     return (INT32)(param1->finishTime - param2->finishTime);
352 }
353 
EDFPriorityInheritance(LosTaskCB * owner,const SchedParam * param)354 STATIC VOID EDFPriorityInheritance(LosTaskCB *owner, const SchedParam *param)
355 {
356     (VOID)owner;
357     (VOID)param;
358 }
359 
EDFPriorityRestore(LosTaskCB * owner,const LOS_DL_LIST * list,const SchedParam * param)360 STATIC VOID EDFPriorityRestore(LosTaskCB *owner, const LOS_DL_LIST *list, const SchedParam *param)
361 {
362     (VOID)owner;
363     (VOID)list;
364     (VOID)param;
365 }
366 
EDFTaskSchedParamInit(LosTaskCB * taskCB,UINT16 policy,const SchedParam * parentParam,const LosSchedParam * param)367 UINT32 EDFTaskSchedParamInit(LosTaskCB *taskCB, UINT16 policy,
368                              const SchedParam *parentParam,
369                              const LosSchedParam *param)
370 {
371     (VOID)parentParam;
372     SchedEDF *sched = (SchedEDF *)&taskCB->sp;
373     sched->flags = EDF_INIT;
374     sched->policy = policy;
375     sched->runTime = (INT32)OS_SYS_US_TO_CYCLE((UINT64)param->runTimeUs);
376     sched->deadline = OS_SYS_US_TO_CYCLE(param->deadlineUs);
377     sched->period = OS_SYS_US_TO_CYCLE(param->periodUs);
378     sched->finishTime = 0;
379     taskCB->timeSlice = 0;
380     taskCB->ops = &g_deadlineOps;
381     return LOS_OK;
382 }
383 
EDFProcessDefaultSchedParamGet(SchedParam * param)384 VOID EDFProcessDefaultSchedParamGet(SchedParam *param)
385 {
386     param->runTimeUs = OS_SCHED_EDF_MIN_RUNTIME;
387     param->deadlineUs = OS_SCHED_EDF_MAX_DEADLINE;
388     param->periodUs = param->deadlineUs;
389 }
390 
EDFSchedPolicyInit(SchedRunqueue * rq)391 VOID EDFSchedPolicyInit(SchedRunqueue *rq)
392 {
393     if (ArchCurrCpuid() > 0) {
394         rq->edfRunqueue = &g_schedEDF;
395         return;
396     }
397 
398     EDFRunqueue *erq = &g_schedEDF;
399     erq->period = OS_SCHED_MAX_RESPONSE_TIME;
400     LOS_ListInit(&erq->root);
401     LOS_ListInit(&erq->waitList);
402     rq->edfRunqueue = erq;
403 }
404