SRTOS
Loading...
Searching...
No Matches
task.c
Go to the documentation of this file.
1
7
8#include "task.h"
9
10volatile uint32_t msTicks = 0;
13
14static uint32_t prvCurTaskIDNum = 0;
15static TaskNode *prvNextTask = NULL;
16static TaskNode *prvBlockedTasks = NULL;
17static uint32_t idleTaskStack[STACK_SIZE];
18static TCB idleTaskTCB;
19static TCB *idleTaskTCBptr = &idleTaskTCB;
20static TaskNode idleTaskNode;
21static TaskNode *prvIdleTask;
22static TaskNode *idleTaskNodePtr = &idleTaskNode;
23
24static STATUS prvAddTaskNodeToReadyList (TaskNode *task);
25static TaskNode *prvGetHighestTaskReadyToExecute ();
26static void prvAddTaskToBlockedList (TaskNode *task);
27static void prvUnblockDelayedTasksReadyToUnblock ();
28static TaskNode *createIdleTask ();
29static void idleTask ();
30static void prvCheckCurTaskForStackOverflow ();
31
45uint32_t *
46initTaskStackFrame (uint32_t taskStack[], void (*taskFunc) (void))
47{
48 for (int i = 0; i < STACK_SIZE; ++i)
49 {
50 taskStack[i] = STACK_USAGE_WATERMARK;
51 }
52
53 taskStack[0] = STACK_OVERFLOW_CANARY_VALUE;
54 taskStack[1] = STACK_OVERFLOW_CANARY_VALUE;
55
56 taskStack[STACK_SIZE - 1] = 0x01000000; /* xPSR */
57 taskStack[STACK_SIZE - 2] = ((uint32_t)taskFunc) | 0x1; /* PC */
58 taskStack[STACK_SIZE - 3] = 0xFFFFFFFD; /* LR */
59 taskStack[STACK_SIZE - 4] = 0x00000000; /* R12 */
60 taskStack[STACK_SIZE - 5] = 0x00000000; /* R3 */
61 taskStack[STACK_SIZE - 6] = 0x00000000; /* R2 */
62 taskStack[STACK_SIZE - 7] = 0x00000000; /* R1 */
63 taskStack[STACK_SIZE - 8] = 0x00000000; /* R0 */
64 taskStack[STACK_SIZE - 9] = 0x00000000; /* R11 */
65 taskStack[STACK_SIZE - 10] = 0x00000000; /* R10 */
66 taskStack[STACK_SIZE - 11] = 0x00000000; /* R9 */
67 taskStack[STACK_SIZE - 12] = 0x00000000; /* R8 */
68 taskStack[STACK_SIZE - 13] = 0x00000000; /* R7 */
69 taskStack[STACK_SIZE - 14] = 0x00000000; /* R6 */
70 taskStack[STACK_SIZE - 15] = 0x00000000; /* R5 */
71 taskStack[STACK_SIZE - 16] = 0x00000000; /* R4 */
72
73 return &taskStack[STACK_SIZE - 16];
74}
75
77createTask (uint32_t taskStack[], void (*taskFunc) (void),
78 unsigned int priority, TCB *userAllocatedTCB,
79 TaskNode *userAllocatedTaskNode)
80{
81 if (!taskFunc || !userAllocatedTCB || !userAllocatedTaskNode)
82 return STATUS_FAILURE;
83 if (priority >= MAX_PRIORITIES)
84 return STATUS_FAILURE;
85 if (STACK_SIZE < 18)
86 return STATUS_FAILURE;
87
88 userAllocatedTCB->sp = initTaskStackFrame (taskStack, taskFunc);
89 userAllocatedTCB->priority = priority;
90 userAllocatedTCB->id = prvCurTaskIDNum;
91 prvCurTaskIDNum++;
92 userAllocatedTCB->stackFrameLowerBoundAddr = &taskStack[0];
93
94 /* Insert at end of tasks linked list */
95 userAllocatedTaskNode->taskTCB = userAllocatedTCB;
96 userAllocatedTaskNode->next = NULL;
97
98 STATUS resStatus;
100 {
101 resStatus = prvAddTaskNodeToReadyList (userAllocatedTaskNode);
102 }
104
105 return resStatus;
106}
107
114void
116{
117 msTicks++;
118
119 prvUnblockDelayedTasksReadyToUnblock ();
120
121 if (curTask == NULL)
122 {
123 return;
124 }
125
126 uint32_t curExecutingPriority = curTask->taskTCB->priority;
127
128 TaskNode *highestPriorityPossibleExecute
129 = prvGetHighestTaskReadyToExecute ();
130
131 /* Check if a higher priority task is ready to execute */
132 if (curExecutingPriority < highestPriorityPossibleExecute->taskTCB->priority)
133 {
134 prvNextTask = highestPriorityPossibleExecute;
136 return;
137 }
138
139 if (curTask->next == NULL)
140 {
141 if (highestPriorityPossibleExecute->taskTCB->id != curTask->taskTCB->id)
142 {
143 /* There is another task of equal priority, time to switch. */
144 prvNextTask = highestPriorityPossibleExecute;
146 return;
147 }
148 }
149 else
150 {
151 /* There is another task of equal priority, time to switch. */
152 prvNextTask = curTask->next;
154 return;
155 }
156}
157
165void
167{
168 prvCheckCurTaskForStackOverflow ();
169
170 uint32_t spToSave;
171 __asm volatile ("mrs r0, PSP\n"
172 "stmdb r0!, {r4-r11}\n"
173 "mov %[spToSave], r0\n"
174 : [spToSave] "=r"(spToSave));
175
176 curTask->taskTCB->sp = (uint32_t *)spToSave;
177
178 uint32_t nextSP;
180 {
181 nextSP = (uint32_t)prvNextTask->taskTCB->sp;
182 curTask = prvNextTask;
183 }
185
186 __asm volatile ("mov r2, %[nextSP]\n"
187 "ldmia r2!, {r4-r11}\n"
188 "msr PSP, r2\n"
189 :
190 : [nextSP] "r"(nextSP));
191
192 __asm volatile ("ldr lr, =0xFFFFFFFD\n"
193 "bx lr\n");
194}
195
202void
204{
205 TCB *tcbToStart = curTask->taskTCB;
206 uint32_t spToStart = (uint32_t)tcbToStart->sp;
207
208 __asm volatile ("ldr r0, %[sp]\n"
209 "ldmia r0!, {r4-r11}\n"
210 "msr PSP, r0\n"
211 "ldr lr, =0xFFFFFFFD\n"
212 "bx lr\n"
213 :
214 : [sp] "m"(spToStart));
215}
216
217void
219{
220 prvIdleTask = createIdleTask ();
221 curTask = prvGetHighestTaskReadyToExecute ();
222 __asm volatile ("svc #0");
223}
224
230void
232{
233 ICSR |= (1 << 28);
234}
235
236void
237taskDelay (uint32_t ticksToDelay)
238{
240 {
241 uint32_t curTaskID = curTask->taskTCB->id;
242 uint32_t curTaskPriority = curTask->taskTCB->priority;
243
244 curTask->taskTCB->delayedUntil = msTicks + ticksToDelay;
245
246 /* Remove the task from the ready list */
247 TaskNode *cur = readyTasksList[curTaskPriority];
248 TaskNode *prev = NULL;
249
250 if (cur->next == NULL)
251 {
252 /* This is the only task for this priority, and it must be curTask */
253 readyTasksList[curTaskPriority] = NULL;
254 prvNextTask = prvGetHighestTaskReadyToExecute ();
255 prvAddTaskToBlockedList (curTask);
258 return;
259 }
260
261 /* Check if curTask is the head of the priority */
262 if (cur->taskTCB->id == curTaskID)
263 {
264 readyTasksList[curTaskPriority] = curTask->next;
265
266 prvNextTask = prvGetHighestTaskReadyToExecute ();
267 prvAddTaskToBlockedList (curTask);
270 return;
271 }
272
273 /* There is more than one task for the current priority */
274 while (cur->taskTCB->id != curTaskID)
275 {
276 prev = cur;
277 cur = cur->next;
278 }
279
280 TaskNode *afterCur = cur->next;
281 prev->next = afterCur;
282
283 prvNextTask = prvGetHighestTaskReadyToExecute ();
284 prvAddTaskToBlockedList (curTask);
285 }
288}
289
299static STATUS
300prvAddTaskNodeToReadyList (TaskNode *task)
301{
302 /* Safeguards */
303 if (task->taskTCB->priority >= MAX_PRIORITIES)
304 {
305 return STATUS_FAILURE;
306 }
307
308 task->next = NULL;
309
310 uint32_t curPriority = task->taskTCB->priority;
311
312 TaskNode *curHead = readyTasksList[curPriority];
313
314 if (curHead == NULL)
315 {
316 /* This is the first node for this priority */
317 readyTasksList[curPriority] = task;
318 return STATUS_SUCCESS;
319 }
320
321 /* Get to the end of the LL */
322 while (curHead->next != NULL)
323 {
324 curHead = curHead->next;
325 }
326
327 curHead->next = task;
328 return STATUS_SUCCESS;
329}
330
338static TaskNode *
339prvGetHighestTaskReadyToExecute ()
340{
341 int idx = MAX_PRIORITIES - 1;
342
343 while (idx >= 0)
344 {
345 if (readyTasksList[idx] != NULL)
346 {
347 return readyTasksList[idx];
348 }
349 --idx;
350 }
351
352 return prvIdleTask;
353}
354
362static void
363prvAddTaskToBlockedList (TaskNode *task)
364{
365 task->next = NULL;
366
367 if (prvBlockedTasks == NULL)
368 {
369 prvBlockedTasks = task;
370 return;
371 }
372
373 TaskNode *cur = prvBlockedTasks;
374
375 while (cur->next != NULL)
376 {
377 cur = cur->next;
378 }
379
380 cur->next = task;
381}
382
390static void
391prvUnblockDelayedTasksReadyToUnblock ()
392{
393 TaskNode *cur = prvBlockedTasks;
394 TaskNode *prev = NULL;
395
396 if (cur == NULL)
397 {
398 return;
399 }
400
401 if (cur->next == NULL)
402 {
403 if (cur->taskTCB->delayedUntil == msTicks)
404 {
405 prvBlockedTasks = NULL;
406 prvAddTaskNodeToReadyList (cur);
407 return;
408 }
409 }
410
411 while (cur != NULL)
412 {
413 TaskNode *tempNext = cur->next;
414 if (cur->taskTCB->delayedUntil == msTicks)
415 {
416 if (prev == NULL)
417 {
418 prvBlockedTasks = cur->next;
419 prvAddTaskNodeToReadyList (cur);
420 }
421 else
422 {
423 prev->next = cur->next;
424 prvAddTaskNodeToReadyList (cur);
425 }
426 }
427 else
428 {
429 prev = cur;
430 }
431 cur = tempNext;
432 }
433}
434
442static TaskNode *
443createIdleTask ()
444{
445 idleTaskTCBptr->sp = initTaskStackFrame (idleTaskStack, &idleTask);
446 idleTaskTCBptr->priority = 0;
447 idleTaskTCBptr->id = prvCurTaskIDNum;
448 idleTaskTCBptr->stackFrameLowerBoundAddr = &idleTaskStack[0];
449 idleTaskNodePtr->taskTCB = idleTaskTCBptr;
450 idleTaskNodePtr->next = NULL;
451 prvCurTaskIDNum++;
452
453 return idleTaskNodePtr;
454}
455
461static void
462idleTask ()
463{
464 for (;;)
465 {
466 __asm volatile ("wfi");
467 }
468}
469
477static void
478prvCheckCurTaskForStackOverflow ()
479{
480 uint32_t *curTaskStackFrameLowerBound;
482 {
483 curTaskStackFrameLowerBound = curTask->taskTCB->stackFrameLowerBoundAddr;
484 }
486
487 if ((*curTaskStackFrameLowerBound != STACK_OVERFLOW_CANARY_VALUE)
488 || (*(curTaskStackFrameLowerBound + 1) != STACK_OVERFLOW_CANARY_VALUE))
489 {
491 }
492}
493
494void __attribute__ ((weak))
496{
497 for (;;)
498 {
499 }
500}
501
502uint32_t
504{
505 uint32_t *curTaskStackFrameLowerBound;
507 {
508 curTaskStackFrameLowerBound = curTask->taskTCB->stackFrameLowerBoundAddr;
509 }
511
512 curTaskStackFrameLowerBound
513 += 2; /* Skip the 2 canary values (assumes no stack overflow) */
514
515 uint32_t amtWordsAvailable = 0;
516
517 while (*(curTaskStackFrameLowerBound) == STACK_USAGE_WATERMARK)
518 {
519 curTaskStackFrameLowerBound++;
520 amtWordsAvailable++;
521 }
522
523 return amtWordsAvailable;
524}
#define STACK_SIZE
Default stack size for each task, in 32-bit words.
#define MAX_PRIORITIES
Number of unique task priority levels supported by the scheduler.
#define STACK_OVERFLOW_CANARY_VALUE
Definition mcu_macros.h:26
#define STACK_USAGE_WATERMARK
Definition mcu_macros.h:27
#define ICSR
Definition mcu_macros.h:22
This struct is the Task Control Block (TCB), which is what stores a task's properties.
Definition task.h:31
uint32_t priority
Definition task.h:33
uint32_t delayedUntil
Definition task.h:35
uint32_t * sp
Definition task.h:32
uint32_t id
Definition task.h:34
uint32_t * stackFrameLowerBoundAddr
Definition task.h:36
TCB * taskTCB
Definition task.h:46
TaskNode * next
Definition task.h:47
void systemEXIT_CRITICAL()
Exit a critical section by enabling all interrupts.
void systemENTER_CRITICAL()
Enter a critical section by disabling all interrupts.
volatile uint32_t msTicks
msTicks contains the amount of ticks that have occured since the scheduler started.
Definition task.c:10
void taskDelay(uint32_t ticksToDelay)
This function will delay a task's execution for ticksToDelay ms.
Definition task.c:237
uint32_t * initTaskStackFrame(uint32_t taskStack[], void(*taskFunc)(void))
Initializes a task's stack frame.
Definition task.c:46
void __attribute__((weak))
Definition task.c:494
void startScheduler()
Start the scheduler.
Definition task.c:218
void PendSV_Handler()
This interrupt will be pended when a context switch is needed.
Definition task.c:166
void SVC_Handler()
This interrupt will be executed when the scheduler is started.
Definition task.c:203
void SysTick_Handler()
This interrupt handler will be called every 1 ms, checking if any tasks need to be unblocked or block...
Definition task.c:115
uint32_t getCurTaskWordsAvailable()
This function will return the minimum number of words left on the stack.
Definition task.c:503
TaskNode * readyTasksList[MAX_PRIORITIES]
This is a list of linked lists that contain the ready tasks.
Definition task.c:12
TaskNode * curTask
Definition task.c:11
void setPendSVPending()
This function will be called when a context-switch is needed.
Definition task.c:231
STATUS createTask(uint32_t taskStack[], void(*taskFunc)(void), unsigned int priority, TCB *userAllocatedTCB, TaskNode *userAllocatedTaskNode)
Add a task to the scheduler's ready list.
Definition task.c:77
Task management and scheduler API for SRTOS.
STATUS
This enum is used to indicate whether an operation was sucessful or not.
Definition task.h:22
@ STATUS_FAILURE
Definition task.h:24
@ STATUS_SUCCESS
Definition task.h:23
void handleStackOverflow()
This function will be called when a stack overflow is detected. This function will only be called if ...