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