· 8 years ago · Dec 26, 2017, 12:52 PM
1/*
2 FreeRTOS V8.2.3 - Copyright (C) 2015 Real Time Engineers Ltd.
3 All rights reserved
4
5 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
6
7 This file is part of the FreeRTOS distribution.
8
9 FreeRTOS is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License (version 2) as published by the
11 Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
12
13 ***************************************************************************
14 >>! NOTE: The modification to the GPL is included to allow you to !<<
15 >>! distribute a combined work that includes FreeRTOS without being !<<
16 >>! obliged to provide the source code for proprietary components !<<
17 >>! outside of the FreeRTOS kernel. !<<
18 ***************************************************************************
19
20 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
21 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
22 FOR A PARTICULAR PURPOSE. Full license text is available on the following
23 link: http://www.freertos.org/a00114.html
24
25 ***************************************************************************
26 * *
27 * FreeRTOS provides completely free yet professionally developed, *
28 * robust, strictly quality controlled, supported, and cross *
29 * platform software that is more than just the market leader, it *
30 * is the industry's de facto standard. *
31 * *
32 * Help yourself get started quickly while simultaneously helping *
33 * to support the FreeRTOS project by purchasing a FreeRTOS *
34 * tutorial book, reference manual, or both: *
35 * http://www.FreeRTOS.org/Documentation *
36 * *
37 ***************************************************************************
38
39 http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
40 the FAQ page "My application does not run, what could be wrong?". Have you
41 defined configASSERT()?
42
43 http://www.FreeRTOS.org/support - In return for receiving this top quality
44 embedded software for free we request you assist our global community by
45 participating in the support forum.
46
47 http://www.FreeRTOS.org/training - Investing in training allows your team to
48 be as productive as possible as early as possible. Now you can receive
49 FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
50 Ltd, and the world's leading authority on the world's leading RTOS.
51
52 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
53 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
54 compatible FAT file system, and our tiny thread aware UDP/IP stack.
55
56 http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
57 Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
58
59 http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
60 Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
61 licenses offer ticketed support, indemnification and commercial middleware.
62
63 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
64 engineered and independently SIL3 certified version for use in safety and
65 mission critical applications that require provable dependability.
66
67 1 tab == 4 spaces!
68*/
69
70/* Standard includes. */
71#include <stdlib.h>
72#include <string.h>
73
74/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
75all the API functions to use the MPU wrappers. That should only be done when
76task.h is included from an application file. */
77#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
78
79/* FreeRTOS includes. */
80#include "Arduino_FreeRTOS.h"
81#include "task.h"
82#include "timers.h"
83#include "StackMacros.h"
84#define N 5
85////////////////////////////////////// LDF
86struct taskLDF {
87 int idx;
88 int parent;
89 int cost;
90 int deadline;
91 int arrivalTime;
92 int resource[3];
93} taskovi[N], oldTasks[N];
94struct node{
95 int idx;
96 int deadline;
97} heap[N];
98struct TestNode{
99 int idx;
100 int weight;
101};
102int indeg[N];
103int t = 1;
104int px;
105int resursi[N + N];
106int resultTasks[3][N];
107int marked[N];
108int k = 0;
109int calc;
110int rezultat[N];
111int size_heap;
112int schedulable = -1;
113int pom;
114int parentResult[N];
115void checkDebuger(int *p, int *q, int *idx, int n){
116 *p = taskovi[rezultat[n]].arrivalTime;
117 *q = taskovi[rezultat[n]].cost;
118 *idx = taskovi[rezultat[n]].idx;
119}
120void checkSchedulable(char pr[]){
121 if(schedulable == 1){
122 pr[0] = 'S';
123 } else if(schedulable == 0){
124 pr[0] = 'E';
125 } else {
126 pr[0] = 'F';
127 }
128}
129void insert_heap(struct node a){
130 heap[++size_heap].idx = a.idx;
131 heap[size_heap].deadline = a.deadline;
132}
133int delete_min(){
134 int maxnmb = - 1; int idtsk = -1;
135 for(int w = 1; w <= size_heap; w++){
136 if(heap[w].deadline > maxnmb && heap[w].deadline != 30000){
137 maxnmb = heap[w].deadline;
138 idtsk = w;
139 }
140 }
141 return idtsk;
142}
143int dbgFULL(){
144 return taskovi[rezultat[0]].idx;
145}
146void addTaskLDF(int idx, int parent, int cost, int deadline, int arrivaltime, int resources[]){
147 taskovi[t].idx = idx;
148 taskovi[t].parent = parent;
149 if(parent != 0);
150 indeg[taskovi[t].parent]++;
151 taskovi[t].cost = cost;
152 taskovi[t].arrivalTime = arrivaltime;
153 taskovi[t].deadline = deadline;
154 for(int w = 0; w < 3; w++){
155 taskovi[t].resource[w] = resources[w];
156 }
157 oldTasks[t] = taskovi[t];
158 t++;
159}
160int bigtest(){
161 return k;
162}
163void LDF(){
164 for(int w = 1; w < t; w++){
165 if(!indeg[w]){
166 struct node temp;
167 temp.deadline = taskovi[w].deadline;
168 temp.idx = taskovi[w].idx;
169 insert_heap(temp);
170 }
171 }
172 k = 0;
173 while(size_heap){
174 int get = delete_min();
175 if(get == -1 || taskovi[heap[get].idx].idx == 0){
176 break;
177 }
178 rezultat[k++] = heap[get].idx;
179 indeg[taskovi[heap[get].idx].parent]--;
180 if(indeg[taskovi[heap[get].idx].parent] == 0){
181 struct node temp;
182 temp.deadline = taskovi[taskovi[heap[get].idx].parent].deadline;
183 temp.idx = taskovi[taskovi[heap[get].idx].parent].idx;
184 insert_heap(temp);
185 }
186 heap[get].deadline = 30000;
187 }
188 int lMax = 0;
189 calc = taskovi[rezultat[k-1]].cost;
190 if(calc > taskovi[rezultat[k-1]].deadline){
191 schedulable = 0;
192 return;
193 }
194 for(int w = k - 2; w >= 0; w--){
195 calc += taskovi[rezultat[w]].cost;
196 if(calc > taskovi[rezultat[w]].deadline){
197 schedulable = 0;
198 return;
199 }
200 }
201 schedulable = 1;
202}
203//////////////////////////////////////////////////////////////////////////////////
204int getMax(int x, int y){
205 return x > y ? x : y;
206}
207int isfeasible(int x, int y){
208 int passTest = 0;
209 int getVal = getMax(taskovi[y].arrivalTime, taskovi[x].arrivalTime + taskovi[x].cost);
210 if(getVal + taskovi[y].cost <= taskovi[y].deadline)
211 return 1;
212 else
213 return 0;
214}
215int findParent(int i){
216 for(int w = 1; w <= t; w++){
217 if(taskovi[w].idx == i)
218 return w;
219 }
220}
221int checkParentCondition(int x){
222 if(x == 0)
223 return 1;
224 if(!marked[x])
225 return 0;
226 return checkParentCondition(taskovi[findParent(x)].parent);
227}
228void writeTaskExecutions(int q, int algo){
229 if(parentResult[taskovi[q].idx] == -1){
230 resultTasks[algo][px++] = q;
231 return;
232 }
233 resultTasks[algo][px++] = q;
234 writeTaskExecutions(findParent(parentResult[taskovi[q].idx]), algo);
235}
236int preostaloTaskova;
237void FCFSnSJF(int i, int n, int parent, int algo){
238 if(!checkParentCondition(taskovi[i].parent)){
239 return;
240 }
241 if(taskovi[i].arrivalTime + taskovi[i].cost > taskovi[i].deadline){
242 return;
243 }
244 if(parent == -1)
245 parentResult[taskovi[i].idx] = -1;
246 else
247 parentResult[taskovi[i].idx] = taskovi[parent].idx;
248
249 marked[taskovi[i].idx] = 1;
250 for(int w = 1; w < n; w++){
251 if(!marked[taskovi[w].idx]){
252 int get = isfeasible(i, w);
253 if(get == 0){
254 marked[taskovi[i].idx] = 0;
255 return;
256 }
257 }
258 }
259 preostaloTaskova--;
260 if(preostaloTaskova == 0){
261 schedulable = 1;
262 writeTaskExecutions(i, algo);
263 return;
264 }
265 for(int w = 1; w < n; w++){
266 if(!schedulable && !marked[taskovi[w].idx]){
267 struct taskLDF temp = taskovi[w];
268 taskovi[w].arrivalTime = getMax(taskovi[w].arrivalTime, taskovi[i].arrivalTime + taskovi[i].cost);
269 if(taskovi[w].arrivalTime > taskovi[w].deadline){
270 taskovi[w].arrivalTime = temp.arrivalTime;
271 }
272 FCFSnSJF(w, n, i, algo);
273 if(!schedulable){
274 taskovi[w].arrivalTime = temp.arrivalTime;
275 }
276 }
277 }
278}
279int EAT(int i){
280 int room = 0;
281 for(int w = 0; w < 3; w++){
282 if(taskovi[i].resource[w]){
283 room = getMax(room, resursi[w + 1]);
284 }
285 }
286 return room;
287}
288void ESTF(int i, int n, int parent, int algo){
289 if(!checkParentCondition(taskovi[i].parent))
290 return;
291 if(taskovi[i].arrivalTime + taskovi[i].cost > taskovi[i].deadline)
292 return;
293 if(parent == -1)
294 parentResult[taskovi[i].idx] = -1;
295 else
296 parentResult[taskovi[i].idx] = taskovi[parent].idx;
297
298 marked[taskovi[i].idx] = 1;
299 for(int w = 0; w < 3; w++){
300 if(taskovi[i].resource[w]){
301 resursi[w + 1] = taskovi[i].arrivalTime + taskovi[i].cost;
302 }
303 }
304 for(int w = 1; w < n; w++){
305 if(!marked[taskovi[w].idx]){
306 int get = isfeasible(i, w);
307 if(get == 0){
308 marked[taskovi[i].idx] = 0;
309 for(int w = 0; w < 3; w++){
310 if(taskovi[i].resource[w])
311 resursi[w + 1] = 0;
312 }
313 return;
314 }
315 }
316 }
317 preostaloTaskova--;
318 if(preostaloTaskova == 0){
319 schedulable = 1;
320 writeTaskExecutions(i, algo);
321 return;
322 }
323
324 struct TestNode Test[N + 1] = {};
325 for(int w = 1; w < n; w++){
326 Test[w].idx = taskovi[w].idx;
327 Test[w].weight = getMax(taskovi[w].arrivalTime, EAT(w));
328 }
329 int lock = 1;
330 do{
331 lock = 1;
332 for(int w = 1; w < n - 1; w++){
333 if(Test[w].weight > Test[w + 1].weight){
334 struct TestNode temp = Test[w];
335 Test[w] = Test[w + 1];
336 Test[w + 1] = temp;
337 lock = 0;
338 }
339 }
340 } while(!lock);
341 for(int w = 1; w < n; w++){
342 if(marked[Test[w].idx])
343 continue;
344 if(!schedulable){
345 struct taskLDF temp = taskovi[Test[w].idx];
346 taskovi[Test[w].idx].arrivalTime = getMax(taskovi[Test[w].idx].arrivalTime, taskovi[i].arrivalTime + taskovi[i].cost);
347 if(taskovi[Test[w].idx].arrivalTime > taskovi[Test[w].idx].deadline){
348 taskovi[Test[w].idx].arrivalTime = temp.arrivalTime;
349 }
350 ESTF(findParent(Test[w].idx), n, i, algo);
351 if(!schedulable){
352 taskovi[Test[w].idx].arrivalTime = temp.arrivalTime;
353 }
354 }
355 }
356}
357void loadOldTasks(){
358 for(int w = 1; w < t; w++){
359 taskovi[w] = oldTasks[w];
360 }
361}
362void SPRING(){
363 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
364 int lock = 0;
365 int H[3] = {-1, -1, -1};
366 schedulable = 0;
367 px = 0;
368 do{
369 lock = 1;
370 for(int w = 1; w < t - 1; w++){
371 if(taskovi[w].arrivalTime > taskovi[w + 1].arrivalTime){
372 struct taskLDF temp = taskovi[w];
373 taskovi[w] = taskovi[w + 1];
374 taskovi[w + 1] = temp;
375 lock = 0;
376 }
377 }
378 } while(!lock);
379 for(int w = 1; w < t; w++){
380 preostaloTaskova = t - 1;
381 FCFSnSJF(w, t, -1, 0);
382 if(!schedulable){
383 marked[taskovi[w].idx] = 0;
384 } else break;
385 }
386 if(schedulable)
387 H[0] = taskovi[resultTasks[0][0]].arrivalTime + taskovi[resultTasks[0][0]].cost;
388
389 loadOldTasks();
390 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
391 px = 0;
392 memset(marked, 0, sizeof(marked));
393 memset(parentResult, 0, sizeof(parentResult));
394 schedulable = 0;
395 lock = 0;
396 do{
397 lock = 1;
398 for(int w = 1; w < t - 1; w++){
399 if(taskovi[w].cost > taskovi[w + 1].cost){
400 struct taskLDF temp = taskovi[w];
401 taskovi[w] = taskovi[w + 1];
402 taskovi[w + 1] = temp;
403 lock = 0;
404 }
405 }
406 } while(!lock);
407 for(int w = 1; w < t; w++){
408 preostaloTaskova = t - 1;
409 FCFSnSJF(w, t, -1, 1);
410 if(!schedulable){
411 marked[w] = 0;
412 } else break;
413 }
414 if(schedulable)
415 H[1] = taskovi[resultTasks[1][0]].arrivalTime + taskovi[resultTasks[1][0]].cost;
416
417 loadOldTasks();
418 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
419 px = 0;
420 memset(marked, 0, sizeof(marked));
421 memset(parentResult, 0, sizeof(parentResult));
422 schedulable = 0;
423 lock = 0;
424 for(int w = 0; w < 3; w++){
425 resursi[w] = -1;
426 }
427 struct TestNode Test[N + 1] = {};
428 for(int w = 1; w < t; w++){
429 Test[w].idx = taskovi[w].idx;
430 Test[w].weight = getMax(taskovi[w].arrivalTime, EAT(w));
431 }
432 do{
433 lock = 1;
434 for(int w = 1; w < t - 1; w++){
435 if(Test[w].weight > Test[w + 1].weight){
436 struct TestNode temp = Test[w];
437 Test[w] = Test[w + 1];
438 Test[w + 1] = temp;
439 lock = 0;
440 }
441 }
442 } while(!lock);
443 for(int w = 1; w < t; w++){
444 preostaloTaskova = t - 1;
445 ESTF(w, t, -1, 2);
446 if(!schedulable){
447 marked[w] = 0;
448 for(int i = 0; i < 3; i++){
449 if(taskovi[w].resource[i])
450 resursi[i + 1] = 0;
451 }
452 } else break;
453 }
454 if(schedulable)
455 H[2] = taskovi[resultTasks[2][0]].arrivalTime + taskovi[resultTasks[2][0]].cost;
456
457 int getResult = 30000;
458 loadOldTasks();
459 for(int w = 0; w < 3; w++){
460 if(H[w] < getResult && H[w] != -1){
461 getResult = H[w];
462 }
463 }
464 if(getResult != 30000){
465 schedulable = 1;
466 for(int w = 0; w < 3; w++){
467 if(getResult == H[w]){
468 for(int i = 0; i < px; i++){
469 rezultat[k++] = resultTasks[w][i];
470 }
471 }
472 if(w == 0){
473 do{
474 lock = 1;
475 for(int itq = 1; itq < t - 1; itq++){
476 if(taskovi[itq].arrivalTime > taskovi[itq + 1].arrivalTime){
477 struct taskLDF temp = taskovi[itq];
478 taskovi[itq] = taskovi[itq + 1];
479 taskovi[itq + 1] = temp;
480 lock = 0;
481 }
482 }
483 } while(!lock);
484 } else if(w == 1){
485 lock = 0;
486 do{
487 lock = 1;
488 for(int itq = 1; itq < t - 1; itq++){
489 if(taskovi[itq].cost > taskovi[itq + 1].cost){
490 struct taskLDF temp = taskovi[itq];
491 taskovi[itq] = taskovi[itq + 1];
492 taskovi[itq + 1] = temp;
493 lock = 0;
494 }
495 }
496 } while(!lock);
497 } else {
498 loadOldTasks();
499 }
500 break;
501 }
502 }
503 for(int w = k - 1; w > 0; w--){
504 struct taskLDF temp = taskovi[rezultat[w + 1]];
505 taskovi[rezultat[w - 1]].arrivalTime = getMax(taskovi[rezultat[w - 1]].arrivalTime, taskovi[rezultat[w]].arrivalTime + taskovi[rezultat[w]].cost);
506 if(taskovi[rezultat[w - 1]].arrivalTime > taskovi[rezultat[w - 1]].deadline){
507 taskovi[rezultat[w - 1]].arrivalTime = temp.arrivalTime;
508 }
509 }
510}
511void addScheduler(char inputTasks[], int n, char dbg[]){
512 int idTaska, parentTaska, costTaska, deadlineTaska, arrivalTimeTaska;
513 int resources[3] = {};
514 idTaska = parentTaska = costTaska = deadlineTaska = arrivalTimeTaska = 0;
515 int idt = 0;
516 while(inputTasks[idt] < '0' || inputTasks[idt] > '9'){
517 idt++;
518 }
519 while(inputTasks[idt] != ' '){
520 idTaska = idTaska * 10 + (inputTasks[idt] - '0');
521 idt++;
522 }
523 idt++;
524 while(inputTasks[idt] != ' '){
525 parentTaska = parentTaska * 10 + (inputTasks[idt] - '0');
526 idt++;
527 }
528 idt++;
529 while(inputTasks[idt] != ' '){
530 costTaska = costTaska * 10 + (inputTasks[idt] - '0');
531 idt++;
532 }
533 idt++;
534 while(inputTasks[idt] != ' '){
535 deadlineTaska = deadlineTaska * 10 + (inputTasks[idt] - '0');
536 idt++;
537 }
538 idt++;
539 while(inputTasks[idt] != ' '){
540 arrivalTimeTaska = arrivalTimeTaska * 10 + (inputTasks[idt] - '0');
541 idt++;
542 }
543 idt++;
544 resources[0] = inputTasks[idt] - '0';
545 idt++;
546 idt++;
547 resources[1] = inputTasks[idt] - '0';
548 idt++;
549 idt++;
550 resources[2] = inputTasks[idt] - '0';
551 idt++;
552 idt++;
553 addTaskLDF(idTaska, parentTaska, costTaska, deadlineTaska, arrivalTimeTaska, resources);
554 if(idTaska == n){
555 LDF();
556 //SPRING();
557 }
558}
559////////////////////////////////////////////////////////////////////////////
560/* Lint e961 and e750 are suppressed as a MISRA exception justified because the
561MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the
562header files above, but not in this file, in order to generate the correct
563privileged Vs unprivileged linkage and placement. */
564#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */
565
566/* Set configUSE_STATS_FORMATTING_FUNCTIONS to 2 to include the stats formatting
567functions but without including stdio.h here. */
568#if ( configUSE_STATS_FORMATTING_FUNCTIONS == 1 )
569/* At the bottom of this file are two optional functions that can be used
570 to generate human readable text from the raw data generated by the
571 uxTaskGetSystemState() function. Note the formatting functions are provided
572 for convenience only, and are NOT considered part of the kernel. */
573#include <stdio.h>
574#endif /* configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) */
575
576/* Sanity check the configuration. */
577#if( configUSE_TICKLESS_IDLE != 0 )
578#if( INCLUDE_vTaskSuspend != 1 )
579#error INCLUDE_vTaskSuspend must be set to 1 if configUSE_TICKLESS_IDLE is not set to 0
580#endif /* INCLUDE_vTaskSuspend */
581#endif /* configUSE_TICKLESS_IDLE */
582
583/*
584* Defines the size, in words, of the stack allocated to the idle task.
585*/
586#define tskIDLE_STACK_SIZE configIDLE_STACK_SIZE
587
588#if( configUSE_PREEMPTION == 0 )
589/* If the cooperative scheduler is being used then a yield should not be
590 performed just because a higher priority task has been woken. */
591#define taskYIELD_IF_USING_PREEMPTION()
592#else
593#define taskYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API()
594#endif
595
596/* Value that can be assigned to the eNotifyState member of the TCB. */
597typedef enum
598{
599 eNotWaitingNotification = 0,
600 eWaitingNotification,
601 eNotified
602} eNotifyValue;
603
604/*
605* Task control block. A task control block (TCB) is allocated for each task,
606* and stores task state information, including a pointer to the task's context
607* (the task's run time environment, including register values)
608*/
609typedef struct tskTaskControlBlock
610{
611 volatile StackType_t *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */
612
613 #if ( portUSING_MPU_WRAPPERS == 1 )
614 xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */
615 BaseType_t xUsingStaticallyAllocatedStack; /* Set to pdTRUE if the stack is a statically allocated array, and pdFALSE if the stack is dynamically allocated. */
616 #endif
617
618 ListItem_t xGenericListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
619 ListItem_t xEventListItem; /*< Used to reference a task from an event list. */
620 UBaseType_t uxPriority; /*< The priority of the task. 0 is the lowest priority. */
621 StackType_t *pxStack; /*< Points to the start of the stack. */
622 char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
623
624 #if ( portSTACK_GROWTH > 0 )
625 StackType_t *pxEndOfStack; /*< Points to the end of the stack on architectures where the stack grows up from low memory. */
626 #endif
627
628 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
629 UBaseType_t uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */
630 #endif
631
632 #if ( configUSE_TRACE_FACILITY == 1 )
633 UBaseType_t uxTCBNumber; /*< Stores a number that increments each time a TCB is created. It allows debuggers to determine when a task has been deleted and then recreated. */
634 UBaseType_t uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */
635 #endif
636
637 #if ( configUSE_MUTEXES == 1 )
638 UBaseType_t uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
639 UBaseType_t uxMutexesHeld;
640 #endif
641
642 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
643 TaskHookFunction_t pxTaskTag;
644 #endif
645
646 #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
647 void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
648 #endif
649
650 #if ( configGENERATE_RUN_TIME_STATS == 1 )
651 uint32_t ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */
652 #endif
653
654 #if ( configUSE_NEWLIB_REENTRANT == 1 )
655 /* Allocate a Newlib reent structure that is specific to this task.
656 Note Newlib support has been included by popular demand, but is not
657 used by the FreeRTOS maintainers themselves. FreeRTOS is not
658 responsible for resulting newlib operation. User must be familiar with
659 newlib and must provide system-wide implementations of the necessary
660 stubs. Be warned that (at the time of writing) the current newlib design
661 implements a system-wide malloc() that must be provided with locks. */
662 struct _reent xNewLib_reent;
663 #endif
664
665 #if ( configUSE_TASK_NOTIFICATIONS == 1 )
666 volatile uint32_t ulNotifiedValue;
667 volatile eNotifyValue eNotifyState;
668 #endif
669
670} TCB_t;
671
672/*
673* Some kernel aware debuggers require the data the debugger needs access to to
674* be global, rather than file scope.
675*/
676#ifdef portREMOVE_STATIC_QUALIFIER
677#define static
678#endif
679
680/*lint -e956 A manual analysis and inspection has been used to determine which
681static variables must be declared volatile. */
682
683PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL;
684
685/* Lists for ready and blocked tasks. --------------------*/
686PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ];/*< Prioritised ready tasks. */
687PRIVILEGED_DATA static List_t xDelayedTaskList1; /*< Delayed tasks. */
688PRIVILEGED_DATA static List_t xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
689PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList; /*< Points to the delayed task list currently being used. */
690PRIVILEGED_DATA static List_t * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
691PRIVILEGED_DATA static List_t xPendingReadyList; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready list when the scheduler is resumed. */
692
693#if ( INCLUDE_vTaskDelete == 1 )
694
695PRIVILEGED_DATA static List_t xTasksWaitingTermination; /*< Tasks that have been deleted - but their memory not yet freed. */
696PRIVILEGED_DATA static volatile UBaseType_t uxTasksDeleted = ( UBaseType_t ) 0U;
697
698#endif
699
700#if ( INCLUDE_vTaskSuspend == 1 )
701
702PRIVILEGED_DATA static List_t xSuspendedTaskList; /*< Tasks that are currently suspended. */
703
704#endif
705
706#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
707
708PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle = NULL; /*< Holds the handle of the idle task. The idle task is created automatically when the scheduler is started. */
709
710#endif
711
712/* Other file private variables. --------------------------------*/
713PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U;
714PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) 0U;
715PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY;
716PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE;
717PRIVILEGED_DATA static volatile UBaseType_t uxPendedTicks = ( UBaseType_t ) 0U;
718PRIVILEGED_DATA static volatile BaseType_t xYieldPending = pdFALSE;
719PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = ( BaseType_t ) 0;
720PRIVILEGED_DATA static UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U;
721PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = ( TickType_t ) 0U; /* Initialised to portMAX_DELAY before the scheduler starts. */
722
723/* Context switches are held pending while the scheduler is suspended. Also,
724interrupts must not manipulate the xGenericListItem of a TCB, or any of the
725lists the xGenericListItem can be referenced from, if the scheduler is suspended.
726If an interrupt needs to unblock a task while the scheduler is suspended then it
727moves the task's event list item into the xPendingReadyList, ready for the
728kernel to move the task from the pending ready list into the real ready list
729when the scheduler is unsuspended. The pending ready list itself can only be
730accessed from a critical section. */
731PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t ) pdFALSE;
732
733#if ( configGENERATE_RUN_TIME_STATS == 1 )
734
735PRIVILEGED_DATA static uint32_t ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */
736PRIVILEGED_DATA static uint32_t ulTotalRunTime = 0UL; /*< Holds the total amount of execution time as defined by the run time counter clock. */
737
738#endif
739
740/*lint +e956 */
741
742/* Debugging and trace facilities private variables and macros. ------------*/
743
744/*
745* The value used to fill the stack of a task when the task is created. This
746* is used purely for checking the high water mark for tasks.
747*/
748#define tskSTACK_FILL_BYTE ( 0xa5U )
749
750/*
751* Macros used by vListTask to indicate which state a task is in.
752*/
753#define tskBLOCKED_CHAR ( 'B' )
754#define tskREADY_CHAR ( 'R' )
755#define tskDELETED_CHAR ( 'D' )
756#define tskSUSPENDED_CHAR ( 'S' )
757
758/*-----------------------------------------------------------*/
759
760#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
761
762/* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is
763 performed in a generic way that is not optimised to any particular
764 microcontroller architecture. */
765
766/* uxTopReadyPriority holds the priority of the highest priority ready
767 state task. */
768#define taskRECORD_READY_PRIORITY( uxPriority ) \
769 { \
770 if( ( uxPriority ) > uxTopReadyPriority ) \
771 { \
772 uxTopReadyPriority = ( uxPriority ); \
773 } \
774 } /* taskRECORD_READY_PRIORITY */
775
776/*-----------------------------------------------------------*/
777
778#define taskSELECT_HIGHEST_PRIORITY_TASK() \
779 { \
780 /* Find the highest priority queue that contains ready tasks. */ \
781 while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) ) \
782 { \
783 configASSERT( uxTopReadyPriority ); \
784 --uxTopReadyPriority; \
785 } \
786 \
787 /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of \
788 the same priority get an equal share of the processor time. */ \
789 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) ); \
790 } /* taskSELECT_HIGHEST_PRIORITY_TASK */
791
792/*-----------------------------------------------------------*/
793
794/* Define away taskRESET_READY_PRIORITY() and portRESET_READY_PRIORITY() as
795 they are only required when a port optimised method of task selection is
796 being used. */
797#define taskRESET_READY_PRIORITY( uxPriority )
798#define portRESET_READY_PRIORITY( uxPriority, uxTopReadyPriority )
799
800#else /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
801
802/* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 1 then task selection is
803 performed in a way that is tailored to the particular microcontroller
804 architecture being used. */
805
806/* A port optimised version is provided. Call the port defined macros. */
807#define taskRECORD_READY_PRIORITY( uxPriority ) portRECORD_READY_PRIORITY( uxPriority, uxTopReadyPriority )
808
809/*-----------------------------------------------------------*/
810
811#define taskSELECT_HIGHEST_PRIORITY_TASK() \
812 { \
813 UBaseType_t uxTopPriority; \
814 \
815 /* Find the highest priority queue that contains ready tasks. */ \
816 portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \
817 configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \
818 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \
819 } /* taskSELECT_HIGHEST_PRIORITY_TASK() */
820
821/*-----------------------------------------------------------*/
822
823/* A port optimised version is provided, call it only if the TCB being reset
824 is being referenced from a ready list. If it is referenced from a delayed
825 or suspended list then it won't be in a ready list. */
826#define taskRESET_READY_PRIORITY( uxPriority ) \
827 { \
828 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == ( UBaseType_t ) 0 ) \
829 { \
830 portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) ); \
831 } \
832 }
833
834#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
835
836/*-----------------------------------------------------------*/
837
838/* pxDelayedTaskList and pxOverflowDelayedTaskList are switched when the tick
839count overflows. */
840#define taskSWITCH_DELAYED_LISTS() \
841 { \
842 List_t *pxTemp; \
843 \
844 /* The delayed tasks list should be empty when the lists are switched. */ \
845 configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) ); \
846 \
847 pxTemp = pxDelayedTaskList; \
848 pxDelayedTaskList = pxOverflowDelayedTaskList; \
849 pxOverflowDelayedTaskList = pxTemp; \
850 xNumOfOverflows++; \
851 prvResetNextTaskUnblockTime(); \
852 }
853
854/*-----------------------------------------------------------*/
855
856/*
857* Place the task represented by pxTCB into the appropriate ready list for
858* the task. It is inserted at the end of the list.
859*/
860#define prvAddTaskToReadyList( pxTCB ) \
861 traceMOVED_TASK_TO_READY_STATE( pxTCB ); \
862 taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \
863 vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xGenericListItem ) )
864/*-----------------------------------------------------------*/
865
866/*
867* Several functions take an TaskHandle_t parameter that can optionally be NULL,
868* where NULL is used to indicate that the handle of the currently executing
869* task should be used in place of the parameter. This macro simply checks to
870* see if the parameter is NULL and returns a pointer to the appropriate TCB.
871*/
872#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( TCB_t * ) pxCurrentTCB : ( TCB_t * ) ( pxHandle ) )
873
874/* The item value of the event list item is normally used to hold the priority
875of the task to which it belongs (coded to allow it to be held in reverse
876priority order). However, it is occasionally borrowed for other purposes. It
877is important its value is not updated due to a task priority change while it is
878being used for another purpose. The following bit definition is used to inform
879the scheduler that the value should not be changed - in which case it is the
880responsibility of whichever module is using the value to ensure it gets set back
881to its original value when it is released. */
882#if configUSE_16_BIT_TICKS == 1
883#define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x8000U
884#else
885#define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x80000000UL
886#endif
887
888/* Callback function prototypes. --------------------------*/
889#if configCHECK_FOR_STACK_OVERFLOW > 0
890extern void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName );
891#endif
892
893#if configUSE_TICK_HOOK > 0
894extern void vApplicationTickHook( void );
895#endif
896
897/* File private functions. --------------------------------*/
898
899/*
900* Utility to ready a TCB for a given task. Mainly just copies the parameters
901* into the TCB structure.
902*/
903static void prvInitialiseTCBVariables( TCB_t * const pxTCB, const char * const pcName, UBaseType_t uxPriority, const MemoryRegion_t * const xRegions, const uint16_t usStackDepth ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
904
905/**
906* Utility task that simply returns pdTRUE if the task referenced by xTask is
907* currently in the Suspended state, or pdFALSE if the task referenced by xTask
908* is in any other state.
909*/
910#if ( INCLUDE_vTaskSuspend == 1 )
911static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
912#endif /* INCLUDE_vTaskSuspend */
913
914/*
915* Utility to ready all the lists used by the scheduler. This is called
916* automatically upon the creation of the first task.
917*/
918static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION;
919
920/*
921* The idle task, which as all tasks is implemented as a never ending loop.
922* The idle task is automatically created and added to the ready lists upon
923* creation of the first user task.
924*
925* The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific
926* language extensions. The equivalent prototype for this function is:
927*
928* void prvIdleTask( void *pvParameters );
929*
930*/
931static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters );
932
933/*
934* Utility to free all memory allocated by the scheduler to hold a TCB,
935* including the stack pointed to by the TCB.
936*
937* This does not free memory allocated by the task itself (i.e. memory
938* allocated by calls to pvPortMalloc from within the tasks application code).
939*/
940#if ( INCLUDE_vTaskDelete == 1 )
941
942static void prvDeleteTCB( TCB_t *pxTCB ) PRIVILEGED_FUNCTION;
943
944#endif
945
946/*
947* Used only by the idle task. This checks to see if anything has been placed
948* in the list of tasks waiting to be deleted. If so the task is cleaned up
949* and its TCB deleted.
950*/
951static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION;
952
953/*
954* The currently executing task is entering the Blocked state. Add the task to
955* either the current or the overflow delayed task list.
956*/
957static void prvAddCurrentTaskToDelayedList( const TickType_t xTimeToWake ) PRIVILEGED_FUNCTION;
958
959/*
960* Allocates memory from the heap for a TCB and associated stack. Checks the
961* allocation was successful.
962*/
963static TCB_t *prvAllocateTCBAndStack( const uint16_t usStackDepth, StackType_t * const puxStackBuffer ) PRIVILEGED_FUNCTION;
964
965/*
966* Fills an TaskStatus_t structure with information on each task that is
967* referenced from the pxList list (which may be a ready list, a delayed list,
968* a suspended list, etc.).
969*
970* THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM
971* NORMAL APPLICATION CODE.
972*/
973#if ( configUSE_TRACE_FACILITY == 1 )
974
975static UBaseType_t prvListTaskWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState ) PRIVILEGED_FUNCTION;
976
977#endif
978
979/*
980* When a task is created, the stack of the task is filled with a known value.
981* This function determines the 'high water mark' of the task stack by
982* determining how much of the stack remains at the original preset value.
983*/
984#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
985
986static uint16_t prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte ) PRIVILEGED_FUNCTION;
987
988#endif
989
990/*
991* Return the amount of time, in ticks, that will pass before the kernel will
992* next move a task from the Blocked state to the Running state.
993*
994* This conditional compilation should use inequality to 0, not equality to 1.
995* This is to ensure portSUPPRESS_TICKS_AND_SLEEP() can be called when user
996* defined low power mode implementations require configUSE_TICKLESS_IDLE to be
997* set to a value other than 1.
998*/
999#if ( configUSE_TICKLESS_IDLE != 0 )
1000
1001static TickType_t prvGetExpectedIdleTime( void ) PRIVILEGED_FUNCTION;
1002
1003#endif
1004
1005/*
1006* Set xNextTaskUnblockTime to the time at which the next Blocked state task
1007* will exit the Blocked state.
1008*/
1009static void prvResetNextTaskUnblockTime( void );
1010
1011#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) )
1012
1013/*
1014 * Helper function used to pad task names with spaces when printing out
1015 * human readable tables of task information.
1016 */
1017static char *prvWriteNameToBuffer( char *pcBuffer, const char *pcTaskName );
1018
1019#endif
1020/*-----------------------------------------------------------*/
1021
1022BaseType_t xTaskGenericCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, StackType_t * const puxStackBuffer, const MemoryRegion_t * const xRegions ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
1023{
1024 BaseType_t xReturn;
1025 TCB_t * pxNewTCB;
1026 StackType_t *pxTopOfStack;
1027
1028 configASSERT( pxTaskCode );
1029 configASSERT( ( ( uxPriority & ( UBaseType_t ) ( ~portPRIVILEGE_BIT ) ) < ( UBaseType_t ) configMAX_PRIORITIES ) );
1030
1031 /* Allocate the memory required by the TCB and stack for the new task,
1032 checking that the allocation was successful. */
1033 pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer );
1034
1035 if( pxNewTCB != NULL )
1036 {
1037 #if( portUSING_MPU_WRAPPERS == 1 )
1038 /* Should the task be created in privileged mode? */
1039 BaseType_t xRunPrivileged;
1040 if( ( uxPriority & portPRIVILEGE_BIT ) != 0U )
1041 {
1042 xRunPrivileged = pdTRUE;
1043 }
1044 else
1045 {
1046 xRunPrivileged = pdFALSE;
1047 }
1048 uxPriority &= ~portPRIVILEGE_BIT;
1049
1050 if( puxStackBuffer != NULL )
1051 {
1052 /* The application provided its own stack. Note this so no
1053 attempt is made to delete the stack should that task be
1054 deleted. */
1055 pxNewTCB->xUsingStaticallyAllocatedStack = pdTRUE;
1056 }
1057 else
1058 {
1059 /* The stack was allocated dynamically. Note this so it can be
1060 deleted again if the task is deleted. */
1061 pxNewTCB->xUsingStaticallyAllocatedStack = pdFALSE;
1062 }
1063 #endif /* portUSING_MPU_WRAPPERS == 1 */
1064
1065 /* Calculate the top of stack address. This depends on whether the
1066 stack grows from high memory to low (as per the 80x86) or vice versa.
1067 portSTACK_GROWTH is used to make the result positive or negative as
1068 required by the port. */
1069 #if( portSTACK_GROWTH < 0 )
1070 {
1071 pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - ( uint16_t ) 1 );
1072 pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); /*lint !e923 MISRA exception. Avoiding casts between pointers and integers is not practical. Size differences accounted for using portPOINTER_SIZE_TYPE type. */
1073
1074 /* Check the alignment of the calculated top of stack is correct. */
1075 configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
1076 }
1077 #else /* portSTACK_GROWTH */
1078 {
1079 pxTopOfStack = pxNewTCB->pxStack;
1080
1081 /* Check the alignment of the stack buffer is correct. */
1082 configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxNewTCB->pxStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
1083
1084 /* If we want to use stack checking on architectures that use
1085 a positive stack growth direction then we also need to store the
1086 other extreme of the stack space. */
1087 pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
1088 }
1089 #endif /* portSTACK_GROWTH */
1090
1091 /* Setup the newly allocated TCB with the initial state of the task. */
1092 prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth );
1093
1094 /* Initialize the TCB stack to look as if the task was already running,
1095 but had been interrupted by the scheduler. The return address is set
1096 to the start of the task function. Once the stack has been initialised
1097 the top of stack variable is updated. */
1098 #if( portUSING_MPU_WRAPPERS == 1 )
1099 {
1100 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
1101 }
1102 #else /* portUSING_MPU_WRAPPERS */
1103 {
1104 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
1105 }
1106 #endif /* portUSING_MPU_WRAPPERS */
1107
1108 if( ( void * ) pxCreatedTask != NULL )
1109 {
1110 /* Pass the TCB out - in an anonymous way. The calling function/
1111 task can use this as a handle to delete the task later if
1112 required.*/
1113 *pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
1114 }
1115 else
1116 {
1117 mtCOVERAGE_TEST_MARKER();
1118 }
1119
1120 /* Ensure interrupts don't access the task lists while they are being
1121 updated. */
1122 taskENTER_CRITICAL();
1123 {
1124 uxCurrentNumberOfTasks++;
1125 if( pxCurrentTCB == NULL )
1126 {
1127 /* There are no other tasks, or all the other tasks are in
1128 the suspended state - make this the current task. */
1129 pxCurrentTCB = pxNewTCB;
1130
1131 if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )
1132 {
1133 /* This is the first task to be created so do the preliminary
1134 initialisation required. We will not recover if this call
1135 fails, but we will report the failure. */
1136 prvInitialiseTaskLists();
1137 }
1138 else
1139 {
1140 mtCOVERAGE_TEST_MARKER();
1141 }
1142 }
1143 else
1144 {
1145 /* If the scheduler is not already running, make this task the
1146 current task if it is the highest priority task to be created
1147 so far. */
1148 if( xSchedulerRunning == pdFALSE )
1149 {
1150 if( pxCurrentTCB->uxPriority <= uxPriority )
1151 {
1152 pxCurrentTCB = pxNewTCB;
1153 }
1154 else
1155 {
1156 mtCOVERAGE_TEST_MARKER();
1157 }
1158 }
1159 else
1160 {
1161 mtCOVERAGE_TEST_MARKER();
1162 }
1163 }
1164
1165 uxTaskNumber++;
1166
1167 #if ( configUSE_TRACE_FACILITY == 1 )
1168 {
1169 /* Add a counter into the TCB for tracing only. */
1170 pxNewTCB->uxTCBNumber = uxTaskNumber;
1171 }
1172 #endif /* configUSE_TRACE_FACILITY */
1173 traceTASK_CREATE( pxNewTCB );
1174
1175 prvAddTaskToReadyList( pxNewTCB );
1176
1177 xReturn = pdPASS;
1178 portSETUP_TCB( pxNewTCB );
1179 }
1180 taskEXIT_CRITICAL();
1181 }
1182 else
1183 {
1184 xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
1185 traceTASK_CREATE_FAILED();
1186 }
1187
1188 if( xReturn == pdPASS )
1189 {
1190 if( xSchedulerRunning != pdFALSE )
1191 {
1192 /* If the created task is of a higher priority than the current task
1193 then it should run now. */
1194 if( pxCurrentTCB->uxPriority < uxPriority )
1195 {
1196 taskYIELD_IF_USING_PREEMPTION();
1197 }
1198 else
1199 {
1200 mtCOVERAGE_TEST_MARKER();
1201 }
1202 }
1203 else
1204 {
1205 mtCOVERAGE_TEST_MARKER();
1206 }
1207 }
1208
1209 return xReturn;
1210}
1211/*-----------------------------------------------------------*/
1212
1213#if ( INCLUDE_vTaskDelete == 1 )
1214
1215void vTaskDelete( TaskHandle_t xTaskToDelete )
1216{
1217 TCB_t *pxTCB;
1218
1219 taskENTER_CRITICAL();
1220 {
1221 /* If null is passed in here then it is the calling task that is
1222 being deleted. */
1223 pxTCB = prvGetTCBFromHandle( xTaskToDelete );
1224
1225 /* Remove task from the ready list and place in the termination list.
1226 This will stop the task from be scheduled. The idle task will check
1227 the termination list and free up any memory allocated by the
1228 scheduler for the TCB and stack. */
1229 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
1230 {
1231 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
1232 }
1233 else
1234 {
1235 mtCOVERAGE_TEST_MARKER();
1236 }
1237
1238 /* Is the task waiting on an event also? */
1239 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
1240 {
1241 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
1242 }
1243 else
1244 {
1245 mtCOVERAGE_TEST_MARKER();
1246 }
1247
1248 vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );
1249
1250 /* Increment the ucTasksDeleted variable so the idle task knows
1251 there is a task that has been deleted and that it should therefore
1252 check the xTasksWaitingTermination list. */
1253 ++uxTasksDeleted;
1254
1255 /* Increment the uxTaskNumberVariable also so kernel aware debuggers
1256 can detect that the task lists need re-generating. */
1257 uxTaskNumber++;
1258
1259 traceTASK_DELETE( pxTCB );
1260 }
1261 taskEXIT_CRITICAL();
1262
1263 /* Force a reschedule if it is the currently running task that has just
1264 been deleted. */
1265 if( xSchedulerRunning != pdFALSE )
1266 {
1267 if( pxTCB == pxCurrentTCB )
1268 {
1269 configASSERT( uxSchedulerSuspended == 0 );
1270
1271 /* The pre-delete hook is primarily for the Windows simulator,
1272 in which Windows specific clean up operations are performed,
1273 after which it is not possible to yield away from this task -
1274 hence xYieldPending is used to latch that a context switch is
1275 required. */
1276 portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending );
1277 portYIELD_WITHIN_API();
1278 }
1279 else
1280 {
1281 /* Reset the next expected unblock time in case it referred to
1282 the task that has just been deleted. */
1283 taskENTER_CRITICAL();
1284 {
1285 prvResetNextTaskUnblockTime();
1286 }
1287 taskEXIT_CRITICAL();
1288 }
1289 }
1290}
1291
1292#endif /* INCLUDE_vTaskDelete */
1293/*-----------------------------------------------------------*/
1294
1295#if ( INCLUDE_vTaskDelayUntil == 1 )
1296
1297void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement )
1298{
1299 TickType_t xTimeToWake;
1300 BaseType_t xAlreadyYielded, xShouldDelay = pdFALSE;
1301
1302 configASSERT( pxPreviousWakeTime );
1303 configASSERT( ( xTimeIncrement > 0U ) );
1304 configASSERT( uxSchedulerSuspended == 0 );
1305
1306 vTaskSuspendAll();
1307 {
1308 /* Minor optimisation. The tick count cannot change in this
1309 block. */
1310 const TickType_t xConstTickCount = xTickCount;
1311
1312 /* Generate the tick time at which the task wants to wake. */
1313 xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
1314
1315 if( xConstTickCount < *pxPreviousWakeTime )
1316 {
1317 /* The tick count has overflowed since this function was
1318 lasted called. In this case the only time we should ever
1319 actually delay is if the wake time has also overflowed,
1320 and the wake time is greater than the tick time. When this
1321 is the case it is as if neither time had overflowed. */
1322 if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xConstTickCount ) )
1323 {
1324 xShouldDelay = pdTRUE;
1325 }
1326 else
1327 {
1328 mtCOVERAGE_TEST_MARKER();
1329 }
1330 }
1331 else
1332 {
1333 /* The tick time has not overflowed. In this case we will
1334 delay if either the wake time has overflowed, and/or the
1335 tick time is less than the wake time. */
1336 if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xConstTickCount ) )
1337 {
1338 xShouldDelay = pdTRUE;
1339 }
1340 else
1341 {
1342 mtCOVERAGE_TEST_MARKER();
1343 }
1344 }
1345
1346 /* Update the wake time ready for the next call. */
1347 *pxPreviousWakeTime = xTimeToWake;
1348
1349 if( xShouldDelay != pdFALSE )
1350 {
1351 traceTASK_DELAY_UNTIL();
1352
1353 /* Remove the task from the ready list before adding it to the
1354 blocked list as the same list item is used for both lists. */
1355 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
1356 {
1357 /* The current task must be in a ready list, so there is
1358 no need to check, and the port reset macro can be called
1359 directly. */
1360 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
1361 }
1362 else
1363 {
1364 mtCOVERAGE_TEST_MARKER();
1365 }
1366
1367 prvAddCurrentTaskToDelayedList( xTimeToWake );
1368 }
1369 else
1370 {
1371 mtCOVERAGE_TEST_MARKER();
1372 }
1373 }
1374 xAlreadyYielded = xTaskResumeAll();
1375
1376 /* Force a reschedule if xTaskResumeAll has not already done so, we may
1377 have put ourselves to sleep. */
1378 if( xAlreadyYielded == pdFALSE )
1379 {
1380 portYIELD_WITHIN_API();
1381 }
1382 else
1383 {
1384 mtCOVERAGE_TEST_MARKER();
1385 }
1386}
1387
1388#endif /* INCLUDE_vTaskDelayUntil */
1389/*-----------------------------------------------------------*/
1390
1391#if ( INCLUDE_vTaskDelay == 1 )
1392
1393void vTaskDelay( const TickType_t xTicksToDelay )
1394{
1395 TickType_t xTimeToWake;
1396 BaseType_t xAlreadyYielded = pdFALSE;
1397
1398
1399 /* A delay time of zero just forces a reschedule. */
1400 if( xTicksToDelay > ( TickType_t ) 0U )
1401 {
1402 configASSERT( uxSchedulerSuspended == 0 );
1403 vTaskSuspendAll();
1404 {
1405 traceTASK_DELAY();
1406
1407 /* A task that is removed from the event list while the
1408 scheduler is suspended will not get placed in the ready
1409 list or removed from the blocked list until the scheduler
1410 is resumed.
1411
1412 This task cannot be in an event list as it is the currently
1413 executing task. */
1414
1415 /* Calculate the time to wake - this may overflow but this is
1416 not a problem. */
1417 xTimeToWake = xTickCount + xTicksToDelay;
1418
1419 /* We must remove ourselves from the ready list before adding
1420 ourselves to the blocked list as the same list item is used for
1421 both lists. */
1422 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
1423 {
1424 /* The current task must be in a ready list, so there is
1425 no need to check, and the port reset macro can be called
1426 directly. */
1427 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
1428 }
1429 else
1430 {
1431 mtCOVERAGE_TEST_MARKER();
1432 }
1433 prvAddCurrentTaskToDelayedList( xTimeToWake );
1434 }
1435 xAlreadyYielded = xTaskResumeAll();
1436 }
1437 else
1438 {
1439 mtCOVERAGE_TEST_MARKER();
1440 }
1441
1442 /* Force a reschedule if xTaskResumeAll has not already done so, we may
1443 have put ourselves to sleep. */
1444 if( xAlreadyYielded == pdFALSE )
1445 {
1446 portYIELD_WITHIN_API();
1447 }
1448 else
1449 {
1450 mtCOVERAGE_TEST_MARKER();
1451 }
1452}
1453
1454#endif /* INCLUDE_vTaskDelay */
1455/*-----------------------------------------------------------*/
1456
1457#if ( INCLUDE_eTaskGetState == 1 )
1458
1459eTaskState eTaskGetState( TaskHandle_t xTask )
1460{
1461 eTaskState eReturn;
1462 List_t *pxStateList;
1463 const TCB_t * const pxTCB = ( TCB_t * ) xTask;
1464
1465 configASSERT( pxTCB );
1466
1467 if( pxTCB == pxCurrentTCB )
1468 {
1469 /* The task calling this function is querying its own state. */
1470 eReturn = eRunning;
1471 }
1472 else
1473 {
1474 taskENTER_CRITICAL();
1475 {
1476 pxStateList = ( List_t * ) listLIST_ITEM_CONTAINER( &( pxTCB->xGenericListItem ) );
1477 }
1478 taskEXIT_CRITICAL();
1479
1480 if( ( pxStateList == pxDelayedTaskList ) || ( pxStateList == pxOverflowDelayedTaskList ) )
1481 {
1482 /* The task being queried is referenced from one of the Blocked
1483 lists. */
1484 eReturn = eBlocked;
1485 }
1486
1487 #if ( INCLUDE_vTaskSuspend == 1 )
1488 else if( pxStateList == &xSuspendedTaskList )
1489 {
1490 /* The task being queried is referenced from the suspended
1491 list. Is it genuinely suspended or is it block
1492 indefinitely? */
1493 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL )
1494 {
1495 eReturn = eSuspended;
1496 }
1497 else
1498 {
1499 eReturn = eBlocked;
1500 }
1501 }
1502 #endif
1503
1504 #if ( INCLUDE_vTaskDelete == 1 )
1505 else if( pxStateList == &xTasksWaitingTermination )
1506 {
1507 /* The task being queried is referenced from the deleted
1508 tasks list. */
1509 eReturn = eDeleted;
1510 }
1511 #endif
1512
1513 else
1514 {
1515 /* If the task is not in any other state, it must be in the
1516 Ready (including pending ready) state. */
1517 eReturn = eReady;
1518 }
1519 }
1520
1521 return eReturn;
1522}
1523
1524#endif /* INCLUDE_eTaskGetState */
1525/*-----------------------------------------------------------*/
1526
1527#if ( INCLUDE_uxTaskPriorityGet == 1 )
1528
1529UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask )
1530{
1531 TCB_t *pxTCB;
1532 UBaseType_t uxReturn;
1533
1534 taskENTER_CRITICAL();
1535 {
1536 /* If null is passed in here then it is the priority of the that
1537 called uxTaskPriorityGet() that is being queried. */
1538 pxTCB = prvGetTCBFromHandle( xTask );
1539 uxReturn = pxTCB->uxPriority;
1540 }
1541 taskEXIT_CRITICAL();
1542
1543 return uxReturn;
1544}
1545
1546#endif /* INCLUDE_uxTaskPriorityGet */
1547/*-----------------------------------------------------------*/
1548
1549#if ( INCLUDE_uxTaskPriorityGet == 1 )
1550
1551UBaseType_t uxTaskPriorityGetFromISR( TaskHandle_t xTask )
1552{
1553 TCB_t *pxTCB;
1554 UBaseType_t uxReturn, uxSavedInterruptState;
1555
1556 /* RTOS ports that support interrupt nesting have the concept of a
1557 maximum system call (or maximum API call) interrupt priority.
1558 Interrupts that are above the maximum system call priority are keep
1559 permanently enabled, even when the RTOS kernel is in a critical section,
1560 but cannot make any calls to FreeRTOS API functions. If configASSERT()
1561 is defined in FreeRTOSConfig.h then
1562 portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
1563 failure if a FreeRTOS API function is called from an interrupt that has
1564 been assigned a priority above the configured maximum system call
1565 priority. Only FreeRTOS functions that end in FromISR can be called
1566 from interrupts that have been assigned a priority at or (logically)
1567 below the maximum system call interrupt priority. FreeRTOS maintains a
1568 separate interrupt safe API to ensure interrupt entry is as fast and as
1569 simple as possible. More information (albeit Cortex-M specific) is
1570 provided on the following link:
1571 http://www.freertos.org/RTOS-Cortex-M3-M4.html */
1572 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
1573
1574 uxSavedInterruptState = portSET_INTERRUPT_MASK_FROM_ISR();
1575 {
1576 /* If null is passed in here then it is the priority of the calling
1577 task that is being queried. */
1578 pxTCB = prvGetTCBFromHandle( xTask );
1579 uxReturn = pxTCB->uxPriority;
1580 }
1581 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptState );
1582
1583 return uxReturn;
1584}
1585
1586#endif /* INCLUDE_uxTaskPriorityGet */
1587/*-----------------------------------------------------------*/
1588
1589#if ( INCLUDE_vTaskPrioritySet == 1 )
1590
1591void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority )
1592{
1593 TCB_t *pxTCB;
1594 UBaseType_t uxCurrentBasePriority, uxPriorityUsedOnEntry;
1595 BaseType_t xYieldRequired = pdFALSE;
1596
1597 configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) );
1598
1599 /* Ensure the new priority is valid. */
1600 if( uxNewPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
1601 {
1602 uxNewPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
1603 }
1604 else
1605 {
1606 mtCOVERAGE_TEST_MARKER();
1607 }
1608
1609 taskENTER_CRITICAL();
1610 {
1611 /* If null is passed in here then it is the priority of the calling
1612 task that is being changed. */
1613 pxTCB = prvGetTCBFromHandle( xTask );
1614
1615 traceTASK_PRIORITY_SET( pxTCB, uxNewPriority );
1616
1617 #if ( configUSE_MUTEXES == 1 )
1618 {
1619 uxCurrentBasePriority = pxTCB->uxBasePriority;
1620 }
1621 #else
1622 {
1623 uxCurrentBasePriority = pxTCB->uxPriority;
1624 }
1625 #endif
1626
1627 if( uxCurrentBasePriority != uxNewPriority )
1628 {
1629 /* The priority change may have readied a task of higher
1630 priority than the calling task. */
1631 if( uxNewPriority > uxCurrentBasePriority )
1632 {
1633 if( pxTCB != pxCurrentTCB )
1634 {
1635 /* The priority of a task other than the currently
1636 running task is being raised. Is the priority being
1637 raised above that of the running task? */
1638 if( uxNewPriority >= pxCurrentTCB->uxPriority )
1639 {
1640 xYieldRequired = pdTRUE;
1641 }
1642 else
1643 {
1644 mtCOVERAGE_TEST_MARKER();
1645 }
1646 }
1647 else
1648 {
1649 /* The priority of the running task is being raised,
1650 but the running task must already be the highest
1651 priority task able to run so no yield is required. */
1652 }
1653 }
1654 else if( pxTCB == pxCurrentTCB )
1655 {
1656 /* Setting the priority of the running task down means
1657 there may now be another task of higher priority that
1658 is ready to execute. */
1659 xYieldRequired = pdTRUE;
1660 }
1661 else
1662 {
1663 /* Setting the priority of any other task down does not
1664 require a yield as the running task must be above the
1665 new priority of the task being modified. */
1666 }
1667
1668 /* Remember the ready list the task might be referenced from
1669 before its uxPriority member is changed so the
1670 taskRESET_READY_PRIORITY() macro can function correctly. */
1671 uxPriorityUsedOnEntry = pxTCB->uxPriority;
1672
1673 #if ( configUSE_MUTEXES == 1 )
1674 {
1675 /* Only change the priority being used if the task is not
1676 currently using an inherited priority. */
1677 if( pxTCB->uxBasePriority == pxTCB->uxPriority )
1678 {
1679 pxTCB->uxPriority = uxNewPriority;
1680 }
1681 else
1682 {
1683 mtCOVERAGE_TEST_MARKER();
1684 }
1685
1686 /* The base priority gets set whatever. */
1687 pxTCB->uxBasePriority = uxNewPriority;
1688 }
1689 #else
1690 {
1691 pxTCB->uxPriority = uxNewPriority;
1692 }
1693 #endif
1694
1695 /* Only reset the event list item value if the value is not
1696 being used for anything else. */
1697 if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
1698 {
1699 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxNewPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
1700 }
1701 else
1702 {
1703 mtCOVERAGE_TEST_MARKER();
1704 }
1705
1706 /* If the task is in the blocked or suspended list we need do
1707 nothing more than change it's priority variable. However, if
1708 the task is in a ready list it needs to be removed and placed
1709 in the list appropriate to its new priority. */
1710 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xGenericListItem ) ) != pdFALSE )
1711 {
1712 /* The task is currently in its ready list - remove before adding
1713 it to it's new ready list. As we are in a critical section we
1714 can do this even if the scheduler is suspended. */
1715 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
1716 {
1717 /* It is known that the task is in its ready list so
1718 there is no need to check again and the port level
1719 reset macro can be called directly. */
1720 portRESET_READY_PRIORITY( uxPriorityUsedOnEntry, uxTopReadyPriority );
1721 }
1722 else
1723 {
1724 mtCOVERAGE_TEST_MARKER();
1725 }
1726 prvAddTaskToReadyList( pxTCB );
1727 }
1728 else
1729 {
1730 mtCOVERAGE_TEST_MARKER();
1731 }
1732
1733 if( xYieldRequired == pdTRUE )
1734 {
1735 taskYIELD_IF_USING_PREEMPTION();
1736 }
1737 else
1738 {
1739 mtCOVERAGE_TEST_MARKER();
1740 }
1741
1742 /* Remove compiler warning about unused variables when the port
1743 optimised task selection is not being used. */
1744 ( void ) uxPriorityUsedOnEntry;
1745 }
1746 }
1747 taskEXIT_CRITICAL();
1748}
1749
1750#endif /* INCLUDE_vTaskPrioritySet */
1751/*-----------------------------------------------------------*/
1752
1753#if ( INCLUDE_vTaskSuspend == 1 )
1754
1755void vTaskSuspend( TaskHandle_t xTaskToSuspend )
1756{
1757 TCB_t *pxTCB;
1758
1759 taskENTER_CRITICAL();
1760 {
1761 /* If null is passed in here then it is the running task that is
1762 being suspended. */
1763 pxTCB = prvGetTCBFromHandle( xTaskToSuspend );
1764
1765 traceTASK_SUSPEND( pxTCB );
1766
1767 /* Remove task from the ready/delayed list and place in the
1768 suspended list. */
1769 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
1770 {
1771 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
1772 }
1773 else
1774 {
1775 mtCOVERAGE_TEST_MARKER();
1776 }
1777
1778 /* Is the task waiting on an event also? */
1779 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
1780 {
1781 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
1782 }
1783 else
1784 {
1785 mtCOVERAGE_TEST_MARKER();
1786 }
1787
1788 vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );
1789 }
1790 taskEXIT_CRITICAL();
1791
1792 if( pxTCB == pxCurrentTCB )
1793 {
1794 if( xSchedulerRunning != pdFALSE )
1795 {
1796 /* The current task has just been suspended. */
1797 configASSERT( uxSchedulerSuspended == 0 );
1798 portYIELD_WITHIN_API();
1799 }
1800 else
1801 {
1802 /* The scheduler is not running, but the task that was pointed
1803 to by pxCurrentTCB has just been suspended and pxCurrentTCB
1804 must be adjusted to point to a different task. */
1805 if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks )
1806 {
1807 /* No other tasks are ready, so set pxCurrentTCB back to
1808 NULL so when the next task is created pxCurrentTCB will
1809 be set to point to it no matter what its relative priority
1810 is. */
1811 pxCurrentTCB = NULL;
1812 }
1813 else
1814 {
1815 vTaskSwitchContext();
1816 }
1817 }
1818 }
1819 else
1820 {
1821 if( xSchedulerRunning != pdFALSE )
1822 {
1823 /* A task other than the currently running task was suspended,
1824 reset the next expected unblock time in case it referred to the
1825 task that is now in the Suspended state. */
1826 taskENTER_CRITICAL();
1827 {
1828 prvResetNextTaskUnblockTime();
1829 }
1830 taskEXIT_CRITICAL();
1831 }
1832 else
1833 {
1834 mtCOVERAGE_TEST_MARKER();
1835 }
1836 }
1837}
1838
1839#endif /* INCLUDE_vTaskSuspend */
1840/*-----------------------------------------------------------*/
1841
1842#if ( INCLUDE_vTaskSuspend == 1 )
1843
1844static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask )
1845{
1846 BaseType_t xReturn = pdFALSE;
1847 const TCB_t * const pxTCB = ( TCB_t * ) xTask;
1848
1849 /* Accesses xPendingReadyList so must be called from a critical
1850 section. */
1851
1852 /* It does not make sense to check if the calling task is suspended. */
1853 configASSERT( xTask );
1854
1855 /* Is the task being resumed actually in the suspended list? */
1856 if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE )
1857 {
1858 /* Has the task already been resumed from within an ISR? */
1859 if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) == pdFALSE )
1860 {
1861 /* Is it in the suspended list because it is in the Suspended
1862 state, or because is is blocked with no timeout? */
1863 if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) != pdFALSE )
1864 {
1865 xReturn = pdTRUE;
1866 }
1867 else
1868 {
1869 mtCOVERAGE_TEST_MARKER();
1870 }
1871 }
1872 else
1873 {
1874 mtCOVERAGE_TEST_MARKER();
1875 }
1876 }
1877 else
1878 {
1879 mtCOVERAGE_TEST_MARKER();
1880 }
1881
1882 return xReturn;
1883} /*lint !e818 xTask cannot be a pointer to const because it is a typedef. */
1884
1885#endif /* INCLUDE_vTaskSuspend */
1886/*-----------------------------------------------------------*/
1887
1888#if ( INCLUDE_vTaskSuspend == 1 )
1889
1890void vTaskResume( TaskHandle_t xTaskToResume )
1891{
1892 TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume;
1893
1894 /* It does not make sense to resume the calling task. */
1895 configASSERT( xTaskToResume );
1896
1897 /* The parameter cannot be NULL as it is impossible to resume the
1898 currently executing task. */
1899 if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
1900 {
1901 taskENTER_CRITICAL();
1902 {
1903 if( prvTaskIsTaskSuspended( pxTCB ) == pdTRUE )
1904 {
1905 traceTASK_RESUME( pxTCB );
1906
1907 /* As we are in a critical section we can access the ready
1908 lists even if the scheduler is suspended. */
1909 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
1910 prvAddTaskToReadyList( pxTCB );
1911
1912 /* We may have just resumed a higher priority task. */
1913 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
1914 {
1915 /* This yield may not cause the task just resumed to run,
1916 but will leave the lists in the correct state for the
1917 next yield. */
1918 taskYIELD_IF_USING_PREEMPTION();
1919 }
1920 else
1921 {
1922 mtCOVERAGE_TEST_MARKER();
1923 }
1924 }
1925 else
1926 {
1927 mtCOVERAGE_TEST_MARKER();
1928 }
1929 }
1930 taskEXIT_CRITICAL();
1931 }
1932 else
1933 {
1934 mtCOVERAGE_TEST_MARKER();
1935 }
1936}
1937
1938#endif /* INCLUDE_vTaskSuspend */
1939
1940/*-----------------------------------------------------------*/
1941
1942#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
1943
1944BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume )
1945{
1946 BaseType_t xYieldRequired = pdFALSE;
1947 TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume;
1948 UBaseType_t uxSavedInterruptStatus;
1949
1950 configASSERT( xTaskToResume );
1951
1952 /* RTOS ports that support interrupt nesting have the concept of a
1953 maximum system call (or maximum API call) interrupt priority.
1954 Interrupts that are above the maximum system call priority are keep
1955 permanently enabled, even when the RTOS kernel is in a critical section,
1956 but cannot make any calls to FreeRTOS API functions. If configASSERT()
1957 is defined in FreeRTOSConfig.h then
1958 portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
1959 failure if a FreeRTOS API function is called from an interrupt that has
1960 been assigned a priority above the configured maximum system call
1961 priority. Only FreeRTOS functions that end in FromISR can be called
1962 from interrupts that have been assigned a priority at or (logically)
1963 below the maximum system call interrupt priority. FreeRTOS maintains a
1964 separate interrupt safe API to ensure interrupt entry is as fast and as
1965 simple as possible. More information (albeit Cortex-M specific) is
1966 provided on the following link:
1967 http://www.freertos.org/RTOS-Cortex-M3-M4.html */
1968 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
1969
1970 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
1971 {
1972 if( prvTaskIsTaskSuspended( pxTCB ) == pdTRUE )
1973 {
1974 traceTASK_RESUME_FROM_ISR( pxTCB );
1975
1976 /* Check the ready lists can be accessed. */
1977 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
1978 {
1979 /* Ready lists can be accessed so move the task from the
1980 suspended list to the ready list directly. */
1981 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
1982 {
1983 xYieldRequired = pdTRUE;
1984 }
1985 else
1986 {
1987 mtCOVERAGE_TEST_MARKER();
1988 }
1989
1990 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
1991 prvAddTaskToReadyList( pxTCB );
1992 }
1993 else
1994 {
1995 /* The delayed or ready lists cannot be accessed so the task
1996 is held in the pending ready list until the scheduler is
1997 unsuspended. */
1998 vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
1999 }
2000 }
2001 else
2002 {
2003 mtCOVERAGE_TEST_MARKER();
2004 }
2005 }
2006 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
2007
2008 return xYieldRequired;
2009}
2010
2011#endif /* ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) */
2012/*-----------------------------------------------------------*/
2013
2014void vTaskStartScheduler( void )
2015{
2016 BaseType_t xReturn;
2017
2018 /* Add the idle task at the lowest priority. */
2019 #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
2020 {
2021 /* Create the idle task, storing its handle in xIdleTaskHandle so it can
2022 be returned by the xTaskGetIdleTaskHandle() function. */
2023 xReturn = xTaskCreate( prvIdleTask, "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
2024 }
2025 #else
2026 {
2027 /* Create the idle task without storing its handle. */
2028 xReturn = xTaskCreate( prvIdleTask, "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), NULL ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
2029 }
2030 #endif /* INCLUDE_xTaskGetIdleTaskHandle */
2031
2032 #if ( configUSE_TIMERS == 1 )
2033 {
2034 if( xReturn == pdPASS )
2035 {
2036 xReturn = xTimerCreateTimerTask();
2037 }
2038 else
2039 {
2040 mtCOVERAGE_TEST_MARKER();
2041 }
2042 }
2043 #endif /* configUSE_TIMERS */
2044
2045 if( xReturn == pdPASS )
2046 {
2047 /* Interrupts are turned off here, to ensure a tick does not occur
2048 before or during the call to xPortStartScheduler(). The stacks of
2049 the created tasks contain a status word with interrupts switched on
2050 so interrupts will automatically get re-enabled when the first task
2051 starts to run. */
2052 portDISABLE_INTERRUPTS();
2053
2054 #if ( configUSE_NEWLIB_REENTRANT == 1 )
2055 {
2056 /* Switch Newlib's _impure_ptr variable to point to the _reent
2057 structure specific to the task that will run first. */
2058 _impure_ptr = &( pxCurrentTCB->xNewLib_reent );
2059 }
2060 #endif /* configUSE_NEWLIB_REENTRANT */
2061
2062 xNextTaskUnblockTime = portMAX_DELAY;
2063 xSchedulerRunning = pdTRUE;
2064 xTickCount = ( TickType_t ) 0U;
2065
2066 /* If configGENERATE_RUN_TIME_STATS is defined then the following
2067 macro must be defined to configure the timer/counter used to generate
2068 the run time counter time base. */
2069 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();
2070
2071 /* Setting up the timer tick is hardware specific and thus in the
2072 portable interface. */
2073 if( xPortStartScheduler() != pdFALSE )
2074 {
2075 /* Should not reach here as if the scheduler is running the
2076 function will not return. */
2077 }
2078 else
2079 {
2080 /* Should only reach here if a task calls xTaskEndScheduler(). */
2081 }
2082 }
2083 else
2084 {
2085 /* This line will only be reached if the kernel could not be started,
2086 because there was not enough FreeRTOS heap to create the idle task
2087 or the timer task. */
2088 configASSERT( xReturn );
2089 }
2090}
2091/*-----------------------------------------------------------*/
2092
2093void vTaskEndScheduler( void )
2094{
2095 /* Stop the scheduler interrupts and call the portable scheduler end
2096 routine so the original ISRs can be restored if necessary. The port
2097 layer must ensure interrupts enable bit is left in the correct state. */
2098 portDISABLE_INTERRUPTS();
2099 xSchedulerRunning = pdFALSE;
2100 vPortEndScheduler();
2101 portENABLE_INTERRUPTS(); /* As per comment, enable interrupts. */
2102}
2103/*----------------------------------------------------------*/
2104
2105void vTaskSuspendAll( void )
2106{
2107 /* A critical section is not required as the variable is of type
2108 BaseType_t. Please read Richard Barry's reply in the following link to a
2109 post in the FreeRTOS support forum before reporting this as a bug! -
2110 http://goo.gl/wu4acr */
2111 ++uxSchedulerSuspended;
2112}
2113/*----------------------------------------------------------*/
2114
2115#if ( configUSE_TICKLESS_IDLE != 0 )
2116
2117static TickType_t prvGetExpectedIdleTime( void )
2118{
2119 TickType_t xReturn;
2120
2121 if( pxCurrentTCB->uxPriority > tskIDLE_PRIORITY )
2122 {
2123 xReturn = 0;
2124 }
2125 else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > 1 )
2126 {
2127 /* There are other idle priority tasks in the ready state. If
2128 time slicing is used then the very next tick interrupt must be
2129 processed. */
2130 xReturn = 0;
2131 }
2132 else
2133 {
2134 xReturn = xNextTaskUnblockTime - xTickCount;
2135 }
2136
2137 return xReturn;
2138}
2139
2140#endif /* configUSE_TICKLESS_IDLE */
2141/*----------------------------------------------------------*/
2142
2143BaseType_t xTaskResumeAll( void )
2144{
2145 TCB_t *pxTCB;
2146 BaseType_t xAlreadyYielded = pdFALSE;
2147
2148 /* If uxSchedulerSuspended is zero then this function does not match a
2149 previous call to vTaskSuspendAll(). */
2150 configASSERT( uxSchedulerSuspended );
2151
2152 /* It is possible that an ISR caused a task to be removed from an event
2153 list while the scheduler was suspended. If this was the case then the
2154 removed task will have been added to the xPendingReadyList. Once the
2155 scheduler has been resumed it is safe to move all the pending ready
2156 tasks from this list into their appropriate ready list. */
2157 taskENTER_CRITICAL();
2158 {
2159 --uxSchedulerSuspended;
2160
2161 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
2162 {
2163 if( uxCurrentNumberOfTasks > ( UBaseType_t ) 0U )
2164 {
2165 /* Move any readied tasks from the pending list into the
2166 appropriate ready list. */
2167 while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE )
2168 {
2169 pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) );
2170 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
2171 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
2172 prvAddTaskToReadyList( pxTCB );
2173
2174 /* If the moved task has a priority higher than the current
2175 task then a yield must be performed. */
2176 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
2177 {
2178 xYieldPending = pdTRUE;
2179 }
2180 else
2181 {
2182 mtCOVERAGE_TEST_MARKER();
2183 }
2184 }
2185
2186 /* If any ticks occurred while the scheduler was suspended then
2187 they should be processed now. This ensures the tick count does
2188 not slip, and that any delayed tasks are resumed at the correct
2189 time. */
2190 if( uxPendedTicks > ( UBaseType_t ) 0U )
2191 {
2192 while( uxPendedTicks > ( UBaseType_t ) 0U )
2193 {
2194 if( xTaskIncrementTick() != pdFALSE )
2195 {
2196 xYieldPending = pdTRUE;
2197 }
2198 else
2199 {
2200 mtCOVERAGE_TEST_MARKER();
2201 }
2202 --uxPendedTicks;
2203 }
2204 }
2205 else
2206 {
2207 mtCOVERAGE_TEST_MARKER();
2208 }
2209
2210 if( xYieldPending == pdTRUE )
2211 {
2212 #if( configUSE_PREEMPTION != 0 )
2213 {
2214 xAlreadyYielded = pdTRUE;
2215 }
2216 #endif
2217 taskYIELD_IF_USING_PREEMPTION();
2218 }
2219 else
2220 {
2221 mtCOVERAGE_TEST_MARKER();
2222 }
2223 }
2224 }
2225 else
2226 {
2227 mtCOVERAGE_TEST_MARKER();
2228 }
2229 }
2230 taskEXIT_CRITICAL();
2231
2232 return xAlreadyYielded;
2233}
2234/*-----------------------------------------------------------*/
2235
2236TickType_t xTaskGetTickCount( void )
2237{
2238 TickType_t xTicks;
2239
2240 /* Critical section required if running on a 16 bit processor. */
2241 portTICK_TYPE_ENTER_CRITICAL();
2242 {
2243 xTicks = xTickCount;
2244 }
2245 portTICK_TYPE_EXIT_CRITICAL();
2246
2247 return xTicks;
2248}
2249/*-----------------------------------------------------------*/
2250
2251TickType_t xTaskGetTickCountFromISR( void )
2252{
2253 TickType_t xReturn;
2254 UBaseType_t uxSavedInterruptStatus;
2255
2256 /* RTOS ports that support interrupt nesting have the concept of a maximum
2257 system call (or maximum API call) interrupt priority. Interrupts that are
2258 above the maximum system call priority are kept permanently enabled, even
2259 when the RTOS kernel is in a critical section, but cannot make any calls to
2260 FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h
2261 then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
2262 failure if a FreeRTOS API function is called from an interrupt that has been
2263 assigned a priority above the configured maximum system call priority.
2264 Only FreeRTOS functions that end in FromISR can be called from interrupts
2265 that have been assigned a priority at or (logically) below the maximum
2266 system call interrupt priority. FreeRTOS maintains a separate interrupt
2267 safe API to ensure interrupt entry is as fast and as simple as possible.
2268 More information (albeit Cortex-M specific) is provided on the following
2269 link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */
2270 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
2271
2272 uxSavedInterruptStatus = portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR();
2273 {
2274 xReturn = xTickCount;
2275 }
2276 portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
2277
2278 return xReturn;
2279}
2280/*-----------------------------------------------------------*/
2281
2282UBaseType_t uxTaskGetNumberOfTasks( void )
2283{
2284 /* A critical section is not required because the variables are of type
2285 BaseType_t. */
2286 return uxCurrentNumberOfTasks;
2287}
2288/*-----------------------------------------------------------*/
2289
2290#if ( INCLUDE_pcTaskGetTaskName == 1 )
2291
2292char *pcTaskGetTaskName( TaskHandle_t xTaskToQuery )
2293{
2294 TCB_t *pxTCB;
2295
2296 /* If null is passed in here then the name of the calling task is being queried. */
2297 pxTCB = prvGetTCBFromHandle( xTaskToQuery );
2298 configASSERT( pxTCB );
2299 return &( pxTCB->pcTaskName[ 0 ] );
2300}
2301
2302#endif /* INCLUDE_pcTaskGetTaskName */
2303/*-----------------------------------------------------------*/
2304
2305#if ( configUSE_TRACE_FACILITY == 1 )
2306
2307UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime )
2308{
2309 UBaseType_t uxTask = 0, uxQueue = configMAX_PRIORITIES;
2310
2311 vTaskSuspendAll();
2312 {
2313 /* Is there a space in the array for each task in the system? */
2314 if( uxArraySize >= uxCurrentNumberOfTasks )
2315 {
2316 /* Fill in an TaskStatus_t structure with information on each
2317 task in the Ready state. */
2318 do
2319 {
2320 uxQueue--;
2321 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &( pxReadyTasksLists[ uxQueue ] ), eReady );
2322
2323 } while( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
2324
2325 /* Fill in an TaskStatus_t structure with information on each
2326 task in the Blocked state. */
2327 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxDelayedTaskList, eBlocked );
2328 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxOverflowDelayedTaskList, eBlocked );
2329
2330 #if( INCLUDE_vTaskDelete == 1 )
2331 {
2332 /* Fill in an TaskStatus_t structure with information on
2333 each task that has been deleted but not yet cleaned up. */
2334 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xTasksWaitingTermination, eDeleted );
2335 }
2336 #endif
2337
2338 #if ( INCLUDE_vTaskSuspend == 1 )
2339 {
2340 /* Fill in an TaskStatus_t structure with information on
2341 each task in the Suspended state. */
2342 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xSuspendedTaskList, eSuspended );
2343 }
2344 #endif
2345
2346 #if ( configGENERATE_RUN_TIME_STATS == 1)
2347 {
2348 if( pulTotalRunTime != NULL )
2349 {
2350 #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
2351 portALT_GET_RUN_TIME_COUNTER_VALUE( ( *pulTotalRunTime ) );
2352 #else
2353 *pulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
2354 #endif
2355 }
2356 }
2357 #else
2358 {
2359 if( pulTotalRunTime != NULL )
2360 {
2361 *pulTotalRunTime = 0;
2362 }
2363 }
2364 #endif
2365 }
2366 else
2367 {
2368 mtCOVERAGE_TEST_MARKER();
2369 }
2370 }
2371 ( void ) xTaskResumeAll();
2372
2373 return uxTask;
2374}
2375
2376#endif /* configUSE_TRACE_FACILITY */
2377/*----------------------------------------------------------*/
2378
2379#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
2380
2381TaskHandle_t xTaskGetIdleTaskHandle( void )
2382{
2383 /* If xTaskGetIdleTaskHandle() is called before the scheduler has been
2384 started, then xIdleTaskHandle will be NULL. */
2385 configASSERT( ( xIdleTaskHandle != NULL ) );
2386 return xIdleTaskHandle;
2387}
2388
2389#endif /* INCLUDE_xTaskGetIdleTaskHandle */
2390/*----------------------------------------------------------*/
2391
2392/* This conditional compilation should use inequality to 0, not equality to 1.
2393This is to ensure vTaskStepTick() is available when user defined low power mode
2394implementations require configUSE_TICKLESS_IDLE to be set to a value other than
23951. */
2396#if ( configUSE_TICKLESS_IDLE != 0 )
2397
2398void vTaskStepTick( const TickType_t xTicksToJump )
2399{
2400 /* Correct the tick count value after a period during which the tick
2401 was suppressed. Note this does *not* call the tick hook function for
2402 each stepped tick. */
2403 configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime );
2404 xTickCount += xTicksToJump;
2405 traceINCREASE_TICK_COUNT( xTicksToJump );
2406}
2407
2408#endif /* configUSE_TICKLESS_IDLE */
2409/*----------------------------------------------------------*/
2410
2411BaseType_t xTaskIncrementTick( void )
2412{
2413 TCB_t * pxTCB;
2414 TickType_t xItemValue;
2415 BaseType_t xSwitchRequired = pdFALSE;
2416
2417 /* Called by the portable layer each time a tick interrupt occurs.
2418 Increments the tick then checks to see if the new tick value will cause any
2419 tasks to be unblocked. */
2420 traceTASK_INCREMENT_TICK( xTickCount );
2421 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
2422 {
2423 /* Increment the RTOS tick, switching the delayed and overflowed
2424 delayed lists if it wraps to 0. */
2425 ++xTickCount;
2426
2427 {
2428 /* Minor optimisation. The tick count cannot change in this
2429 block. */
2430 const TickType_t xConstTickCount = xTickCount;
2431
2432 if( xConstTickCount == ( TickType_t ) 0U )
2433 {
2434 taskSWITCH_DELAYED_LISTS();
2435 }
2436 else
2437 {
2438 mtCOVERAGE_TEST_MARKER();
2439 }
2440
2441 /* See if this tick has made a timeout expire. Tasks are stored in
2442 the queue in the order of their wake time - meaning once one task
2443 has been found whose block time has not expired there is no need to
2444 look any further down the list. */
2445 if( xConstTickCount >= xNextTaskUnblockTime )
2446 {
2447 for( ;; )
2448 {
2449 if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
2450 {
2451 /* The delayed list is empty. Set xNextTaskUnblockTime
2452 to the maximum possible value so it is extremely
2453 unlikely that the
2454 if( xTickCount >= xNextTaskUnblockTime ) test will pass
2455 next time through. */
2456 xNextTaskUnblockTime = portMAX_DELAY;
2457 break;
2458 }
2459 else
2460 {
2461 /* The delayed list is not empty, get the value of the
2462 item at the head of the delayed list. This is the time
2463 at which the task at the head of the delayed list must
2464 be removed from the Blocked state. */
2465 pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
2466 xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) );
2467
2468 if( xConstTickCount < xItemValue )
2469 {
2470 /* It is not time to unblock this item yet, but the
2471 item value is the time at which the task at the head
2472 of the blocked list must be removed from the Blocked
2473 state - so record the item value in
2474 xNextTaskUnblockTime. */
2475 xNextTaskUnblockTime = xItemValue;
2476 break;
2477 }
2478 else
2479 {
2480 mtCOVERAGE_TEST_MARKER();
2481 }
2482
2483 /* It is time to remove the item from the Blocked state. */
2484 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
2485
2486 /* Is the task waiting on an event also? If so remove
2487 it from the event list. */
2488 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
2489 {
2490 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
2491 }
2492 else
2493 {
2494 mtCOVERAGE_TEST_MARKER();
2495 }
2496
2497 /* Place the unblocked task into the appropriate ready
2498 list. */
2499 prvAddTaskToReadyList( pxTCB );
2500
2501 /* A task being unblocked cannot cause an immediate
2502 context switch if preemption is turned off. */
2503 #if ( configUSE_PREEMPTION == 1 )
2504 {
2505 /* Preemption is on, but a context switch should
2506 only be performed if the unblocked task has a
2507 priority that is equal to or higher than the
2508 currently executing task. */
2509 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
2510 {
2511 xSwitchRequired = pdTRUE;
2512 }
2513 else
2514 {
2515 mtCOVERAGE_TEST_MARKER();
2516 }
2517 }
2518 #endif /* configUSE_PREEMPTION */
2519 }
2520 }
2521 }
2522 }
2523
2524 /* Tasks of equal priority to the currently running task will share
2525 processing time (time slice) if preemption is on, and the application
2526 writer has not explicitly turned time slicing off. */
2527 #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )
2528 {
2529 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( UBaseType_t ) 1 )
2530 {
2531 xSwitchRequired = pdTRUE;
2532 }
2533 else
2534 {
2535 mtCOVERAGE_TEST_MARKER();
2536 }
2537 }
2538 #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */
2539
2540 #if ( configUSE_TICK_HOOK == 1 )
2541 {
2542 /* Guard against the tick hook being called when the pended tick
2543 count is being unwound (when the scheduler is being unlocked). */
2544 if( uxPendedTicks == ( UBaseType_t ) 0U )
2545 {
2546 vApplicationTickHook();
2547 }
2548 else
2549 {
2550 mtCOVERAGE_TEST_MARKER();
2551 }
2552 }
2553 #endif /* configUSE_TICK_HOOK */
2554 }
2555 else
2556 {
2557 ++uxPendedTicks;
2558
2559 /* The tick hook gets called at regular intervals, even if the
2560 scheduler is locked. */
2561 #if ( configUSE_TICK_HOOK == 1 )
2562 {
2563 vApplicationTickHook();
2564 }
2565 #endif
2566 }
2567
2568 #if ( configUSE_PREEMPTION == 1 )
2569 {
2570 if( xYieldPending != pdFALSE )
2571 {
2572 xSwitchRequired = pdTRUE;
2573 }
2574 else
2575 {
2576 mtCOVERAGE_TEST_MARKER();
2577 }
2578 }
2579 #endif /* configUSE_PREEMPTION */
2580
2581 return xSwitchRequired;
2582}
2583/*-----------------------------------------------------------*/
2584
2585#if ( configUSE_APPLICATION_TASK_TAG == 1 )
2586
2587void vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction )
2588{
2589 TCB_t *xTCB;
2590
2591 /* If xTask is NULL then it is the task hook of the calling task that is
2592 getting set. */
2593 if( xTask == NULL )
2594 {
2595 xTCB = ( TCB_t * ) pxCurrentTCB;
2596 }
2597 else
2598 {
2599 xTCB = ( TCB_t * ) xTask;
2600 }
2601
2602 /* Save the hook function in the TCB. A critical section is required as
2603 the value can be accessed from an interrupt. */
2604 taskENTER_CRITICAL();
2605 xTCB->pxTaskTag = pxHookFunction;
2606 taskEXIT_CRITICAL();
2607}
2608
2609#endif /* configUSE_APPLICATION_TASK_TAG */
2610/*-----------------------------------------------------------*/
2611
2612#if ( configUSE_APPLICATION_TASK_TAG == 1 )
2613
2614TaskHookFunction_t xTaskGetApplicationTaskTag( TaskHandle_t xTask )
2615{
2616 TCB_t *xTCB;
2617 TaskHookFunction_t xReturn;
2618
2619 /* If xTask is NULL then we are setting our own task hook. */
2620 if( xTask == NULL )
2621 {
2622 xTCB = ( TCB_t * ) pxCurrentTCB;
2623 }
2624 else
2625 {
2626 xTCB = ( TCB_t * ) xTask;
2627 }
2628
2629 /* Save the hook function in the TCB. A critical section is required as
2630 the value can be accessed from an interrupt. */
2631 taskENTER_CRITICAL();
2632 {
2633 xReturn = xTCB->pxTaskTag;
2634 }
2635 taskEXIT_CRITICAL();
2636
2637 return xReturn;
2638}
2639
2640#endif /* configUSE_APPLICATION_TASK_TAG */
2641/*-----------------------------------------------------------*/
2642
2643#if ( configUSE_APPLICATION_TASK_TAG == 1 )
2644
2645BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter )
2646{
2647 TCB_t *xTCB;
2648 BaseType_t xReturn;
2649
2650 /* If xTask is NULL then we are calling our own task hook. */
2651 if( xTask == NULL )
2652 {
2653 xTCB = ( TCB_t * ) pxCurrentTCB;
2654 }
2655 else
2656 {
2657 xTCB = ( TCB_t * ) xTask;
2658 }
2659
2660 if( xTCB->pxTaskTag != NULL )
2661 {
2662 xReturn = xTCB->pxTaskTag( pvParameter );
2663 }
2664 else
2665 {
2666 xReturn = pdFAIL;
2667 }
2668
2669 return xReturn;
2670}
2671
2672#endif /* configUSE_APPLICATION_TASK_TAG */
2673/*-----------------------------------------------------------*/
2674
2675void vTaskSwitchContext( void )
2676{
2677 if( uxSchedulerSuspended != ( UBaseType_t ) pdFALSE )
2678 {
2679 /* The scheduler is currently suspended - do not allow a context
2680 switch. */
2681 xYieldPending = pdTRUE;
2682 }
2683 else
2684 {
2685 xYieldPending = pdFALSE;
2686 traceTASK_SWITCHED_OUT();
2687
2688 #if ( configGENERATE_RUN_TIME_STATS == 1 )
2689 {
2690 #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
2691 portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime );
2692 #else
2693 ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
2694 #endif
2695
2696 /* Add the amount of time the task has been running to the
2697 accumulated time so far. The time the task started running was
2698 stored in ulTaskSwitchedInTime. Note that there is no overflow
2699 protection here so count values are only valid until the timer
2700 overflows. The guard against negative values is to protect
2701 against suspect run time stat counter implementations - which
2702 are provided by the application, not the kernel. */
2703 if( ulTotalRunTime > ulTaskSwitchedInTime )
2704 {
2705 pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime );
2706 }
2707 else
2708 {
2709 mtCOVERAGE_TEST_MARKER();
2710 }
2711 ulTaskSwitchedInTime = ulTotalRunTime;
2712 }
2713 #endif /* configGENERATE_RUN_TIME_STATS */
2714
2715 /* Check for stack overflow, if configured. */
2716 taskCHECK_FOR_STACK_OVERFLOW();
2717
2718 /* Select a new task to run using either the generic C or port
2719 optimised asm code. */
2720 taskSELECT_HIGHEST_PRIORITY_TASK();
2721 traceTASK_SWITCHED_IN();
2722
2723 #if ( configUSE_NEWLIB_REENTRANT == 1 )
2724 {
2725 /* Switch Newlib's _impure_ptr variable to point to the _reent
2726 structure specific to this task. */
2727 _impure_ptr = &( pxCurrentTCB->xNewLib_reent );
2728 }
2729 #endif /* configUSE_NEWLIB_REENTRANT */
2730 }
2731}
2732/*-----------------------------------------------------------*/
2733
2734void vTaskPlaceOnEventList( List_t * const pxEventList, const TickType_t xTicksToWait )
2735{
2736 TickType_t xTimeToWake;
2737
2738 configASSERT( pxEventList );
2739
2740 /* THIS FUNCTION MUST BE CALLED WITH EITHER INTERRUPTS DISABLED OR THE
2741 SCHEDULER SUSPENDED AND THE QUEUE BEING ACCESSED LOCKED. */
2742
2743 /* Place the event list item of the TCB in the appropriate event list.
2744 This is placed in the list in priority order so the highest priority task
2745 is the first to be woken by the event. The queue that contains the event
2746 list is locked, preventing simultaneous access from interrupts. */
2747 vListInsert( pxEventList, &( pxCurrentTCB->xEventListItem ) );
2748
2749 /* The task must be removed from from the ready list before it is added to
2750 the blocked list as the same list item is used for both lists. Exclusive
2751 access to the ready lists guaranteed because the scheduler is locked. */
2752 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
2753 {
2754 /* The current task must be in a ready list, so there is no need to
2755 check, and the port reset macro can be called directly. */
2756 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
2757 }
2758 else
2759 {
2760 mtCOVERAGE_TEST_MARKER();
2761 }
2762
2763 #if ( INCLUDE_vTaskSuspend == 1 )
2764 {
2765 if( xTicksToWait == portMAX_DELAY )
2766 {
2767 /* Add the task to the suspended task list instead of a delayed task
2768 list to ensure the task is not woken by a timing event. It will
2769 block indefinitely. */
2770 vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) );
2771 }
2772 else
2773 {
2774 /* Calculate the time at which the task should be woken if the event
2775 does not occur. This may overflow but this doesn't matter, the
2776 scheduler will handle it. */
2777 xTimeToWake = xTickCount + xTicksToWait;
2778 prvAddCurrentTaskToDelayedList( xTimeToWake );
2779 }
2780 }
2781 #else /* INCLUDE_vTaskSuspend */
2782 {
2783 /* Calculate the time at which the task should be woken if the event does
2784 not occur. This may overflow but this doesn't matter, the scheduler
2785 will handle it. */
2786 xTimeToWake = xTickCount + xTicksToWait;
2787 prvAddCurrentTaskToDelayedList( xTimeToWake );
2788 }
2789 #endif /* INCLUDE_vTaskSuspend */
2790}
2791/*-----------------------------------------------------------*/
2792
2793void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, const TickType_t xItemValue, const TickType_t xTicksToWait )
2794{
2795 TickType_t xTimeToWake;
2796
2797 configASSERT( pxEventList );
2798
2799 /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by
2800 the event groups implementation. */
2801 configASSERT( uxSchedulerSuspended != 0 );
2802
2803 /* Store the item value in the event list item. It is safe to access the
2804 event list item here as interrupts won't access the event list item of a
2805 task that is not in the Blocked state. */
2806 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE );
2807
2808 /* Place the event list item of the TCB at the end of the appropriate event
2809 list. It is safe to access the event list here because it is part of an
2810 event group implementation - and interrupts don't access event groups
2811 directly (instead they access them indirectly by pending function calls to
2812 the task level). */
2813 vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) );
2814
2815 /* The task must be removed from the ready list before it is added to the
2816 blocked list. Exclusive access can be assured to the ready list as the
2817 scheduler is locked. */
2818 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
2819 {
2820 /* The current task must be in a ready list, so there is no need to
2821 check, and the port reset macro can be called directly. */
2822 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
2823 }
2824 else
2825 {
2826 mtCOVERAGE_TEST_MARKER();
2827 }
2828
2829 #if ( INCLUDE_vTaskSuspend == 1 )
2830 {
2831 if( xTicksToWait == portMAX_DELAY )
2832 {
2833 /* Add the task to the suspended task list instead of a delayed task
2834 list to ensure it is not woken by a timing event. It will block
2835 indefinitely. */
2836 vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) );
2837 }
2838 else
2839 {
2840 /* Calculate the time at which the task should be woken if the event
2841 does not occur. This may overflow but this doesn't matter, the
2842 kernel will manage it correctly. */
2843 xTimeToWake = xTickCount + xTicksToWait;
2844 prvAddCurrentTaskToDelayedList( xTimeToWake );
2845 }
2846 }
2847 #else /* INCLUDE_vTaskSuspend */
2848 {
2849 /* Calculate the time at which the task should be woken if the event does
2850 not occur. This may overflow but this doesn't matter, the kernel
2851 will manage it correctly. */
2852 xTimeToWake = xTickCount + xTicksToWait;
2853 prvAddCurrentTaskToDelayedList( xTimeToWake );
2854 }
2855 #endif /* INCLUDE_vTaskSuspend */
2856}
2857/*-----------------------------------------------------------*/
2858
2859#if configUSE_TIMERS == 1
2860
2861void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, const TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely )
2862{
2863 TickType_t xTimeToWake;
2864
2865 configASSERT( pxEventList );
2866
2867 /* This function should not be called by application code hence the
2868 'Restricted' in its name. It is not part of the public API. It is
2869 designed for use by kernel code, and has special calling requirements -
2870 it should be called with the scheduler suspended. */
2871
2872
2873 /* Place the event list item of the TCB in the appropriate event list.
2874 In this case it is assume that this is the only task that is going to
2875 be waiting on this event list, so the faster vListInsertEnd() function
2876 can be used in place of vListInsert. */
2877 vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) );
2878
2879 /* We must remove this task from the ready list before adding it to the
2880 blocked list as the same list item is used for both lists. This
2881 function is called with the scheduler locked so interrupts will not
2882 access the lists at the same time. */
2883 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
2884 {
2885 /* The current task must be in a ready list, so there is no need to
2886 check, and the port reset macro can be called directly. */
2887 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
2888 }
2889 else
2890 {
2891 mtCOVERAGE_TEST_MARKER();
2892 }
2893
2894 /* If vTaskSuspend() is available then the suspended task list is also
2895 available and a task that is blocking indefinitely can enter the
2896 suspended state (it is not really suspended as it will re-enter the
2897 Ready state when the event it is waiting indefinitely for occurs).
2898 Blocking indefinitely is useful when using tickless idle mode as when
2899 all tasks are blocked indefinitely all timers can be turned off. */
2900 #if( INCLUDE_vTaskSuspend == 1 )
2901 {
2902 if( xWaitIndefinitely == pdTRUE )
2903 {
2904 /* Add the task to the suspended task list instead of a delayed
2905 task list to ensure the task is not woken by a timing event. It
2906 will block indefinitely. */
2907 vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) );
2908 }
2909 else
2910 {
2911 /* Calculate the time at which the task should be woken if the
2912 event does not occur. This may overflow but this doesn't
2913 matter. */
2914 xTimeToWake = xTickCount + xTicksToWait;
2915 traceTASK_DELAY_UNTIL();
2916 prvAddCurrentTaskToDelayedList( xTimeToWake );
2917 }
2918 }
2919 #else
2920 {
2921 /* Calculate the time at which the task should be woken if the event
2922 does not occur. This may overflow but this doesn't matter. */
2923 xTimeToWake = xTickCount + xTicksToWait;
2924 traceTASK_DELAY_UNTIL();
2925 prvAddCurrentTaskToDelayedList( xTimeToWake );
2926
2927 /* Remove compiler warnings when INCLUDE_vTaskSuspend() is not
2928 defined. */
2929 ( void ) xWaitIndefinitely;
2930 }
2931 #endif
2932}
2933
2934#endif /* configUSE_TIMERS */
2935/*-----------------------------------------------------------*/
2936
2937BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList )
2938{
2939 TCB_t *pxUnblockedTCB;
2940 BaseType_t xReturn;
2941
2942 /* THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION. It can also be
2943 called from a critical section within an ISR. */
2944
2945 /* The event list is sorted in priority order, so the first in the list can
2946 be removed as it is known to be the highest priority. Remove the TCB from
2947 the delayed list, and add it to the ready list.
2948
2949 If an event is for a queue that is locked then this function will never
2950 get called - the lock count on the queue will get modified instead. This
2951 means exclusive access to the event list is guaranteed here.
2952
2953 This function assumes that a check has already been made to ensure that
2954 pxEventList is not empty. */
2955 pxUnblockedTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
2956 configASSERT( pxUnblockedTCB );
2957 ( void ) uxListRemove( &( pxUnblockedTCB->xEventListItem ) );
2958
2959 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
2960 {
2961 ( void ) uxListRemove( &( pxUnblockedTCB->xGenericListItem ) );
2962 prvAddTaskToReadyList( pxUnblockedTCB );
2963 }
2964 else
2965 {
2966 /* The delayed and ready lists cannot be accessed, so hold this task
2967 pending until the scheduler is resumed. */
2968 vListInsertEnd( &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );
2969 }
2970
2971 if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority )
2972 {
2973 /* Return true if the task removed from the event list has a higher
2974 priority than the calling task. This allows the calling task to know if
2975 it should force a context switch now. */
2976 xReturn = pdTRUE;
2977
2978 /* Mark that a yield is pending in case the user is not using the
2979 "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */
2980 xYieldPending = pdTRUE;
2981 }
2982 else
2983 {
2984 xReturn = pdFALSE;
2985 }
2986
2987 #if( configUSE_TICKLESS_IDLE != 0 )
2988 {
2989 /* If a task is blocked on a kernel object then xNextTaskUnblockTime
2990 might be set to the blocked task's time out time. If the task is
2991 unblocked for a reason other than a timeout xNextTaskUnblockTime is
2992 normally left unchanged, because it is automatically reset to a new
2993 value when the tick count equals xNextTaskUnblockTime. However if
2994 tickless idling is used it might be more important to enter sleep mode
2995 at the earliest possible time - so reset xNextTaskUnblockTime here to
2996 ensure it is updated at the earliest possible time. */
2997 prvResetNextTaskUnblockTime();
2998 }
2999 #endif
3000
3001 return xReturn;
3002}
3003/*-----------------------------------------------------------*/
3004
3005BaseType_t xTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue )
3006{
3007 TCB_t *pxUnblockedTCB;
3008 BaseType_t xReturn;
3009
3010 /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by
3011 the event flags implementation. */
3012 configASSERT( uxSchedulerSuspended != pdFALSE );
3013
3014 /* Store the new item value in the event list. */
3015 listSET_LIST_ITEM_VALUE( pxEventListItem, xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE );
3016
3017 /* Remove the event list form the event flag. Interrupts do not access
3018 event flags. */
3019 pxUnblockedTCB = ( TCB_t * ) listGET_LIST_ITEM_OWNER( pxEventListItem );
3020 configASSERT( pxUnblockedTCB );
3021 ( void ) uxListRemove( pxEventListItem );
3022
3023 /* Remove the task from the delayed list and add it to the ready list. The
3024 scheduler is suspended so interrupts will not be accessing the ready
3025 lists. */
3026 ( void ) uxListRemove( &( pxUnblockedTCB->xGenericListItem ) );
3027 prvAddTaskToReadyList( pxUnblockedTCB );
3028
3029 if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority )
3030 {
3031 /* Return true if the task removed from the event list has
3032 a higher priority than the calling task. This allows
3033 the calling task to know if it should force a context
3034 switch now. */
3035 xReturn = pdTRUE;
3036
3037 /* Mark that a yield is pending in case the user is not using the
3038 "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */
3039 xYieldPending = pdTRUE;
3040 }
3041 else
3042 {
3043 xReturn = pdFALSE;
3044 }
3045
3046 return xReturn;
3047}
3048/*-----------------------------------------------------------*/
3049
3050void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut )
3051{
3052 configASSERT( pxTimeOut );
3053 pxTimeOut->xOverflowCount = xNumOfOverflows;
3054 pxTimeOut->xTimeOnEntering = xTickCount;
3055}
3056/*-----------------------------------------------------------*/
3057
3058BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait )
3059{
3060 BaseType_t xReturn;
3061
3062 configASSERT( pxTimeOut );
3063 configASSERT( pxTicksToWait );
3064
3065 taskENTER_CRITICAL();
3066 {
3067 /* Minor optimisation. The tick count cannot change in this block. */
3068 const TickType_t xConstTickCount = xTickCount;
3069
3070 #if ( INCLUDE_vTaskSuspend == 1 )
3071 /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is
3072 the maximum block time then the task should block indefinitely, and
3073 therefore never time out. */
3074 if( *pxTicksToWait == portMAX_DELAY )
3075 {
3076 xReturn = pdFALSE;
3077 }
3078 else /* We are not blocking indefinitely, perform the checks below. */
3079 #endif
3080
3081 if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( xConstTickCount >= pxTimeOut->xTimeOnEntering ) ) /*lint !e525 Indentation preferred as is to make code within pre-processor directives clearer. */
3082 {
3083 /* The tick count is greater than the time at which vTaskSetTimeout()
3084 was called, but has also overflowed since vTaskSetTimeOut() was called.
3085 It must have wrapped all the way around and gone past us again. This
3086 passed since vTaskSetTimeout() was called. */
3087 xReturn = pdTRUE;
3088 }
3089 else if( ( xConstTickCount - pxTimeOut->xTimeOnEntering ) < *pxTicksToWait )
3090 {
3091 /* Not a genuine timeout. Adjust parameters for time remaining. */
3092 *pxTicksToWait -= ( xConstTickCount - pxTimeOut->xTimeOnEntering );
3093 vTaskSetTimeOutState( pxTimeOut );
3094 xReturn = pdFALSE;
3095 }
3096 else
3097 {
3098 xReturn = pdTRUE;
3099 }
3100 }
3101 taskEXIT_CRITICAL();
3102
3103 return xReturn;
3104}
3105/*-----------------------------------------------------------*/
3106
3107void vTaskMissedYield( void )
3108{
3109 xYieldPending = pdTRUE;
3110}
3111/*-----------------------------------------------------------*/
3112
3113#if ( configUSE_TRACE_FACILITY == 1 )
3114
3115UBaseType_t uxTaskGetTaskNumber( TaskHandle_t xTask )
3116{
3117 UBaseType_t uxReturn;
3118 TCB_t *pxTCB;
3119
3120 if( xTask != NULL )
3121 {
3122 pxTCB = ( TCB_t * ) xTask;
3123 uxReturn = pxTCB->uxTaskNumber;
3124 }
3125 else
3126 {
3127 uxReturn = 0U;
3128 }
3129
3130 return uxReturn;
3131}
3132
3133#endif /* configUSE_TRACE_FACILITY */
3134/*-----------------------------------------------------------*/
3135
3136#if ( configUSE_TRACE_FACILITY == 1 )
3137
3138void vTaskSetTaskNumber( TaskHandle_t xTask, const UBaseType_t uxHandle )
3139{
3140 TCB_t *pxTCB;
3141
3142 if( xTask != NULL )
3143 {
3144 pxTCB = ( TCB_t * ) xTask;
3145 pxTCB->uxTaskNumber = uxHandle;
3146 }
3147}
3148
3149#endif /* configUSE_TRACE_FACILITY */
3150
3151/*
3152* -----------------------------------------------------------
3153* The Idle task.
3154* ----------------------------------------------------------
3155*
3156* The portTASK_FUNCTION() macro is used to allow port/compiler specific
3157* language extensions. The equivalent prototype for this function is:
3158*
3159* void prvIdleTask( void *pvParameters );
3160*
3161*/
3162static portTASK_FUNCTION( prvIdleTask, pvParameters )
3163{
3164 /* Stop warnings. */
3165 ( void ) pvParameters;
3166
3167 for( ;; )
3168 {
3169 /* See if any tasks have been deleted. */
3170 prvCheckTasksWaitingTermination();
3171
3172 #if ( configUSE_PREEMPTION == 0 )
3173 {
3174 /* If we are not using preemption we keep forcing a task switch to
3175 see if any other task has become available. If we are using
3176 preemption we don't need to do this as any task becoming available
3177 will automatically get the processor anyway. */
3178 taskYIELD();
3179 }
3180 #endif /* configUSE_PREEMPTION */
3181
3182 #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
3183 {
3184 /* When using preemption tasks of equal priority will be
3185 timesliced. If a task that is sharing the idle priority is ready
3186 to run then the idle task should yield before the end of the
3187 timeslice.
3188
3189 A critical region is not required here as we are just reading from
3190 the list, and an occasional incorrect value will not matter. If
3191 the ready list at the idle priority contains more than one task
3192 then a task other than the idle task is ready to execute. */
3193 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( UBaseType_t ) 1 )
3194 {
3195 taskYIELD();
3196 }
3197 else
3198 {
3199 mtCOVERAGE_TEST_MARKER();
3200 }
3201 }
3202 #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */
3203
3204 #if ( configUSE_IDLE_HOOK == 1 )
3205 {
3206 extern void vApplicationIdleHook( void );
3207
3208 /* Call the user defined function from within the idle task. This
3209 allows the application designer to add background functionality
3210 without the overhead of a separate task.
3211 NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
3212 CALL A FUNCTION THAT MIGHT BLOCK. */
3213 vApplicationIdleHook();
3214 }
3215 #endif /* configUSE_IDLE_HOOK */
3216
3217 /* This conditional compilation should use inequality to 0, not equality
3218 to 1. This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when
3219 user defined low power mode implementations require
3220 configUSE_TICKLESS_IDLE to be set to a value other than 1. */
3221 #if ( configUSE_TICKLESS_IDLE != 0 )
3222 {
3223 TickType_t xExpectedIdleTime;
3224
3225 /* It is not desirable to suspend then resume the scheduler on
3226 each iteration of the idle task. Therefore, a preliminary
3227 test of the expected idle time is performed without the
3228 scheduler suspended. The result here is not necessarily
3229 valid. */
3230 xExpectedIdleTime = prvGetExpectedIdleTime();
3231
3232 if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
3233 {
3234 vTaskSuspendAll();
3235 {
3236 /* Now the scheduler is suspended, the expected idle
3237 time can be sampled again, and this time its value can
3238 be used. */
3239 configASSERT( xNextTaskUnblockTime >= xTickCount );
3240 xExpectedIdleTime = prvGetExpectedIdleTime();
3241
3242 if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
3243 {
3244 traceLOW_POWER_IDLE_BEGIN();
3245 portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime );
3246 traceLOW_POWER_IDLE_END();
3247 }
3248 else
3249 {
3250 mtCOVERAGE_TEST_MARKER();
3251 }
3252 }
3253 ( void ) xTaskResumeAll();
3254 }
3255 else
3256 {
3257 mtCOVERAGE_TEST_MARKER();
3258 }
3259 }
3260 #endif /* configUSE_TICKLESS_IDLE */
3261 }
3262}
3263/*-----------------------------------------------------------*/
3264
3265#if( configUSE_TICKLESS_IDLE != 0 )
3266
3267eSleepModeStatus eTaskConfirmSleepModeStatus( void )
3268{
3269 /* The idle task exists in addition to the application tasks. */
3270 const UBaseType_t uxNonApplicationTasks = 1;
3271 eSleepModeStatus eReturn = eStandardSleep;
3272
3273 if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0 )
3274 {
3275 /* A task was made ready while the scheduler was suspended. */
3276 eReturn = eAbortSleep;
3277 }
3278 else if( xYieldPending != pdFALSE )
3279 {
3280 /* A yield was pended while the scheduler was suspended. */
3281 eReturn = eAbortSleep;
3282 }
3283 else
3284 {
3285 /* If all the tasks are in the suspended list (which might mean they
3286 have an infinite block time rather than actually being suspended)
3287 then it is safe to turn all clocks off and just wait for external
3288 interrupts. */
3289 if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) )
3290 {
3291 eReturn = eNoTasksWaitingTimeout;
3292 }
3293 else
3294 {
3295 mtCOVERAGE_TEST_MARKER();
3296 }
3297 }
3298
3299 return eReturn;
3300}
3301
3302#endif /* configUSE_TICKLESS_IDLE */
3303/*-----------------------------------------------------------*/
3304
3305static void prvInitialiseTCBVariables( TCB_t * const pxTCB, const char * const pcName, UBaseType_t uxPriority, const MemoryRegion_t * const xRegions, const uint16_t usStackDepth ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
3306{
3307 UBaseType_t x;
3308
3309 /* Store the task name in the TCB. */
3310 for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
3311 {
3312 pxTCB->pcTaskName[ x ] = pcName[ x ];
3313
3314 /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than
3315 configMAX_TASK_NAME_LEN characters just in case the memory after the
3316 string is not accessible (extremely unlikely). */
3317 if( pcName[ x ] == 0x00 )
3318 {
3319 break;
3320 }
3321 else
3322 {
3323 mtCOVERAGE_TEST_MARKER();
3324 }
3325 }
3326
3327 /* Ensure the name string is terminated in the case that the string length
3328 was greater or equal to configMAX_TASK_NAME_LEN. */
3329 pxTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0';
3330
3331 /* This is used as an array index so must ensure it's not too large. First
3332 remove the privilege bit if one is present. */
3333 if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
3334 {
3335 uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
3336 }
3337 else
3338 {
3339 mtCOVERAGE_TEST_MARKER();
3340 }
3341
3342 pxTCB->uxPriority = uxPriority;
3343 #if ( configUSE_MUTEXES == 1 )
3344 {
3345 pxTCB->uxBasePriority = uxPriority;
3346 pxTCB->uxMutexesHeld = 0;
3347 }
3348 #endif /* configUSE_MUTEXES */
3349
3350 vListInitialiseItem( &( pxTCB->xGenericListItem ) );
3351 vListInitialiseItem( &( pxTCB->xEventListItem ) );
3352
3353 /* Set the pxTCB as a link back from the ListItem_t. This is so we can get
3354 back to the containing TCB from a generic item in a list. */
3355 listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB );
3356
3357 /* Event lists are always in priority order. */
3358 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
3359 listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB );
3360
3361 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
3362 {
3363 pxTCB->uxCriticalNesting = ( UBaseType_t ) 0U;
3364 }
3365 #endif /* portCRITICAL_NESTING_IN_TCB */
3366
3367 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
3368 {
3369 pxTCB->pxTaskTag = NULL;
3370 }
3371 #endif /* configUSE_APPLICATION_TASK_TAG */
3372
3373 #if ( configGENERATE_RUN_TIME_STATS == 1 )
3374 {
3375 pxTCB->ulRunTimeCounter = 0UL;
3376 }
3377 #endif /* configGENERATE_RUN_TIME_STATS */
3378
3379 #if ( portUSING_MPU_WRAPPERS == 1 )
3380 {
3381 vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth );
3382 }
3383 #else /* portUSING_MPU_WRAPPERS */
3384 {
3385 ( void ) xRegions;
3386 ( void ) usStackDepth;
3387 }
3388 #endif /* portUSING_MPU_WRAPPERS */
3389
3390 #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 )
3391 {
3392 for( x = 0; x < ( UBaseType_t ) configNUM_THREAD_LOCAL_STORAGE_POINTERS; x++ )
3393 {
3394 pxTCB->pvThreadLocalStoragePointers[ x ] = NULL;
3395 }
3396 }
3397 #endif
3398
3399 #if ( configUSE_TASK_NOTIFICATIONS == 1 )
3400 {
3401 pxTCB->ulNotifiedValue = 0;
3402 pxTCB->eNotifyState = eNotWaitingNotification;
3403 }
3404 #endif
3405
3406 #if ( configUSE_NEWLIB_REENTRANT == 1 )
3407 {
3408 /* Initialise this task's Newlib reent structure. */
3409 _REENT_INIT_PTR( ( &( pxTCB->xNewLib_reent ) ) );
3410 }
3411 #endif /* configUSE_NEWLIB_REENTRANT */
3412}
3413/*-----------------------------------------------------------*/
3414
3415#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 )
3416
3417void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue )
3418{
3419 TCB_t *pxTCB;
3420
3421 if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS )
3422 {
3423 pxTCB = prvGetTCBFromHandle( xTaskToSet );
3424 pxTCB->pvThreadLocalStoragePointers[ xIndex ] = pvValue;
3425 }
3426}
3427
3428#endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS */
3429/*-----------------------------------------------------------*/
3430
3431#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 )
3432
3433void *pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery, BaseType_t xIndex )
3434{
3435 void *pvReturn = NULL;
3436 TCB_t *pxTCB;
3437
3438 if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS )
3439 {
3440 pxTCB = prvGetTCBFromHandle( xTaskToQuery );
3441 pvReturn = pxTCB->pvThreadLocalStoragePointers[ xIndex ];
3442 }
3443 else
3444 {
3445 pvReturn = NULL;
3446 }
3447
3448 return pvReturn;
3449}
3450
3451#endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS */
3452/*-----------------------------------------------------------*/
3453
3454#if ( portUSING_MPU_WRAPPERS == 1 )
3455
3456void vTaskAllocateMPURegions( TaskHandle_t xTaskToModify, const MemoryRegion_t * const xRegions )
3457{
3458 TCB_t *pxTCB;
3459
3460 /* If null is passed in here then we are modifying the MPU settings of
3461 the calling task. */
3462 pxTCB = prvGetTCBFromHandle( xTaskToModify );
3463
3464 vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 );
3465}
3466
3467#endif /* portUSING_MPU_WRAPPERS */
3468/*-----------------------------------------------------------*/
3469
3470static void prvInitialiseTaskLists( void )
3471{
3472 UBaseType_t uxPriority;
3473
3474 for( uxPriority = ( UBaseType_t ) 0U; uxPriority < ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ )
3475 {
3476 vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) );
3477 }
3478
3479 vListInitialise( &xDelayedTaskList1 );
3480 vListInitialise( &xDelayedTaskList2 );
3481 vListInitialise( &xPendingReadyList );
3482
3483 #if ( INCLUDE_vTaskDelete == 1 )
3484 {
3485 vListInitialise( &xTasksWaitingTermination );
3486 }
3487 #endif /* INCLUDE_vTaskDelete */
3488
3489 #if ( INCLUDE_vTaskSuspend == 1 )
3490 {
3491 vListInitialise( &xSuspendedTaskList );
3492 }
3493 #endif /* INCLUDE_vTaskSuspend */
3494
3495 /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
3496 using list2. */
3497 pxDelayedTaskList = &xDelayedTaskList1;
3498 pxOverflowDelayedTaskList = &xDelayedTaskList2;
3499}
3500/*-----------------------------------------------------------*/
3501
3502static void prvCheckTasksWaitingTermination( void )
3503{
3504 #if ( INCLUDE_vTaskDelete == 1 )
3505 {
3506 BaseType_t xListIsEmpty;
3507
3508 /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
3509 too often in the idle task. */
3510 while( uxTasksDeleted > ( UBaseType_t ) 0U )
3511 {
3512 vTaskSuspendAll();
3513 {
3514 xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
3515 }
3516 ( void ) xTaskResumeAll();
3517
3518 if( xListIsEmpty == pdFALSE )
3519 {
3520 TCB_t *pxTCB;
3521
3522 taskENTER_CRITICAL();
3523 {
3524 pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) );
3525 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
3526 --uxCurrentNumberOfTasks;
3527 --uxTasksDeleted;
3528 }
3529 taskEXIT_CRITICAL();
3530
3531 prvDeleteTCB( pxTCB );
3532 }
3533 else
3534 {
3535 mtCOVERAGE_TEST_MARKER();
3536 }
3537 }
3538 }
3539 #endif /* vTaskDelete */
3540}
3541/*-----------------------------------------------------------*/
3542
3543static void prvAddCurrentTaskToDelayedList( const TickType_t xTimeToWake )
3544{
3545 /* The list item will be inserted in wake time order. */
3546 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
3547
3548 if( xTimeToWake < xTickCount )
3549 {
3550 /* Wake time has overflowed. Place this item in the overflow list. */
3551 vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xGenericListItem ) );
3552 }
3553 else
3554 {
3555 /* The wake time has not overflowed, so the current block list is used. */
3556 vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xGenericListItem ) );
3557
3558 /* If the task entering the blocked state was placed at the head of the
3559 list of blocked tasks then xNextTaskUnblockTime needs to be updated
3560 too. */
3561 if( xTimeToWake < xNextTaskUnblockTime )
3562 {
3563 xNextTaskUnblockTime = xTimeToWake;
3564 }
3565 else
3566 {
3567 mtCOVERAGE_TEST_MARKER();
3568 }
3569 }
3570}
3571/*-----------------------------------------------------------*/
3572
3573static TCB_t *prvAllocateTCBAndStack( const uint16_t usStackDepth, StackType_t * const puxStackBuffer )
3574{
3575 TCB_t *pxNewTCB;
3576
3577 /* If the stack grows down then allocate the stack then the TCB so the stack
3578 does not grow into the TCB. Likewise if the stack grows up then allocate
3579 the TCB then the stack. */
3580 #if( portSTACK_GROWTH > 0 )
3581 {
3582 /* Allocate space for the TCB. Where the memory comes from depends on
3583 the implementation of the port malloc function. */
3584 pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
3585
3586 if( pxNewTCB != NULL )
3587 {
3588 /* Allocate space for the stack used by the task being created.
3589 The base of the stack memory stored in the TCB so the task can
3590 be deleted later if required. */
3591 pxNewTCB->pxStack = ( StackType_t * ) pvPortMallocAligned( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ), puxStackBuffer ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
3592
3593 if( pxNewTCB->pxStack == NULL )
3594 {
3595 /* Could not allocate the stack. Delete the allocated TCB. */
3596 vPortFree( pxNewTCB );
3597 pxNewTCB = NULL;
3598 }
3599 }
3600 }
3601 #else /* portSTACK_GROWTH */
3602 {
3603 StackType_t *pxStack;
3604
3605 /* Allocate space for the stack used by the task being created. */
3606 pxStack = ( StackType_t * ) pvPortMallocAligned( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ), puxStackBuffer ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
3607
3608 if( pxStack != NULL )
3609 {
3610 /* Allocate space for the TCB. Where the memory comes from depends
3611 on the implementation of the port malloc function. */
3612 pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
3613
3614 if( pxNewTCB != NULL )
3615 {
3616 /* Store the stack location in the TCB. */
3617 pxNewTCB->pxStack = pxStack;
3618 }
3619 else
3620 {
3621 /* The stack cannot be used as the TCB was not created. Free it
3622 again. */
3623 vPortFree( pxStack );
3624 }
3625 }
3626 else
3627 {
3628 pxNewTCB = NULL;
3629 }
3630 }
3631 #endif /* portSTACK_GROWTH */
3632
3633 if( pxNewTCB != NULL )
3634 {
3635 /* Avoid dependency on memset() if it is not required. */
3636 #if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
3637 {
3638 /* Just to help debugging. */
3639 ( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) usStackDepth * sizeof( StackType_t ) );
3640 }
3641 #endif /* ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) ) */
3642 }
3643
3644 return pxNewTCB;
3645}
3646/*-----------------------------------------------------------*/
3647
3648#if ( configUSE_TRACE_FACILITY == 1 )
3649
3650static UBaseType_t prvListTaskWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState )
3651{
3652 volatile TCB_t *pxNextTCB, *pxFirstTCB;
3653 UBaseType_t uxTask = 0;
3654
3655 if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 )
3656 {
3657 listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
3658
3659 /* Populate an TaskStatus_t structure within the
3660 pxTaskStatusArray array for each task that is referenced from
3661 pxList. See the definition of TaskStatus_t in task.h for the
3662 meaning of each TaskStatus_t structure member. */
3663 do
3664 {
3665 listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
3666
3667 pxTaskStatusArray[ uxTask ].xHandle = ( TaskHandle_t ) pxNextTCB;
3668 pxTaskStatusArray[ uxTask ].pcTaskName = ( const char * ) &( pxNextTCB->pcTaskName [ 0 ] );
3669 pxTaskStatusArray[ uxTask ].xTaskNumber = pxNextTCB->uxTCBNumber;
3670 pxTaskStatusArray[ uxTask ].eCurrentState = eState;
3671 pxTaskStatusArray[ uxTask ].uxCurrentPriority = pxNextTCB->uxPriority;
3672
3673 #if ( INCLUDE_vTaskSuspend == 1 )
3674 {
3675 /* If the task is in the suspended list then there is a chance
3676 it is actually just blocked indefinitely - so really it should
3677 be reported as being in the Blocked state. */
3678 if( eState == eSuspended )
3679 {
3680 if( listLIST_ITEM_CONTAINER( &( pxNextTCB->xEventListItem ) ) != NULL )
3681 {
3682 pxTaskStatusArray[ uxTask ].eCurrentState = eBlocked;
3683 }
3684 }
3685 }
3686 #endif /* INCLUDE_vTaskSuspend */
3687
3688 #if ( configUSE_MUTEXES == 1 )
3689 {
3690 pxTaskStatusArray[ uxTask ].uxBasePriority = pxNextTCB->uxBasePriority;
3691 }
3692 #else
3693 {
3694 pxTaskStatusArray[ uxTask ].uxBasePriority = 0;
3695 }
3696 #endif
3697
3698 #if ( configGENERATE_RUN_TIME_STATS == 1 )
3699 {
3700 pxTaskStatusArray[ uxTask ].ulRunTimeCounter = pxNextTCB->ulRunTimeCounter;
3701 }
3702 #else
3703 {
3704 pxTaskStatusArray[ uxTask ].ulRunTimeCounter = 0;
3705 }
3706 #endif
3707
3708 #if ( portSTACK_GROWTH > 0 )
3709 {
3710 pxTaskStatusArray[ uxTask ].usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxNextTCB->pxEndOfStack );
3711 }
3712 #else
3713 {
3714 pxTaskStatusArray[ uxTask ].usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxNextTCB->pxStack );
3715 }
3716 #endif
3717
3718 uxTask++;
3719
3720 } while( pxNextTCB != pxFirstTCB );
3721 }
3722 else
3723 {
3724 mtCOVERAGE_TEST_MARKER();
3725 }
3726
3727 return uxTask;
3728}
3729
3730#endif /* configUSE_TRACE_FACILITY */
3731/*-----------------------------------------------------------*/
3732
3733#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
3734
3735static uint16_t prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte )
3736{
3737 uint32_t ulCount = 0U;
3738
3739 while( *pucStackByte == ( uint8_t ) tskSTACK_FILL_BYTE )
3740 {
3741 pucStackByte -= portSTACK_GROWTH;
3742 ulCount++;
3743 }
3744
3745 ulCount /= ( uint32_t ) sizeof( StackType_t );
3746
3747 return ( uint16_t ) ulCount;
3748}
3749
3750#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) */
3751/*-----------------------------------------------------------*/
3752
3753#if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )
3754
3755UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask )
3756{
3757 TCB_t *pxTCB;
3758 uint8_t *pucEndOfStack;
3759 UBaseType_t uxReturn;
3760
3761 pxTCB = prvGetTCBFromHandle( xTask );
3762
3763 #if portSTACK_GROWTH < 0
3764 {
3765 pucEndOfStack = ( uint8_t * ) pxTCB->pxStack;
3766 }
3767 #else
3768 {
3769 pucEndOfStack = ( uint8_t * ) pxTCB->pxEndOfStack;
3770 }
3771 #endif
3772
3773 uxReturn = ( UBaseType_t ) prvTaskCheckFreeStackSpace( pucEndOfStack );
3774
3775 return uxReturn;
3776}
3777
3778#endif /* INCLUDE_uxTaskGetStackHighWaterMark */
3779/*-----------------------------------------------------------*/
3780
3781#if ( INCLUDE_vTaskDelete == 1 )
3782
3783static void prvDeleteTCB( TCB_t *pxTCB )
3784{
3785 /* This call is required specifically for the TriCore port. It must be
3786 above the vPortFree() calls. The call is also used by ports/demos that
3787 want to allocate and clean RAM statically. */
3788 portCLEAN_UP_TCB( pxTCB );
3789
3790 /* Free up the memory allocated by the scheduler for the task. It is up
3791 to the task to free any memory allocated at the application level. */
3792 #if ( configUSE_NEWLIB_REENTRANT == 1 )
3793 {
3794 _reclaim_reent( &( pxTCB->xNewLib_reent ) );
3795 }
3796 #endif /* configUSE_NEWLIB_REENTRANT */
3797
3798 #if( portUSING_MPU_WRAPPERS == 1 )
3799 {
3800 /* Only free the stack if it was allocated dynamically in the first
3801 place. */
3802 if( pxTCB->xUsingStaticallyAllocatedStack == pdFALSE )
3803 {
3804 vPortFreeAligned( pxTCB->pxStack );
3805 }
3806 }
3807 #else
3808 {
3809 vPortFreeAligned( pxTCB->pxStack );
3810 }
3811 #endif
3812
3813 vPortFree( pxTCB );
3814}
3815
3816#endif /* INCLUDE_vTaskDelete */
3817/*-----------------------------------------------------------*/
3818
3819static void prvResetNextTaskUnblockTime( void )
3820{
3821 TCB_t *pxTCB;
3822
3823 if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
3824 {
3825 /* The new current delayed list is empty. Set xNextTaskUnblockTime to
3826 the maximum possible value so it is extremely unlikely that the
3827 if( xTickCount >= xNextTaskUnblockTime ) test will pass until
3828 there is an item in the delayed list. */
3829 xNextTaskUnblockTime = portMAX_DELAY;
3830 }
3831 else
3832 {
3833 /* The new current delayed list is not empty, get the value of
3834 the item at the head of the delayed list. This is the time at
3835 which the task at the head of the delayed list should be removed
3836 from the Blocked state. */
3837 ( pxTCB ) = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
3838 xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( ( pxTCB )->xGenericListItem ) );
3839 }
3840}
3841/*-----------------------------------------------------------*/
3842
3843#if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) )
3844
3845TaskHandle_t xTaskGetCurrentTaskHandle( void )
3846{
3847 TaskHandle_t xReturn;
3848
3849 /* A critical section is not required as this is not called from
3850 an interrupt and the current TCB will always be the same for any
3851 individual execution thread. */
3852 xReturn = pxCurrentTCB;
3853
3854 return xReturn;
3855}
3856
3857#endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */
3858/*-----------------------------------------------------------*/
3859
3860#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
3861
3862BaseType_t xTaskGetSchedulerState( void )
3863{
3864 BaseType_t xReturn;
3865
3866 if( xSchedulerRunning == pdFALSE )
3867 {
3868 xReturn = taskSCHEDULER_NOT_STARTED;
3869 }
3870 else
3871 {
3872 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
3873 {
3874 xReturn = taskSCHEDULER_RUNNING;
3875 }
3876 else
3877 {
3878 xReturn = taskSCHEDULER_SUSPENDED;
3879 }
3880 }
3881
3882 return xReturn;
3883}
3884
3885#endif /* ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) */
3886/*-----------------------------------------------------------*/
3887
3888#if ( configUSE_MUTEXES == 1 )
3889
3890void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder )
3891{
3892 TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder;
3893
3894 /* If the mutex was given back by an interrupt while the queue was
3895 locked then the mutex holder might now be NULL. */
3896 if( pxMutexHolder != NULL )
3897 {
3898 /* If the holder of the mutex has a priority below the priority of
3899 the task attempting to obtain the mutex then it will temporarily
3900 inherit the priority of the task attempting to obtain the mutex. */
3901 if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )
3902 {
3903 /* Adjust the mutex holder state to account for its new
3904 priority. Only reset the event list item value if the value is
3905 not being used for anything else. */
3906 if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
3907 {
3908 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
3909 }
3910 else
3911 {
3912 mtCOVERAGE_TEST_MARKER();
3913 }
3914
3915 /* If the task being modified is in the ready state it will need
3916 to be moved into a new list. */
3917 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) != pdFALSE )
3918 {
3919 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
3920 {
3921 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
3922 }
3923 else
3924 {
3925 mtCOVERAGE_TEST_MARKER();
3926 }
3927
3928 /* Inherit the priority before being moved into the new list. */
3929 pxTCB->uxPriority = pxCurrentTCB->uxPriority;
3930 prvAddTaskToReadyList( pxTCB );
3931 }
3932 else
3933 {
3934 /* Just inherit the priority. */
3935 pxTCB->uxPriority = pxCurrentTCB->uxPriority;
3936 }
3937
3938 traceTASK_PRIORITY_INHERIT( pxTCB, pxCurrentTCB->uxPriority );
3939 }
3940 else
3941 {
3942 mtCOVERAGE_TEST_MARKER();
3943 }
3944 }
3945 else
3946 {
3947 mtCOVERAGE_TEST_MARKER();
3948 }
3949}
3950
3951#endif /* configUSE_MUTEXES */
3952/*-----------------------------------------------------------*/
3953
3954#if ( configUSE_MUTEXES == 1 )
3955
3956BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder )
3957{
3958 TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder;
3959 BaseType_t xReturn = pdFALSE;
3960
3961 if( pxMutexHolder != NULL )
3962 {
3963 /* A task can only have an inherited priority if it holds the mutex.
3964 If the mutex is held by a task then it cannot be given from an
3965 interrupt, and if a mutex is given by the holding task then it must
3966 be the running state task. */
3967 configASSERT( pxTCB == pxCurrentTCB );
3968
3969 configASSERT( pxTCB->uxMutexesHeld );
3970 ( pxTCB->uxMutexesHeld )--;
3971
3972 /* Has the holder of the mutex inherited the priority of another
3973 task? */
3974 if( pxTCB->uxPriority != pxTCB->uxBasePriority )
3975 {
3976 /* Only disinherit if no other mutexes are held. */
3977 if( pxTCB->uxMutexesHeld == ( UBaseType_t ) 0 )
3978 {
3979 /* A task can only have an inherited priority if it holds
3980 the mutex. If the mutex is held by a task then it cannot be
3981 given from an interrupt, and if a mutex is given by the
3982 holding task then it must be the running state task. Remove
3983 the holding task from the ready list. */
3984 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
3985 {
3986 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
3987 }
3988 else
3989 {
3990 mtCOVERAGE_TEST_MARKER();
3991 }
3992
3993 /* Disinherit the priority before adding the task into the
3994 new ready list. */
3995 traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority );
3996 pxTCB->uxPriority = pxTCB->uxBasePriority;
3997
3998 /* Reset the event list item value. It cannot be in use for
3999 any other purpose if this task is running, and it must be
4000 running to give back the mutex. */
4001 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxTCB->uxPriority );
4002 prvAddTaskToReadyList( pxTCB );
4003
4004 /* Return true to indicate that a context switch is required.
4005 This is only actually required in the corner case whereby
4006 multiple mutexes were held and the mutexes were given back
4007 in an order different to that in which they were taken.
4008 If a context switch did not occur when the first mutex was
4009 returned, even if a task was waiting on it, then a context
4010 switch should occur when the last mutex is returned whether
4011 a task is waiting on it or not. */
4012 xReturn = pdTRUE;
4013 }
4014 else
4015 {
4016 mtCOVERAGE_TEST_MARKER();
4017 }
4018 }
4019 else
4020 {
4021 mtCOVERAGE_TEST_MARKER();
4022 }
4023 }
4024 else
4025 {
4026 mtCOVERAGE_TEST_MARKER();
4027 }
4028
4029 return xReturn;
4030}
4031
4032#endif /* configUSE_MUTEXES */
4033/*-----------------------------------------------------------*/
4034
4035#if ( portCRITICAL_NESTING_IN_TCB == 1 )
4036
4037void vTaskEnterCritical( void )
4038{
4039 portDISABLE_INTERRUPTS();
4040
4041 if( xSchedulerRunning != pdFALSE )
4042 {
4043 ( pxCurrentTCB->uxCriticalNesting )++;
4044
4045 /* This is not the interrupt safe version of the enter critical
4046 function so assert() if it is being called from an interrupt
4047 context. Only API functions that end in "FromISR" can be used in an
4048 interrupt. Only assert if the critical nesting count is 1 to
4049 protect against recursive calls if the assert function also uses a
4050 critical section. */
4051 if( pxCurrentTCB->uxCriticalNesting == 1 )
4052 {
4053 portASSERT_IF_IN_ISR();
4054 }
4055 }
4056 else
4057 {
4058 mtCOVERAGE_TEST_MARKER();
4059 }
4060}
4061
4062#endif /* portCRITICAL_NESTING_IN_TCB */
4063/*-----------------------------------------------------------*/
4064
4065#if ( portCRITICAL_NESTING_IN_TCB == 1 )
4066
4067void vTaskExitCritical( void )
4068{
4069 if( xSchedulerRunning != pdFALSE )
4070 {
4071 if( pxCurrentTCB->uxCriticalNesting > 0U )
4072 {
4073 ( pxCurrentTCB->uxCriticalNesting )--;
4074
4075 if( pxCurrentTCB->uxCriticalNesting == 0U )
4076 {
4077 portENABLE_INTERRUPTS();
4078 }
4079 else
4080 {
4081 mtCOVERAGE_TEST_MARKER();
4082 }
4083 }
4084 else
4085 {
4086 mtCOVERAGE_TEST_MARKER();
4087 }
4088 }
4089 else
4090 {
4091 mtCOVERAGE_TEST_MARKER();
4092 }
4093}
4094
4095#endif /* portCRITICAL_NESTING_IN_TCB */
4096/*-----------------------------------------------------------*/
4097
4098#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) )
4099
4100static char *prvWriteNameToBuffer( char *pcBuffer, const char *pcTaskName )
4101{
4102 size_t x;
4103
4104 /* Start by copying the entire string. */
4105 strcpy( pcBuffer, pcTaskName );
4106
4107 /* Pad the end of the string with spaces to ensure columns line up when
4108 printed out. */
4109 for( x = strlen( pcBuffer ); x < ( size_t ) ( configMAX_TASK_NAME_LEN - 1 ); x++ )
4110 {
4111 pcBuffer[ x ] = ' ';
4112 }
4113
4114 /* Terminate. */
4115 pcBuffer[ x ] = 0x00;
4116
4117 /* Return the new end of string. */
4118 return &( pcBuffer[ x ] );
4119}
4120
4121#endif /* ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) */
4122/*-----------------------------------------------------------*/
4123
4124#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) )
4125
4126void vTaskList( char * pcWriteBuffer )
4127{
4128 TaskStatus_t *pxTaskStatusArray;
4129 volatile UBaseType_t uxArraySize, x;
4130 char cStatus;
4131
4132 /*
4133 * PLEASE NOTE:
4134 *
4135 * This function is provided for convenience only, and is used by many
4136 * of the demo applications. Do not consider it to be part of the
4137 * scheduler.
4138 *
4139 * vTaskList() calls uxTaskGetSystemState(), then formats part of the
4140 * uxTaskGetSystemState() output into a human readable table that
4141 * displays task names, states and stack usage.
4142 *
4143 * vTaskList() has a dependency on the sprintf() C library function that
4144 * might bloat the code size, use a lot of stack, and provide different
4145 * results on different platforms. An alternative, tiny, third party,
4146 * and limited functionality implementation of sprintf() is provided in
4147 * many of the FreeRTOS/Demo sub-directories in a file called
4148 * printf-stdarg.c (note printf-stdarg.c does not provide a full
4149 * snprintf() implementation!).
4150 *
4151 * It is recommended that production systems call uxTaskGetSystemState()
4152 * directly to get access to raw stats data, rather than indirectly
4153 * through a call to vTaskList().
4154 */
4155
4156
4157 /* Make sure the write buffer does not contain a string. */
4158 *pcWriteBuffer = 0x00;
4159
4160 /* Take a snapshot of the number of tasks in case it changes while this
4161 function is executing. */
4162 uxArraySize = uxCurrentNumberOfTasks;
4163
4164 /* Allocate an array index for each task. */
4165 pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) );
4166
4167 if( pxTaskStatusArray != NULL )
4168 {
4169 /* Generate the (binary) data. */
4170 uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, NULL );
4171
4172 /* Create a human readable table from the binary data. */
4173 for( x = 0; x < uxArraySize; x++ )
4174 {
4175 switch( pxTaskStatusArray[ x ].eCurrentState )
4176 {
4177 case eReady: cStatus = tskREADY_CHAR;
4178 break;
4179
4180 case eBlocked: cStatus = tskBLOCKED_CHAR;
4181 break;
4182
4183 case eSuspended: cStatus = tskSUSPENDED_CHAR;
4184 break;
4185
4186 case eDeleted: cStatus = tskDELETED_CHAR;
4187 break;
4188
4189 default: /* Should not get here, but it is included
4190 to prevent static checking errors. */
4191 cStatus = 0x00;
4192 break;
4193 }
4194
4195 /* Write the task name to the string, padding with spaces so it
4196 can be printed in tabular form more easily. */
4197 pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName );
4198
4199 /* Write the rest of the string. */
4200 sprintf( pcWriteBuffer, "\t%c\t%u\t%u\t%u\r\n", cStatus, ( unsigned int ) pxTaskStatusArray[ x ].uxCurrentPriority, ( unsigned int ) pxTaskStatusArray[ x ].usStackHighWaterMark, ( unsigned int ) pxTaskStatusArray[ x ].xTaskNumber );
4201 pcWriteBuffer += strlen( pcWriteBuffer );
4202 }
4203
4204 /* Free the array again. */
4205 vPortFree( pxTaskStatusArray );
4206 }
4207 else
4208 {
4209 mtCOVERAGE_TEST_MARKER();
4210 }
4211}
4212
4213#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */
4214/*----------------------------------------------------------*/
4215
4216#if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) )
4217
4218void vTaskGetRunTimeStats( char *pcWriteBuffer )
4219{
4220 TaskStatus_t *pxTaskStatusArray;
4221 volatile UBaseType_t uxArraySize, x;
4222 uint32_t ulTotalTime, ulStatsAsPercentage;
4223
4224 #if( configUSE_TRACE_FACILITY != 1 )
4225 {
4226 #error configUSE_TRACE_FACILITY must also be set to 1 in FreeRTOSConfig.h to use vTaskGetRunTimeStats().
4227 }
4228 #endif
4229
4230 /*
4231 * PLEASE NOTE:
4232 *
4233 * This function is provided for convenience only, and is used by many
4234 * of the demo applications. Do not consider it to be part of the
4235 * scheduler.
4236 *
4237 * vTaskGetRunTimeStats() calls uxTaskGetSystemState(), then formats part
4238 * of the uxTaskGetSystemState() output into a human readable table that
4239 * displays the amount of time each task has spent in the Running state
4240 * in both absolute and percentage terms.
4241 *
4242 * vTaskGetRunTimeStats() has a dependency on the sprintf() C library
4243 * function that might bloat the code size, use a lot of stack, and
4244 * provide different results on different platforms. An alternative,
4245 * tiny, third party, and limited functionality implementation of
4246 * sprintf() is provided in many of the FreeRTOS/Demo sub-directories in
4247 * a file called printf-stdarg.c (note printf-stdarg.c does not provide
4248 * a full snprintf() implementation!).
4249 *
4250 * It is recommended that production systems call uxTaskGetSystemState()
4251 * directly to get access to raw stats data, rather than indirectly
4252 * through a call to vTaskGetRunTimeStats().
4253 */
4254
4255 /* Make sure the write buffer does not contain a string. */
4256 *pcWriteBuffer = 0x00;
4257
4258 /* Take a snapshot of the number of tasks in case it changes while this
4259 function is executing. */
4260 uxArraySize = uxCurrentNumberOfTasks;
4261
4262 /* Allocate an array index for each task. */
4263 pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) );
4264
4265 if( pxTaskStatusArray != NULL )
4266 {
4267 /* Generate the (binary) data. */
4268 uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, &ulTotalTime );
4269
4270 /* For percentage calculations. */
4271 ulTotalTime /= 100UL;
4272
4273 /* Avoid divide by zero errors. */
4274 if( ulTotalTime > 0 )
4275 {
4276 /* Create a human readable table from the binary data. */
4277 for( x = 0; x < uxArraySize; x++ )
4278 {
4279 /* What percentage of the total run time has the task used?
4280 This will always be rounded down to the nearest integer.
4281 ulTotalRunTimeDiv100 has already been divided by 100. */
4282 ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter / ulTotalTime;
4283
4284 /* Write the task name to the string, padding with
4285 spaces so it can be printed in tabular form more
4286 easily. */
4287 pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName );
4288
4289 if( ulStatsAsPercentage > 0UL )
4290 {
4291 #ifdef portLU_PRINTF_SPECIFIER_REQUIRED
4292 {
4293 sprintf( pcWriteBuffer, "\t%lu\t\t%lu%%\r\n", pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage );
4294 }
4295 #else
4296 {
4297 /* sizeof( int ) == sizeof( long ) so a smaller
4298 printf() library can be used. */
4299 sprintf( pcWriteBuffer, "\t%u\t\t%u%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage );
4300 }
4301 #endif
4302 }
4303 else
4304 {
4305 /* If the percentage is zero here then the task has
4306 consumed less than 1% of the total run time. */
4307 #ifdef portLU_PRINTF_SPECIFIER_REQUIRED
4308 {
4309 sprintf( pcWriteBuffer, "\t%lu\t\t<1%%\r\n", pxTaskStatusArray[ x ].ulRunTimeCounter );
4310 }
4311 #else
4312 {
4313 /* sizeof( int ) == sizeof( long ) so a smaller
4314 printf() library can be used. */
4315 sprintf( pcWriteBuffer, "\t%u\t\t<1%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter );
4316 }
4317 #endif
4318 }
4319
4320 pcWriteBuffer += strlen( pcWriteBuffer );
4321 }
4322 }
4323 else
4324 {
4325 mtCOVERAGE_TEST_MARKER();
4326 }
4327
4328 /* Free the array again. */
4329 vPortFree( pxTaskStatusArray );
4330 }
4331 else
4332 {
4333 mtCOVERAGE_TEST_MARKER();
4334 }
4335}
4336
4337#endif /* ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */
4338/*-----------------------------------------------------------*/
4339
4340TickType_t uxTaskResetEventItemValue( void )
4341{
4342 TickType_t uxReturn;
4343
4344 uxReturn = listGET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ) );
4345
4346 /* Reset the event list item to its normal value - so it can be used with
4347 queues and semaphores. */
4348 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
4349
4350 return uxReturn;
4351}
4352/*-----------------------------------------------------------*/
4353
4354#if ( configUSE_MUTEXES == 1 )
4355
4356void *pvTaskIncrementMutexHeldCount( void )
4357{
4358 /* If xSemaphoreCreateMutex() is called before any tasks have been created
4359 then pxCurrentTCB will be NULL. */
4360 if( pxCurrentTCB != NULL )
4361 {
4362 ( pxCurrentTCB->uxMutexesHeld )++;
4363 }
4364
4365 return pxCurrentTCB;
4366}
4367
4368#endif /* configUSE_MUTEXES */
4369/*-----------------------------------------------------------*/
4370
4371#if( configUSE_TASK_NOTIFICATIONS == 1 )
4372
4373uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait )
4374{
4375 TickType_t xTimeToWake;
4376 uint32_t ulReturn;
4377
4378 taskENTER_CRITICAL();
4379 {
4380 /* Only block if the notification count is not already non-zero. */
4381 if( pxCurrentTCB->ulNotifiedValue == 0UL )
4382 {
4383 /* Mark this task as waiting for a notification. */
4384 pxCurrentTCB->eNotifyState = eWaitingNotification;
4385
4386 if( xTicksToWait > ( TickType_t ) 0 )
4387 {
4388 /* The task is going to block. First it must be removed
4389 from the ready list. */
4390 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
4391 {
4392 /* The current task must be in a ready list, so there is
4393 no need to check, and the port reset macro can be called
4394 directly. */
4395 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
4396 }
4397 else
4398 {
4399 mtCOVERAGE_TEST_MARKER();
4400 }
4401
4402 #if ( INCLUDE_vTaskSuspend == 1 )
4403 {
4404 if( xTicksToWait == portMAX_DELAY )
4405 {
4406 /* Add the task to the suspended task list instead
4407 of a delayed task list to ensure the task is not
4408 woken by a timing event. It will block
4409 indefinitely. */
4410 vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) );
4411 }
4412 else
4413 {
4414 /* Calculate the time at which the task should be
4415 woken if no notification events occur. This may
4416 overflow but this doesn't matter, the scheduler will
4417 handle it. */
4418 xTimeToWake = xTickCount + xTicksToWait;
4419 prvAddCurrentTaskToDelayedList( xTimeToWake );
4420 }
4421 }
4422 #else /* INCLUDE_vTaskSuspend */
4423 {
4424 /* Calculate the time at which the task should be
4425 woken if the event does not occur. This may
4426 overflow but this doesn't matter, the scheduler will
4427 handle it. */
4428 xTimeToWake = xTickCount + xTicksToWait;
4429 prvAddCurrentTaskToDelayedList( xTimeToWake );
4430 }
4431 #endif /* INCLUDE_vTaskSuspend */
4432
4433 traceTASK_NOTIFY_TAKE_BLOCK();
4434
4435 /* All ports are written to allow a yield in a critical
4436 section (some will yield immediately, others wait until the
4437 critical section exits) - but it is not something that
4438 application code should ever do. */
4439 portYIELD_WITHIN_API();
4440 }
4441 else
4442 {
4443 mtCOVERAGE_TEST_MARKER();
4444 }
4445 }
4446 else
4447 {
4448 mtCOVERAGE_TEST_MARKER();
4449 }
4450 }
4451 taskEXIT_CRITICAL();
4452
4453 taskENTER_CRITICAL();
4454 {
4455 traceTASK_NOTIFY_TAKE();
4456 ulReturn = pxCurrentTCB->ulNotifiedValue;
4457
4458 if( ulReturn != 0UL )
4459 {
4460 if( xClearCountOnExit != pdFALSE )
4461 {
4462 pxCurrentTCB->ulNotifiedValue = 0UL;
4463 }
4464 else
4465 {
4466 ( pxCurrentTCB->ulNotifiedValue )--;
4467 }
4468 }
4469 else
4470 {
4471 mtCOVERAGE_TEST_MARKER();
4472 }
4473
4474 pxCurrentTCB->eNotifyState = eNotWaitingNotification;
4475 }
4476 taskEXIT_CRITICAL();
4477
4478 return ulReturn;
4479}
4480
4481#endif /* configUSE_TASK_NOTIFICATIONS */
4482/*-----------------------------------------------------------*/
4483
4484#if( configUSE_TASK_NOTIFICATIONS == 1 )
4485
4486BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait )
4487{
4488 TickType_t xTimeToWake;
4489 BaseType_t xReturn;
4490
4491 taskENTER_CRITICAL();
4492 {
4493 /* Only block if a notification is not already pending. */
4494 if( pxCurrentTCB->eNotifyState != eNotified )
4495 {
4496 /* Clear bits in the task's notification value as bits may get
4497 set by the notifying task or interrupt. This can be used to
4498 clear the value to zero. */
4499 pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnEntry;
4500
4501 /* Mark this task as waiting for a notification. */
4502 pxCurrentTCB->eNotifyState = eWaitingNotification;
4503
4504 if( xTicksToWait > ( TickType_t ) 0 )
4505 {
4506 /* The task is going to block. First it must be removed
4507 from the ready list. */
4508 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
4509 {
4510 /* The current task must be in a ready list, so there is
4511 no need to check, and the port reset macro can be called
4512 directly. */
4513 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
4514 }
4515 else
4516 {
4517 mtCOVERAGE_TEST_MARKER();
4518 }
4519
4520 #if ( INCLUDE_vTaskSuspend == 1 )
4521 {
4522 if( xTicksToWait == portMAX_DELAY )
4523 {
4524 /* Add the task to the suspended task list instead
4525 of a delayed task list to ensure the task is not
4526 woken by a timing event. It will block
4527 indefinitely. */
4528 vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) );
4529 }
4530 else
4531 {
4532 /* Calculate the time at which the task should be
4533 woken if no notification events occur. This may
4534 overflow but this doesn't matter, the scheduler will
4535 handle it. */
4536 xTimeToWake = xTickCount + xTicksToWait;
4537 prvAddCurrentTaskToDelayedList( xTimeToWake );
4538 }
4539 }
4540 #else /* INCLUDE_vTaskSuspend */
4541 {
4542 /* Calculate the time at which the task should be
4543 woken if the event does not occur. This may
4544 overflow but this doesn't matter, the scheduler will
4545 handle it. */
4546 xTimeToWake = xTickCount + xTicksToWait;
4547 prvAddCurrentTaskToDelayedList( xTimeToWake );
4548 }
4549 #endif /* INCLUDE_vTaskSuspend */
4550
4551 traceTASK_NOTIFY_WAIT_BLOCK();
4552
4553 /* All ports are written to allow a yield in a critical
4554 section (some will yield immediately, others wait until the
4555 critical section exits) - but it is not something that
4556 application code should ever do. */
4557 portYIELD_WITHIN_API();
4558 }
4559 else
4560 {
4561 mtCOVERAGE_TEST_MARKER();
4562 }
4563 }
4564 else
4565 {
4566 mtCOVERAGE_TEST_MARKER();
4567 }
4568 }
4569 taskEXIT_CRITICAL();
4570
4571 taskENTER_CRITICAL();
4572 {
4573 traceTASK_NOTIFY_WAIT();
4574
4575 if( pulNotificationValue != NULL )
4576 {
4577 /* Output the current notification value, which may or may not
4578 have changed. */
4579 *pulNotificationValue = pxCurrentTCB->ulNotifiedValue;
4580 }
4581
4582 /* If eNotifyValue is set then either the task never entered the
4583 blocked state (because a notification was already pending) or the
4584 task unblocked because of a notification. Otherwise the task
4585 unblocked because of a timeout. */
4586 if( pxCurrentTCB->eNotifyState == eWaitingNotification )
4587 {
4588 /* A notification was not received. */
4589 xReturn = pdFALSE;
4590 }
4591 else
4592 {
4593 /* A notification was already pending or a notification was
4594 received while the task was waiting. */
4595 pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnExit;
4596 xReturn = pdTRUE;
4597 }
4598
4599 pxCurrentTCB->eNotifyState = eNotWaitingNotification;
4600 }
4601 taskEXIT_CRITICAL();
4602
4603 return xReturn;
4604}
4605
4606#endif /* configUSE_TASK_NOTIFICATIONS */
4607/*-----------------------------------------------------------*/
4608
4609#if( configUSE_TASK_NOTIFICATIONS == 1 )
4610
4611BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue )
4612{
4613 TCB_t * pxTCB;
4614 eNotifyValue eOriginalNotifyState;
4615 BaseType_t xReturn = pdPASS;
4616
4617 configASSERT( xTaskToNotify );
4618 pxTCB = ( TCB_t * ) xTaskToNotify;
4619
4620 taskENTER_CRITICAL();
4621 {
4622 if( pulPreviousNotificationValue != NULL )
4623 {
4624 *pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
4625 }
4626
4627 eOriginalNotifyState = pxTCB->eNotifyState;
4628
4629 pxTCB->eNotifyState = eNotified;
4630
4631 switch( eAction )
4632 {
4633 case eSetBits :
4634 pxTCB->ulNotifiedValue |= ulValue;
4635 break;
4636
4637 case eIncrement :
4638 ( pxTCB->ulNotifiedValue )++;
4639 break;
4640
4641 case eSetValueWithOverwrite :
4642 pxTCB->ulNotifiedValue = ulValue;
4643 break;
4644
4645 case eSetValueWithoutOverwrite :
4646 if( eOriginalNotifyState != eNotified )
4647 {
4648 pxTCB->ulNotifiedValue = ulValue;
4649 }
4650 else
4651 {
4652 /* The value could not be written to the task. */
4653 xReturn = pdFAIL;
4654 }
4655 break;
4656
4657 case eNoAction:
4658 /* The task is being notified without its notify value being
4659 updated. */
4660 break;
4661 }
4662
4663 traceTASK_NOTIFY();
4664
4665 /* If the task is in the blocked state specifically to wait for a
4666 notification then unblock it now. */
4667 if( eOriginalNotifyState == eWaitingNotification )
4668 {
4669 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
4670 prvAddTaskToReadyList( pxTCB );
4671
4672 /* The task should not have been on an event list. */
4673 configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );
4674
4675 #if( configUSE_TICKLESS_IDLE != 0 )
4676 {
4677 /* If a task is blocked waiting for a notification then
4678 xNextTaskUnblockTime might be set to the blocked task's time
4679 out time. If the task is unblocked for a reason other than
4680 a timeout xNextTaskUnblockTime is normally left unchanged,
4681 because it will automatically get reset to a new value when
4682 the tick count equals xNextTaskUnblockTime. However if
4683 tickless idling is used it might be more important to enter
4684 sleep mode at the earliest possible time - so reset
4685 xNextTaskUnblockTime here to ensure it is updated at the
4686 earliest possible time. */
4687 prvResetNextTaskUnblockTime();
4688 }
4689 #endif
4690
4691 if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
4692 {
4693 /* The notified task has a priority above the currently
4694 executing task so a yield is required. */
4695 taskYIELD_IF_USING_PREEMPTION();
4696 }
4697 else
4698 {
4699 mtCOVERAGE_TEST_MARKER();
4700 }
4701 }
4702 else
4703 {
4704 mtCOVERAGE_TEST_MARKER();
4705 }
4706 }
4707 taskEXIT_CRITICAL();
4708
4709 return xReturn;
4710}
4711
4712#endif /* configUSE_TASK_NOTIFICATIONS */
4713/*-----------------------------------------------------------*/
4714
4715#if( configUSE_TASK_NOTIFICATIONS == 1 )
4716
4717BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken )
4718{
4719 TCB_t * pxTCB;
4720 eNotifyValue eOriginalNotifyState;
4721 BaseType_t xReturn = pdPASS;
4722 UBaseType_t uxSavedInterruptStatus;
4723
4724 configASSERT( xTaskToNotify );
4725
4726 /* RTOS ports that support interrupt nesting have the concept of a
4727 maximum system call (or maximum API call) interrupt priority.
4728 Interrupts that are above the maximum system call priority are keep
4729 permanently enabled, even when the RTOS kernel is in a critical section,
4730 but cannot make any calls to FreeRTOS API functions. If configASSERT()
4731 is defined in FreeRTOSConfig.h then
4732 portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
4733 failure if a FreeRTOS API function is called from an interrupt that has
4734 been assigned a priority above the configured maximum system call
4735 priority. Only FreeRTOS functions that end in FromISR can be called
4736 from interrupts that have been assigned a priority at or (logically)
4737 below the maximum system call interrupt priority. FreeRTOS maintains a
4738 separate interrupt safe API to ensure interrupt entry is as fast and as
4739 simple as possible. More information (albeit Cortex-M specific) is
4740 provided on the following link:
4741 http://www.freertos.org/RTOS-Cortex-M3-M4.html */
4742 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
4743
4744 pxTCB = ( TCB_t * ) xTaskToNotify;
4745
4746 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
4747 {
4748 if( pulPreviousNotificationValue != NULL )
4749 {
4750 *pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
4751 }
4752
4753 eOriginalNotifyState = pxTCB->eNotifyState;
4754 pxTCB->eNotifyState = eNotified;
4755
4756 switch( eAction )
4757 {
4758 case eSetBits :
4759 pxTCB->ulNotifiedValue |= ulValue;
4760 break;
4761
4762 case eIncrement :
4763 ( pxTCB->ulNotifiedValue )++;
4764 break;
4765
4766 case eSetValueWithOverwrite :
4767 pxTCB->ulNotifiedValue = ulValue;
4768 break;
4769
4770 case eSetValueWithoutOverwrite :
4771 if( eOriginalNotifyState != eNotified )
4772 {
4773 pxTCB->ulNotifiedValue = ulValue;
4774 }
4775 else
4776 {
4777 /* The value could not be written to the task. */
4778 xReturn = pdFAIL;
4779 }
4780 break;
4781
4782 case eNoAction :
4783 /* The task is being notified without its notify value being
4784 updated. */
4785 break;
4786 }
4787
4788 traceTASK_NOTIFY_FROM_ISR();
4789
4790 /* If the task is in the blocked state specifically to wait for a
4791 notification then unblock it now. */
4792 if( eOriginalNotifyState == eWaitingNotification )
4793 {
4794 /* The task should not have been on an event list. */
4795 configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );
4796
4797 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
4798 {
4799 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
4800 prvAddTaskToReadyList( pxTCB );
4801 }
4802 else
4803 {
4804 /* The delayed and ready lists cannot be accessed, so hold
4805 this task pending until the scheduler is resumed. */
4806 vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
4807 }
4808
4809 if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
4810 {
4811 /* The notified task has a priority above the currently
4812 executing task so a yield is required. */
4813 if( pxHigherPriorityTaskWoken != NULL )
4814 {
4815 *pxHigherPriorityTaskWoken = pdTRUE;
4816 }
4817 }
4818 else
4819 {
4820 mtCOVERAGE_TEST_MARKER();
4821 }
4822 }
4823 }
4824 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
4825
4826 return xReturn;
4827}
4828
4829#endif /* configUSE_TASK_NOTIFICATIONS */
4830/*-----------------------------------------------------------*/
4831
4832#if( configUSE_TASK_NOTIFICATIONS == 1 )
4833
4834void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify, BaseType_t *pxHigherPriorityTaskWoken )
4835{
4836 TCB_t * pxTCB;
4837 eNotifyValue eOriginalNotifyState;
4838 UBaseType_t uxSavedInterruptStatus;
4839
4840 configASSERT( xTaskToNotify );
4841
4842 /* RTOS ports that support interrupt nesting have the concept of a
4843 maximum system call (or maximum API call) interrupt priority.
4844 Interrupts that are above the maximum system call priority are keep
4845 permanently enabled, even when the RTOS kernel is in a critical section,
4846 but cannot make any calls to FreeRTOS API functions. If configASSERT()
4847 is defined in FreeRTOSConfig.h then
4848 portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
4849 failure if a FreeRTOS API function is called from an interrupt that has
4850 been assigned a priority above the configured maximum system call
4851 priority. Only FreeRTOS functions that end in FromISR can be called
4852 from interrupts that have been assigned a priority at or (logically)
4853 below the maximum system call interrupt priority. FreeRTOS maintains a
4854 separate interrupt safe API to ensure interrupt entry is as fast and as
4855 simple as possible. More information (albeit Cortex-M specific) is
4856 provided on the following link:
4857 http://www.freertos.org/RTOS-Cortex-M3-M4.html */
4858 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
4859
4860 pxTCB = ( TCB_t * ) xTaskToNotify;
4861
4862 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
4863 {
4864 eOriginalNotifyState = pxTCB->eNotifyState;
4865 pxTCB->eNotifyState = eNotified;
4866
4867 /* 'Giving' is equivalent to incrementing a count in a counting
4868 semaphore. */
4869 ( pxTCB->ulNotifiedValue )++;
4870
4871 traceTASK_NOTIFY_GIVE_FROM_ISR();
4872
4873 /* If the task is in the blocked state specifically to wait for a
4874 notification then unblock it now. */
4875 if( eOriginalNotifyState == eWaitingNotification )
4876 {
4877 /* The task should not have been on an event list. */
4878 configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );
4879
4880 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
4881 {
4882 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
4883 prvAddTaskToReadyList( pxTCB );
4884 }
4885 else
4886 {
4887 /* The delayed and ready lists cannot be accessed, so hold
4888 this task pending until the scheduler is resumed. */
4889 vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
4890 }
4891
4892 if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
4893 {
4894 /* The notified task has a priority above the currently
4895 executing task so a yield is required. */
4896 if( pxHigherPriorityTaskWoken != NULL )
4897 {
4898 *pxHigherPriorityTaskWoken = pdTRUE;
4899 }
4900 }
4901 else
4902 {
4903 mtCOVERAGE_TEST_MARKER();
4904 }
4905 }
4906 }
4907 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
4908}
4909
4910#endif /* configUSE_TASK_NOTIFICATIONS */
4911
4912/*-----------------------------------------------------------*/
4913
4914#if( configUSE_TASK_NOTIFICATIONS == 1 )
4915
4916BaseType_t xTaskNotifyStateClear( TaskHandle_t xTask )
4917{
4918 TCB_t *pxTCB;
4919 BaseType_t xReturn;
4920
4921 pxTCB = ( TCB_t * ) xTask;
4922
4923 /* If null is passed in here then it is the calling task that is having
4924 its notification state cleared. */
4925 pxTCB = prvGetTCBFromHandle( pxTCB );
4926
4927 taskENTER_CRITICAL();
4928 {
4929 if( pxTCB->eNotifyState == eNotified )
4930 {
4931 pxTCB->eNotifyState = eNotWaitingNotification;
4932 xReturn = pdPASS;
4933 }
4934 else
4935 {
4936 xReturn = pdFAIL;
4937 }
4938 }
4939 taskEXIT_CRITICAL();
4940
4941 return xReturn;
4942}
4943
4944#endif /* configUSE_TASK_NOTIFICATIONS */
4945
4946#ifdef FREERTOS_MODULE_TEST
4947#include "tasks_test_access_functions.h"
4948#endif