blob: 22587a4e0f35ea08fe0c3cc5353ef209dc8633d7 [file] [log] [blame]
brians0ab60bb2013-01-31 02:21:51 +00001/*
2 FreeRTOS V6.0.5 - Copyright (C) 2010 Real Time Engineers Ltd.
3
4 ***************************************************************************
5 * *
6 * If you are: *
7 * *
8 * + New to FreeRTOS, *
9 * + Wanting to learn FreeRTOS or multitasking in general quickly *
10 * + Looking for basic training, *
11 * + Wanting to improve your FreeRTOS skills and productivity *
12 * *
13 * then take a look at the FreeRTOS eBook *
14 * *
15 * "Using the FreeRTOS Real Time Kernel - a Practical Guide" *
16 * http://www.FreeRTOS.org/Documentation *
17 * *
18 * A pdf reference manual is also available. Both are usually delivered *
19 * to your inbox within 20 minutes to two hours when purchased between 8am *
20 * and 8pm GMT (although please allow up to 24 hours in case of *
21 * exceptional circumstances). Thank you for your support! *
22 * *
23 ***************************************************************************
24
25 This file is part of the FreeRTOS distribution.
26
27 FreeRTOS is free software; you can redistribute it and/or modify it under
28 the terms of the GNU General Public License (version 2) as published by the
29 Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
30 ***NOTE*** The exception to the GPL is included to allow you to distribute
31 a combined work that includes FreeRTOS without being obliged to provide the
32 source code for proprietary components outside of the FreeRTOS kernel.
33 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
34 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
35 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
36 more details. You should have received a copy of the GNU General Public
37 License and the FreeRTOS license exception along with FreeRTOS; if not it
38 can be viewed here: http://www.freertos.org/a00114.html and also obtained
39 by writing to Richard Barry, contact details for whom are available on the
40 FreeRTOS WEB site.
41
42 1 tab == 4 spaces!
43
44 http://www.FreeRTOS.org - Documentation, latest information, license and
45 contact details.
46
47 http://www.SafeRTOS.com - A version that is certified for use in safety
48 critical systems.
49
50 http://www.OpenRTOS.com - Commercial support, development, porting,
51 licensing and training services.
52*/
53
54
55#include <stdio.h>
56#include <stdlib.h>
57#include <string.h>
58
59/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
60all the API functions to use the MPU wrappers. That should only be done when
61task.h is included from an application file. */
62#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
63
64#include "FreeRTOS.h"
65#include "task.h"
66#include "StackMacros.h"
67
68#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
69
70/*
71 * Macro to define the amount of stack available to the idle task.
72 */
73#define tskIDLE_STACK_SIZE configMINIMAL_STACK_SIZE
74
75/*
76 * Task control block. A task control block (TCB) is allocated to each task,
77 * and stores the context of the task.
78 */
79typedef struct tskTaskControlBlock {
80 volatile portSTACK_TYPE *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE STRUCT. */
81
82#if ( portUSING_MPU_WRAPPERS == 1 )
83 xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE STRUCT. */
84#endif
85
86 xListItem xGenericListItem; /*< List item used to place the TCB in ready and blocked queues. */
87 xListItem xEventListItem; /*< List item used to place the TCB in event lists. */
88 unsigned portBASE_TYPE uxPriority; /*< The priority of the task where 0 is the lowest priority. */
89 portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */
90 signed char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */
91
92#if ( portSTACK_GROWTH > 0 )
93 portSTACK_TYPE *pxEndOfStack; /*< Used for stack overflow checking on architectures where the stack grows up from low memory. */
94#endif
95
96#if ( portCRITICAL_NESTING_IN_TCB == 1 )
97 unsigned portBASE_TYPE uxCriticalNesting;
98#endif
99
100#if ( configUSE_TRACE_FACILITY == 1 )
101 unsigned portBASE_TYPE uxTCBNumber; /*< This is used for tracing the scheduler and making debugging easier only. */
102#endif
103
104#if ( configUSE_MUTEXES == 1 )
105 unsigned portBASE_TYPE uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
106#endif
107
108#if ( configUSE_APPLICATION_TASK_TAG == 1 )
109 pdTASK_HOOK_CODE pxTaskTag;
110#endif
111
112#if ( configGENERATE_RUN_TIME_STATS == 1 )
113 unsigned long ulRunTimeCounter; /*< Used for calculating how much CPU time each task is utilising. */
114#endif
115
116} tskTCB;
117
118
119/*
120 * Some kernel aware debuggers require data to be viewed to be global, rather
121 * than file scope.
122 */
123#ifdef portREMOVE_STATIC_QUALIFIER
124#define static
125#endif
126
127/*lint -e956 */
128PRIVILEGED_DATA tskTCB * volatile pxCurrentTCB = NULL;
129
130/* Lists for ready and blocked tasks. --------------------*/
131
132PRIVILEGED_DATA static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */
133PRIVILEGED_DATA static xList xDelayedTaskList1; /*< Delayed tasks. */
134PRIVILEGED_DATA static xList xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
135PRIVILEGED_DATA static xList * volatile pxDelayedTaskList ; /*< Points to the delayed task list currently being used. */
136PRIVILEGED_DATA static xList * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
137PRIVILEGED_DATA static xList xPendingReadyList; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready queue when the scheduler is resumed. */
138
139#if ( INCLUDE_vTaskDelete == 1 )
140
141PRIVILEGED_DATA static volatile xList xTasksWaitingTermination; /*< Tasks that have been deleted - but the their memory not yet freed. */
142PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTasksDeleted = (unsigned portBASE_TYPE) 0;
143
144#endif
145
146#if ( INCLUDE_vTaskSuspend == 1 )
147
148PRIVILEGED_DATA static xList xSuspendedTaskList; /*< Tasks that are currently suspended. */
149
150#endif
151
152/* File private variables. --------------------------------*/
153PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks = (unsigned portBASE_TYPE) 0;
154PRIVILEGED_DATA static volatile portTickType xTickCount = (portTickType) 0;
155PRIVILEGED_DATA static unsigned portBASE_TYPE uxTopUsedPriority = tskIDLE_PRIORITY;
156PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTopReadyPriority = tskIDLE_PRIORITY;
157PRIVILEGED_DATA static volatile signed portBASE_TYPE xSchedulerRunning = pdFALSE;
158PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxSchedulerSuspended = (unsigned portBASE_TYPE) pdFALSE;
159PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxMissedTicks = (unsigned portBASE_TYPE) 0;
160PRIVILEGED_DATA static volatile portBASE_TYPE xMissedYield = (portBASE_TYPE) pdFALSE;
161PRIVILEGED_DATA static volatile portBASE_TYPE xNumOfOverflows = (portBASE_TYPE) 0;
162PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber = (unsigned portBASE_TYPE) 0;
163
164#if ( configGENERATE_RUN_TIME_STATS == 1 )
165
166PRIVILEGED_DATA static char pcStatsString[ 50 ] ;
167PRIVILEGED_DATA static unsigned long ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */
168static void prvGenerateRunTimeStatsForTasksInList(const signed char *pcWriteBuffer, xList *pxList, unsigned long ulTotalRunTime) PRIVILEGED_FUNCTION;
169
170#endif
171
172/* Debugging and trace facilities private variables and macros. ------------*/
173
174/*
175 * The value used to fill the stack of a task when the task is created. This
176 * is used purely for checking the high water mark for tasks.
177 */
178#define tskSTACK_FILL_BYTE ( 0xa5 )
179
180/*
181 * Macros used by vListTask to indicate which state a task is in.
182 */
183#define tskBLOCKED_CHAR ( ( signed char ) 'B' )
184#define tskREADY_CHAR ( ( signed char ) 'R' )
185#define tskDELETED_CHAR ( ( signed char ) 'D' )
186#define tskSUSPENDED_CHAR ( ( signed char ) 'S' )
187
188/*
189 * Macros and private variables used by the trace facility.
190 */
191#if ( configUSE_TRACE_FACILITY == 1 )
192
193#define tskSIZE_OF_EACH_TRACE_LINE ( ( unsigned long ) ( sizeof( unsigned long ) + sizeof( unsigned long ) ) )
194PRIVILEGED_DATA static volatile signed char * volatile pcTraceBuffer;
195PRIVILEGED_DATA static signed char *pcTraceBufferStart;
196PRIVILEGED_DATA static signed char *pcTraceBufferEnd;
197PRIVILEGED_DATA static signed portBASE_TYPE xTracing = pdFALSE;
198static unsigned portBASE_TYPE uxPreviousTask = 255;
199PRIVILEGED_DATA static char pcStatusString[ 50 ];
200
201#endif
202
203/*-----------------------------------------------------------*/
204
205/*
206 * Macro that writes a trace of scheduler activity to a buffer. This trace
207 * shows which task is running when and is very useful as a debugging tool.
208 * As this macro is called each context switch it is a good idea to undefine
209 * it if not using the facility.
210 */
211#if ( configUSE_TRACE_FACILITY == 1 )
212
213#define vWriteTraceToBuffer() \
214 { \
215 if( xTracing ) \
216 { \
217 if( uxPreviousTask != pxCurrentTCB->uxTCBNumber ) \
218 { \
219 if( ( pcTraceBuffer + tskSIZE_OF_EACH_TRACE_LINE ) < pcTraceBufferEnd ) \
220 { \
221 uxPreviousTask = pxCurrentTCB->uxTCBNumber; \
222 *( unsigned long * ) pcTraceBuffer = ( unsigned long ) xTickCount; \
223 pcTraceBuffer += sizeof( unsigned long ); \
224 *( unsigned long * ) pcTraceBuffer = ( unsigned long ) uxPreviousTask; \
225 pcTraceBuffer += sizeof( unsigned long ); \
226 } \
227 else \
228 { \
229 xTracing = pdFALSE; \
230 } \
231 } \
232 } \
233 }
234
235#else
236
237#define vWriteTraceToBuffer()
238
239#endif
240/*-----------------------------------------------------------*/
241
242/*
243 * Place the task represented by pxTCB into the appropriate ready queue for
244 * the task. It is inserted at the end of the list. One quirk of this is
245 * that if the task being inserted is at the same priority as the currently
246 * executing task, then it will only be rescheduled after the currently
247 * executing task has been rescheduled.
248 */
249#define prvAddTaskToReadyQueue( pxTCB ) \
250{ \
251 if( pxTCB->uxPriority > uxTopReadyPriority ) \
252 { \
253 uxTopReadyPriority = pxTCB->uxPriority; \
254 } \
255 vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ); \
256}
257/*-----------------------------------------------------------*/
258
259/*
260 * Macro that looks at the list of tasks that are currently delayed to see if
261 * any require waking.
262 *
263 * Tasks are stored in the queue in the order of their wake time - meaning
264 * once one tasks has been found whose timer has not expired we need not look
265 * any further down the list.
266 */
267#define prvCheckDelayedTasks() \
268{ \
269register tskTCB *pxTCB; \
270 \
271 while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ) ) != NULL ) \
272 { \
273 if( xTickCount < listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ) ) \
274 { \
275 break; \
276 } \
277 vListRemove( &( pxTCB->xGenericListItem ) ); \
278 /* Is the task waiting on an event also? */ \
279 if( pxTCB->xEventListItem.pvContainer ) \
280 { \
281 vListRemove( &( pxTCB->xEventListItem ) ); \
282 } \
283 prvAddTaskToReadyQueue( pxTCB ); \
284 } \
285}
286/*-----------------------------------------------------------*/
287
288/*
289 * Several functions take an xTaskHandle parameter that can optionally be NULL,
290 * where NULL is used to indicate that the handle of the currently executing
291 * task should be used in place of the parameter. This macro simply checks to
292 * see if the parameter is NULL and returns a pointer to the appropriate TCB.
293 */
294#define prvGetTCBFromHandle( pxHandle ) ( ( pxHandle == NULL ) ? ( tskTCB * ) pxCurrentTCB : ( tskTCB * ) pxHandle )
295
296
297/* File private functions. --------------------------------*/
298
299/*
300 * Utility to ready a TCB for a given task. Mainly just copies the parameters
301 * into the TCB structure.
302 */
303static void prvInitialiseTCBVariables(tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth) PRIVILEGED_FUNCTION;
304
305/*
306 * Utility to ready all the lists used by the scheduler. This is called
307 * automatically upon the creation of the first task.
308 */
309static void prvInitialiseTaskLists(void) PRIVILEGED_FUNCTION;
310
311/*
312 * The idle task, which as all tasks is implemented as a never ending loop.
313 * The idle task is automatically created and added to the ready lists upon
314 * creation of the first user task.
315 *
316 * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific
317 * language extensions. The equivalent prototype for this function is:
318 *
319 * void prvIdleTask( void *pvParameters );
320 *
321 */
322static portTASK_FUNCTION_PROTO(prvIdleTask, pvParameters);
323
324/*
325 * Utility to free all memory allocated by the scheduler to hold a TCB,
326 * including the stack pointed to by the TCB.
327 *
328 * This does not free memory allocated by the task itself (i.e. memory
329 * allocated by calls to pvPortMalloc from within the tasks application code).
330 */
331#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
332
333static void prvDeleteTCB(tskTCB *pxTCB) PRIVILEGED_FUNCTION;
334
335#endif
336
337/*
338 * Used only by the idle task. This checks to see if anything has been placed
339 * in the list of tasks waiting to be deleted. If so the task is cleaned up
340 * and its TCB deleted.
341 */
342static void prvCheckTasksWaitingTermination(void) PRIVILEGED_FUNCTION;
343
344/*
345 * Allocates memory from the heap for a TCB and associated stack. Checks the
346 * allocation was successful.
347 */
348static tskTCB *prvAllocateTCBAndStack(unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer) PRIVILEGED_FUNCTION;
349
350/*
351 * Called from vTaskList. vListTasks details all the tasks currently under
352 * control of the scheduler. The tasks may be in one of a number of lists.
353 * prvListTaskWithinSingleList accepts a list and details the tasks from
354 * within just that list.
355 *
356 * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM
357 * NORMAL APPLICATION CODE.
358 */
359#if ( configUSE_TRACE_FACILITY == 1 )
360
361static void prvListTaskWithinSingleList(const signed char *pcWriteBuffer, xList *pxList, signed char cStatus) PRIVILEGED_FUNCTION;
362
363#endif
364
365/*
366 * When a task is created, the stack of the task is filled with a known value.
367 * This function determines the 'high water mark' of the task stack by
368 * determining how much of the stack remains at the original preset value.
369 */
370#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
371
372static unsigned short usTaskCheckFreeStackSpace(const unsigned char * pucStackByte) PRIVILEGED_FUNCTION;
373
374#endif
375
376
377/*lint +e956 */
378
379
380
381/*-----------------------------------------------------------
382 * TASK CREATION API documented in task.h
383 *----------------------------------------------------------*/
384
385signed portBASE_TYPE xTaskGenericCreate(pdTASK_CODE pxTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion * const xRegions)
386{
387 signed portBASE_TYPE xReturn;
388 tskTCB * pxNewTCB;
389
390 /* Allocate the memory required by the TCB and stack for the new task,
391 checking that the allocation was successful. */
392 pxNewTCB = prvAllocateTCBAndStack(usStackDepth, puxStackBuffer);
393
394 if (pxNewTCB != NULL) {
395 portSTACK_TYPE *pxTopOfStack;
396
397#if( portUSING_MPU_WRAPPERS == 1 )
398 /* Should the task be created in privileged mode? */
399 portBASE_TYPE xRunPrivileged;
400 if ((uxPriority & portPRIVILEGE_BIT) != 0x00) {
401 xRunPrivileged = pdTRUE;
402 } else {
403 xRunPrivileged = pdFALSE;
404 }
405 uxPriority &= ~portPRIVILEGE_BIT;
406#endif /* portUSING_MPU_WRAPPERS == 1 */
407
408 /* Calculate the top of stack address. This depends on whether the
409 stack grows from high memory to low (as per the 80x86) or visa versa.
410 portSTACK_GROWTH is used to make the result positive or negative as
411 required by the port. */
412#if( portSTACK_GROWTH < 0 )
413 {
414 pxTopOfStack = pxNewTCB->pxStack + (usStackDepth - 1);
415 pxTopOfStack = (portSTACK_TYPE *)(((unsigned long) pxTopOfStack) & ((unsigned long) ~portBYTE_ALIGNMENT_MASK));
416 }
417#else
418 {
419 pxTopOfStack = pxNewTCB->pxStack;
420
421 /* If we want to use stack checking on architectures that use
422 a positive stack growth direction then we also need to store the
423 other extreme of the stack space. */
424 pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + (usStackDepth - 1);
425 }
426#endif
427
428 /* Setup the newly allocated TCB with the initial state of the task. */
429 prvInitialiseTCBVariables(pxNewTCB, pcName, uxPriority, xRegions, usStackDepth);
430
431 /* Initialize the TCB stack to look as if the task was already running,
432 but had been interrupted by the scheduler. The return address is set
433 to the start of the task function. Once the stack has been initialised
434 the top of stack variable is updated. */
435#if( portUSING_MPU_WRAPPERS == 1 )
436 {
437 pxNewTCB->pxTopOfStack = pxPortInitialiseStack(pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged);
438 }
439#else
440 {
441 pxNewTCB->pxTopOfStack = pxPortInitialiseStack(pxTopOfStack, pxTaskCode, pvParameters);
442 }
443#endif
444
445 /* We are going to manipulate the task queues to add this task to a
446 ready list, so must make sure no interrupts occur. */
447 portENTER_CRITICAL();
448 {
449 uxCurrentNumberOfTasks++;
450 if (uxCurrentNumberOfTasks == (unsigned portBASE_TYPE) 1) {
451 /* As this is the first task it must also be the current task. */
452 pxCurrentTCB = pxNewTCB;
453
454 /* This is the first task to be created so do the preliminary
455 initialisation required. We will not recover if this call
456 fails, but we will report the failure. */
457 prvInitialiseTaskLists();
458 } else {
459 /* If the scheduler is not already running, make this task the
460 current task if it is the highest priority task to be created
461 so far. */
462 if (xSchedulerRunning == pdFALSE) {
463 if (pxCurrentTCB->uxPriority <= uxPriority) {
464 pxCurrentTCB = pxNewTCB;
465 }
466 }
467 }
468
469 /* Remember the top priority to make context switching faster. Use
470 the priority in pxNewTCB as this has been capped to a valid value. */
471 if (pxNewTCB->uxPriority > uxTopUsedPriority) {
472 uxTopUsedPriority = pxNewTCB->uxPriority;
473 }
474
475#if ( configUSE_TRACE_FACILITY == 1 )
476 {
477 /* Add a counter into the TCB for tracing only. */
478 pxNewTCB->uxTCBNumber = uxTaskNumber;
479 }
480#endif
481 uxTaskNumber++;
482
483 prvAddTaskToReadyQueue(pxNewTCB);
484
485 xReturn = pdPASS;
486 traceTASK_CREATE(pxNewTCB);
487 }
488 portEXIT_CRITICAL();
489 } else {
490 xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
491 traceTASK_CREATE_FAILED(pxNewTCB);
492 }
493
494 if (xReturn == pdPASS) {
495 if ((void *) pxCreatedTask != NULL) {
496 /* Pass the TCB out - in an anonymous way. The calling function/
497 task can use this as a handle to delete the task later if
498 required.*/
499 *pxCreatedTask = (xTaskHandle) pxNewTCB;
500 }
501
502 if (xSchedulerRunning != pdFALSE) {
503 /* If the created task is of a higher priority than the current task
504 then it should run now. */
505 if (pxCurrentTCB->uxPriority < uxPriority) {
506 portYIELD_WITHIN_API();
507 }
508 }
509 }
510
511 return xReturn;
512}
513/*-----------------------------------------------------------*/
514
515#if ( INCLUDE_vTaskDelete == 1 )
516
517void vTaskDelete(xTaskHandle pxTaskToDelete)
518{
519 tskTCB *pxTCB;
520
521 portENTER_CRITICAL();
522 {
523 /* Ensure a yield is performed if the current task is being
524 deleted. */
525 if (pxTaskToDelete == pxCurrentTCB) {
526 pxTaskToDelete = NULL;
527 }
528
529 /* If null is passed in here then we are deleting ourselves. */
530 pxTCB = prvGetTCBFromHandle(pxTaskToDelete);
531
532 /* Remove task from the ready list and place in the termination list.
533 This will stop the task from be scheduled. The idle task will check
534 the termination list and free up any memory allocated by the
535 scheduler for the TCB and stack. */
536 vListRemove(&(pxTCB->xGenericListItem));
537
538 /* Is the task waiting on an event also? */
539 if (pxTCB->xEventListItem.pvContainer) {
540 vListRemove(&(pxTCB->xEventListItem));
541 }
542
543 vListInsertEnd((xList *) &xTasksWaitingTermination, &(pxTCB->xGenericListItem));
544
545 /* Increment the ucTasksDeleted variable so the idle task knows
546 there is a task that has been deleted and that it should therefore
547 check the xTasksWaitingTermination list. */
548 ++uxTasksDeleted;
549
550 /* Increment the uxTaskNumberVariable also so kernel aware debuggers
551 can detect that the task lists need re-generating. */
552 uxTaskNumber++;
553
554 traceTASK_DELETE(pxTCB);
555 }
556 portEXIT_CRITICAL();
557
558 /* Force a reschedule if we have just deleted the current task. */
559 if (xSchedulerRunning != pdFALSE) {
560 if ((void *) pxTaskToDelete == NULL) {
561 portYIELD_WITHIN_API();
562 }
563 }
564}
565
566#endif
567
568
569
570
571
572
573/*-----------------------------------------------------------
574 * TASK CONTROL API documented in task.h
575 *----------------------------------------------------------*/
576
577#if ( INCLUDE_vTaskDelayUntil == 1 )
578
579void vTaskDelayUntil(portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement)
580{
581 portTickType xTimeToWake;
582 portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE;
583
584 vTaskSuspendAll();
585 {
586 /* Generate the tick time at which the task wants to wake. */
587 xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
588
589 if (xTickCount < *pxPreviousWakeTime) {
590 /* The tick count has overflowed since this function was
591 lasted called. In this case the only time we should ever
592 actually delay is if the wake time has also overflowed,
593 and the wake time is greater than the tick time. When this
594 is the case it is as if neither time had overflowed. */
595 if ((xTimeToWake < *pxPreviousWakeTime) && (xTimeToWake > xTickCount)) {
596 xShouldDelay = pdTRUE;
597 }
598 } else {
599 /* The tick time has not overflowed. In this case we will
600 delay if either the wake time has overflowed, and/or the
601 tick time is less than the wake time. */
602 if ((xTimeToWake < *pxPreviousWakeTime) || (xTimeToWake > xTickCount)) {
603 xShouldDelay = pdTRUE;
604 }
605 }
606
607 /* Update the wake time ready for the next call. */
608 *pxPreviousWakeTime = xTimeToWake;
609
610 if (xShouldDelay) {
611 traceTASK_DELAY_UNTIL();
612
613 /* We must remove ourselves from the ready list before adding
614 ourselves to the blocked list as the same list item is used for
615 both lists. */
616 vListRemove((xListItem *) &(pxCurrentTCB->xGenericListItem));
617
618 /* The list item will be inserted in wake time order. */
619 listSET_LIST_ITEM_VALUE(&(pxCurrentTCB->xGenericListItem), xTimeToWake);
620
621 if (xTimeToWake < xTickCount) {
622 /* Wake time has overflowed. Place this item in the
623 overflow list. */
624 vListInsert((xList *) pxOverflowDelayedTaskList, (xListItem *) &(pxCurrentTCB->xGenericListItem));
625 } else {
626 /* The wake time has not overflowed, so we can use the
627 current block list. */
628 vListInsert((xList *) pxDelayedTaskList, (xListItem *) &(pxCurrentTCB->xGenericListItem));
629 }
630 }
631 }
632 xAlreadyYielded = xTaskResumeAll();
633
634 /* Force a reschedule if xTaskResumeAll has not already done so, we may
635 have put ourselves to sleep. */
636 if (!xAlreadyYielded) {
637 portYIELD_WITHIN_API();
638 }
639}
640
641#endif
642/*-----------------------------------------------------------*/
643
644#if ( INCLUDE_vTaskDelay == 1 )
645
646void vTaskDelay(portTickType xTicksToDelay)
647{
648 portTickType xTimeToWake;
649 signed portBASE_TYPE xAlreadyYielded = pdFALSE;
650
651 /* A delay time of zero just forces a reschedule. */
652 if (xTicksToDelay > (portTickType) 0) {
653 vTaskSuspendAll();
654 {
655 traceTASK_DELAY();
656
657 /* A task that is removed from the event list while the
658 scheduler is suspended will not get placed in the ready
659 list or removed from the blocked list until the scheduler
660 is resumed.
661
662 This task cannot be in an event list as it is the currently
663 executing task. */
664
665 /* Calculate the time to wake - this may overflow but this is
666 not a problem. */
667 xTimeToWake = xTickCount + xTicksToDelay;
668
669 /* We must remove ourselves from the ready list before adding
670 ourselves to the blocked list as the same list item is used for
671 both lists. */
672 vListRemove((xListItem *) &(pxCurrentTCB->xGenericListItem));
673
674 /* The list item will be inserted in wake time order. */
675 listSET_LIST_ITEM_VALUE(&(pxCurrentTCB->xGenericListItem), xTimeToWake);
676
677 if (xTimeToWake < xTickCount) {
678 /* Wake time has overflowed. Place this item in the
679 overflow list. */
680 vListInsert((xList *) pxOverflowDelayedTaskList, (xListItem *) &(pxCurrentTCB->xGenericListItem));
681 } else {
682 /* The wake time has not overflowed, so we can use the
683 current block list. */
684 vListInsert((xList *) pxDelayedTaskList, (xListItem *) &(pxCurrentTCB->xGenericListItem));
685 }
686 }
687 xAlreadyYielded = xTaskResumeAll();
688 }
689
690 /* Force a reschedule if xTaskResumeAll has not already done so, we may
691 have put ourselves to sleep. */
692 if (!xAlreadyYielded) {
693 portYIELD_WITHIN_API();
694 }
695}
696
697#endif
698/*-----------------------------------------------------------*/
699
700#if ( INCLUDE_uxTaskPriorityGet == 1 )
701
702unsigned portBASE_TYPE uxTaskPriorityGet(xTaskHandle pxTask)
703{
704 tskTCB *pxTCB;
705 unsigned portBASE_TYPE uxReturn;
706
707 portENTER_CRITICAL();
708 {
709 /* If null is passed in here then we are changing the
710 priority of the calling function. */
711 pxTCB = prvGetTCBFromHandle(pxTask);
712 uxReturn = pxTCB->uxPriority;
713 }
714 portEXIT_CRITICAL();
715
716 return uxReturn;
717}
718
719#endif
720/*-----------------------------------------------------------*/
721
722#if ( INCLUDE_vTaskPrioritySet == 1 )
723
724void vTaskPrioritySet(xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority)
725{
726 tskTCB *pxTCB;
727 unsigned portBASE_TYPE uxCurrentPriority, xYieldRequired = pdFALSE;
728
729 /* Ensure the new priority is valid. */
730 if (uxNewPriority >= configMAX_PRIORITIES) {
731 uxNewPriority = configMAX_PRIORITIES - 1;
732 }
733
734 portENTER_CRITICAL();
735 {
736 if (pxTask == pxCurrentTCB) {
737 pxTask = NULL;
738 }
739
740 /* If null is passed in here then we are changing the
741 priority of the calling function. */
742 pxTCB = prvGetTCBFromHandle(pxTask);
743
744 traceTASK_PRIORITY_SET(pxTask, uxNewPriority);
745
746#if ( configUSE_MUTEXES == 1 )
747 {
748 uxCurrentPriority = pxTCB->uxBasePriority;
749 }
750#else
751 {
752 uxCurrentPriority = pxTCB->uxPriority;
753 }
754#endif
755
756 if (uxCurrentPriority != uxNewPriority) {
757 /* The priority change may have readied a task of higher
758 priority than the calling task. */
759 if (uxNewPriority > uxCurrentPriority) {
760 if (pxTask != NULL) {
761 /* The priority of another task is being raised. If we
762 were raising the priority of the currently running task
763 there would be no need to switch as it must have already
764 been the highest priority task. */
765 xYieldRequired = pdTRUE;
766 }
767 } else if (pxTask == NULL) {
768 /* Setting our own priority down means there may now be another
769 task of higher priority that is ready to execute. */
770 xYieldRequired = pdTRUE;
771 }
772
773
774
775#if ( configUSE_MUTEXES == 1 )
776 {
777 /* Only change the priority being used if the task is not
778 currently using an inherited priority. */
779 if (pxTCB->uxBasePriority == pxTCB->uxPriority) {
780 pxTCB->uxPriority = uxNewPriority;
781 }
782
783 /* The base priority gets set whatever. */
784 pxTCB->uxBasePriority = uxNewPriority;
785 }
786#else
787 {
788 pxTCB->uxPriority = uxNewPriority;
789 }
790#endif
791
792 listSET_LIST_ITEM_VALUE(&(pxTCB->xEventListItem), (configMAX_PRIORITIES - (portTickType) uxNewPriority));
793
794 /* If the task is in the blocked or suspended list we need do
795 nothing more than change it's priority variable. However, if
796 the task is in a ready list it needs to be removed and placed
797 in the queue appropriate to its new priority. */
798 if (listIS_CONTAINED_WITHIN(&(pxReadyTasksLists[ uxCurrentPriority ]), &(pxTCB->xGenericListItem))) {
799 /* The task is currently in its ready list - remove before adding
800 it to it's new ready list. As we are in a critical section we
801 can do this even if the scheduler is suspended. */
802 vListRemove(&(pxTCB->xGenericListItem));
803 prvAddTaskToReadyQueue(pxTCB);
804 }
805
806 if (xYieldRequired == pdTRUE) {
807 portYIELD_WITHIN_API();
808 }
809 }
810 }
811 portEXIT_CRITICAL();
812}
813
814#endif
815/*-----------------------------------------------------------*/
816
817#if ( INCLUDE_vTaskSuspend == 1 )
818
819void vTaskSuspend(xTaskHandle pxTaskToSuspend)
820{
821 tskTCB *pxTCB;
822
823 portENTER_CRITICAL();
824 {
825 /* Ensure a yield is performed if the current task is being
826 suspended. */
827 if (pxTaskToSuspend == pxCurrentTCB) {
828 pxTaskToSuspend = NULL;
829 }
830
831 /* If null is passed in here then we are suspending ourselves. */
832 pxTCB = prvGetTCBFromHandle(pxTaskToSuspend);
833
834 traceTASK_SUSPEND(pxTCB);
835
836 /* Remove task from the ready/delayed list and place in the suspended list. */
837 vListRemove(&(pxTCB->xGenericListItem));
838
839 /* Is the task waiting on an event also? */
840 if (pxTCB->xEventListItem.pvContainer) {
841 vListRemove(&(pxTCB->xEventListItem));
842 }
843
844 vListInsertEnd((xList *) &xSuspendedTaskList, &(pxTCB->xGenericListItem));
845 }
846 portEXIT_CRITICAL();
847
848 /* We may have just suspended the current task. */
849 if ((void *) pxTaskToSuspend == NULL) {
850 portYIELD_WITHIN_API();
851 }
852}
853
854#endif
855/*-----------------------------------------------------------*/
856
857#if ( INCLUDE_vTaskSuspend == 1 )
858
859signed portBASE_TYPE xTaskIsTaskSuspended(xTaskHandle xTask)
860{
861 portBASE_TYPE xReturn = pdFALSE;
862 const tskTCB * const pxTCB = (tskTCB *) xTask;
863
864 /* Is the task we are attempting to resume actually in the
865 suspended list? */
866 if (listIS_CONTAINED_WITHIN(&xSuspendedTaskList, &(pxTCB->xGenericListItem)) != pdFALSE) {
867 /* Has the task already been resumed from within an ISR? */
868 if (listIS_CONTAINED_WITHIN(&xPendingReadyList, &(pxTCB->xEventListItem)) != pdTRUE) {
869 /* Is it in the suspended list because it is in the
870 Suspended state? It is possible to be in the suspended
871 list because it is blocked on a task with no timeout
872 specified. */
873 if (listIS_CONTAINED_WITHIN(NULL, &(pxTCB->xEventListItem)) == pdTRUE) {
874 xReturn = pdTRUE;
875 }
876 }
877 }
878
879 return xReturn;
880}
881
882#endif
883/*-----------------------------------------------------------*/
884
885#if ( INCLUDE_vTaskSuspend == 1 )
886
887void vTaskResume(xTaskHandle pxTaskToResume)
888{
889 tskTCB *pxTCB;
890
891 /* Remove the task from whichever list it is currently in, and place
892 it in the ready list. */
893 pxTCB = (tskTCB *) pxTaskToResume;
894
895 /* The parameter cannot be NULL as it is impossible to resume the
896 currently executing task. */
897 if ((pxTCB != NULL) && (pxTCB != pxCurrentTCB)) {
898 portENTER_CRITICAL();
899 {
900 if (xTaskIsTaskSuspended(pxTCB) == pdTRUE) {
901 traceTASK_RESUME(pxTCB);
902
903 /* As we are in a critical section we can access the ready
904 lists even if the scheduler is suspended. */
905 vListRemove(&(pxTCB->xGenericListItem));
906 prvAddTaskToReadyQueue(pxTCB);
907
908 /* We may have just resumed a higher priority task. */
909 if (pxTCB->uxPriority >= pxCurrentTCB->uxPriority) {
910 /* This yield may not cause the task just resumed to run, but
911 will leave the lists in the correct state for the next yield. */
912 portYIELD_WITHIN_API();
913 }
914 }
915 }
916 portEXIT_CRITICAL();
917 }
918}
919
920#endif
921
922/*-----------------------------------------------------------*/
923
924#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
925
926portBASE_TYPE xTaskResumeFromISR(xTaskHandle pxTaskToResume)
927{
928 portBASE_TYPE xYieldRequired = pdFALSE;
929 tskTCB *pxTCB;
930
931 pxTCB = (tskTCB *) pxTaskToResume;
932
933 if (xTaskIsTaskSuspended(pxTCB) == pdTRUE) {
934 traceTASK_RESUME_FROM_ISR(pxTCB);
935
936 if (uxSchedulerSuspended == (unsigned portBASE_TYPE) pdFALSE) {
937 xYieldRequired = (pxTCB->uxPriority >= pxCurrentTCB->uxPriority);
938 vListRemove(&(pxTCB->xGenericListItem));
939 prvAddTaskToReadyQueue(pxTCB);
940 } else {
941 /* We cannot access the delayed or ready lists, so will hold this
942 task pending until the scheduler is resumed, at which point a
943 yield will be performed if necessary. */
944 vListInsertEnd((xList *) &(xPendingReadyList), &(pxTCB->xEventListItem));
945 }
946 }
947
948 return xYieldRequired;
949}
950
951#endif
952
953
954
955
956/*-----------------------------------------------------------
957 * PUBLIC SCHEDULER CONTROL documented in task.h
958 *----------------------------------------------------------*/
959
960
961void vTaskStartScheduler(void)
962{
963 portBASE_TYPE xReturn;
964
965 /* Add the idle task at the lowest priority. */
966 xReturn = xTaskCreate(prvIdleTask, (signed char *) "IDLE", tskIDLE_STACK_SIZE, (void *) NULL, (tskIDLE_PRIORITY | portPRIVILEGE_BIT), (xTaskHandle *) NULL);
967
968 if (xReturn == pdPASS) {
969 /* Interrupts are turned off here, to ensure a tick does not occur
970 before or during the call to xPortStartScheduler(). The stacks of
971 the created tasks contain a status word with interrupts switched on
972 so interrupts will automatically get re-enabled when the first task
973 starts to run.
974
975 STEPPING THROUGH HERE USING A DEBUGGER CAN CAUSE BIG PROBLEMS IF THE
976 DEBUGGER ALLOWS INTERRUPTS TO BE PROCESSED. */
977 portDISABLE_INTERRUPTS();
978
979 xSchedulerRunning = pdTRUE;
980 xTickCount = (portTickType) 0;
981
982 /* If configGENERATE_RUN_TIME_STATS is defined then the following
983 macro must be defined to configure the timer/counter used to generate
984 the run time counter time base. */
985 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();
986
987 /* Setting up the timer tick is hardware specific and thus in the
988 portable interface. */
989 if (xPortStartScheduler()) {
990 /* Should not reach here as if the scheduler is running the
991 function will not return. */
992 } else {
993 /* Should only reach here if a task calls xTaskEndScheduler(). */
994 }
995 }
996}
997/*-----------------------------------------------------------*/
998
999void vTaskEndScheduler(void)
1000{
1001 /* Stop the scheduler interrupts and call the portable scheduler end
1002 routine so the original ISRs can be restored if necessary. The port
1003 layer must ensure interrupts enable bit is left in the correct state. */
1004 portDISABLE_INTERRUPTS();
1005 xSchedulerRunning = pdFALSE;
1006 vPortEndScheduler();
1007}
1008/*----------------------------------------------------------*/
1009
1010void vTaskSuspendAll(void)
1011{
1012 /* A critical section is not required as the variable is of type
1013 portBASE_TYPE. */
1014 ++uxSchedulerSuspended;
1015}
1016/*----------------------------------------------------------*/
1017
1018signed portBASE_TYPE xTaskResumeAll(void)
1019{
1020 register tskTCB *pxTCB;
1021 signed portBASE_TYPE xAlreadyYielded = pdFALSE;
1022
1023 /* It is possible that an ISR caused a task to be removed from an event
1024 list while the scheduler was suspended. If this was the case then the
1025 removed task will have been added to the xPendingReadyList. Once the
1026 scheduler has been resumed it is safe to move all the pending ready
1027 tasks from this list into their appropriate ready list. */
1028 portENTER_CRITICAL();
1029 {
1030 --uxSchedulerSuspended;
1031
1032 if (uxSchedulerSuspended == (unsigned portBASE_TYPE) pdFALSE) {
1033 if (uxCurrentNumberOfTasks > (unsigned portBASE_TYPE) 0) {
1034 portBASE_TYPE xYieldRequired = pdFALSE;
1035
1036 /* Move any readied tasks from the pending list into the
1037 appropriate ready list. */
1038 while ((pxTCB = (tskTCB *) listGET_OWNER_OF_HEAD_ENTRY(((xList *) & xPendingReadyList))) != NULL) {
1039 vListRemove(&(pxTCB->xEventListItem));
1040 vListRemove(&(pxTCB->xGenericListItem));
1041 prvAddTaskToReadyQueue(pxTCB);
1042
1043 /* If we have moved a task that has a priority higher than
1044 the current task then we should yield. */
1045 if (pxTCB->uxPriority >= pxCurrentTCB->uxPriority) {
1046 xYieldRequired = pdTRUE;
1047 }
1048 }
1049
1050 /* If any ticks occurred while the scheduler was suspended then
1051 they should be processed now. This ensures the tick count does not
1052 slip, and that any delayed tasks are resumed at the correct time. */
1053 if (uxMissedTicks > (unsigned portBASE_TYPE) 0) {
1054 while (uxMissedTicks > (unsigned portBASE_TYPE) 0) {
1055 vTaskIncrementTick();
1056 --uxMissedTicks;
1057 }
1058
1059 /* As we have processed some ticks it is appropriate to yield
1060 to ensure the highest priority task that is ready to run is
1061 the task actually running. */
1062#if configUSE_PREEMPTION == 1
1063 {
1064 xYieldRequired = pdTRUE;
1065 }
1066#endif
1067 }
1068
1069 if ((xYieldRequired == pdTRUE) || (xMissedYield == pdTRUE)) {
1070 xAlreadyYielded = pdTRUE;
1071 xMissedYield = pdFALSE;
1072 portYIELD_WITHIN_API();
1073 }
1074 }
1075 }
1076 }
1077 portEXIT_CRITICAL();
1078
1079 return xAlreadyYielded;
1080}
1081
1082
1083
1084
1085
1086
1087/*-----------------------------------------------------------
1088 * PUBLIC TASK UTILITIES documented in task.h
1089 *----------------------------------------------------------*/
1090
1091
1092
1093portTickType xTaskGetTickCount(void)
1094{
1095 portTickType xTicks;
1096
1097 /* Critical section required if running on a 16 bit processor. */
1098 portENTER_CRITICAL();
1099 {
1100 xTicks = xTickCount;
1101 }
1102 portEXIT_CRITICAL();
1103
1104 return xTicks;
1105}
1106/*-----------------------------------------------------------*/
1107
1108unsigned portBASE_TYPE uxTaskGetNumberOfTasks(void)
1109{
1110 /* A critical section is not required because the variables are of type
1111 portBASE_TYPE. */
1112 return uxCurrentNumberOfTasks;
1113}
1114/*-----------------------------------------------------------*/
1115
1116#if ( configUSE_TRACE_FACILITY == 1 )
1117
1118void vTaskList(signed char *pcWriteBuffer)
1119{
1120 unsigned portBASE_TYPE uxQueue;
1121
1122 /* This is a VERY costly function that should be used for debug only.
1123 It leaves interrupts disabled for a LONG time. */
1124
1125 vTaskSuspendAll();
1126 {
1127 /* Run through all the lists that could potentially contain a TCB and
1128 report the task name, state and stack high water mark. */
1129
1130 pcWriteBuffer[ 0 ] = (signed char) 0x00;
1131 strcat((char *) pcWriteBuffer, (const char *) "\r\n");
1132
1133 uxQueue = uxTopUsedPriority + 1;
1134
1135 do {
1136 uxQueue--;
1137
1138 if (!listLIST_IS_EMPTY(&(pxReadyTasksLists[ uxQueue ]))) {
1139 prvListTaskWithinSingleList(pcWriteBuffer, (xList *) &(pxReadyTasksLists[ uxQueue ]), tskREADY_CHAR);
1140 }
1141 } while (uxQueue > (unsigned short) tskIDLE_PRIORITY);
1142
1143 if (!listLIST_IS_EMPTY(pxDelayedTaskList)) {
1144 prvListTaskWithinSingleList(pcWriteBuffer, (xList *) pxDelayedTaskList, tskBLOCKED_CHAR);
1145 }
1146
1147 if (!listLIST_IS_EMPTY(pxOverflowDelayedTaskList)) {
1148 prvListTaskWithinSingleList(pcWriteBuffer, (xList *) pxOverflowDelayedTaskList, tskBLOCKED_CHAR);
1149 }
1150
1151#if( INCLUDE_vTaskDelete == 1 )
1152 {
1153 if (!listLIST_IS_EMPTY(&xTasksWaitingTermination)) {
1154 prvListTaskWithinSingleList(pcWriteBuffer, (xList *) &xTasksWaitingTermination, tskDELETED_CHAR);
1155 }
1156 }
1157#endif
1158
1159#if ( INCLUDE_vTaskSuspend == 1 )
1160 {
1161 if (!listLIST_IS_EMPTY(&xSuspendedTaskList)) {
1162 prvListTaskWithinSingleList(pcWriteBuffer, (xList *) &xSuspendedTaskList, tskSUSPENDED_CHAR);
1163 }
1164 }
1165#endif
1166 }
1167 xTaskResumeAll();
1168}
1169
1170#endif
1171/*----------------------------------------------------------*/
1172
1173#if ( configGENERATE_RUN_TIME_STATS == 1 )
1174
1175void vTaskGetRunTimeStats(signed char *pcWriteBuffer)
1176{
1177 unsigned portBASE_TYPE uxQueue;
1178 unsigned long ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
1179
1180 /* This is a VERY costly function that should be used for debug only.
1181 It leaves interrupts disabled for a LONG time. */
1182
1183 vTaskSuspendAll();
1184 {
1185 /* Run through all the lists that could potentially contain a TCB,
1186 generating a table of run timer percentages in the provided
1187 buffer. */
1188
1189 pcWriteBuffer[ 0 ] = (signed char) 0x00;
1190 strcat((char *) pcWriteBuffer, (const char *) "\r\n");
1191
1192 uxQueue = uxTopUsedPriority + 1;
1193
1194 do {
1195 uxQueue--;
1196
1197 if (!listLIST_IS_EMPTY(&(pxReadyTasksLists[ uxQueue ]))) {
1198 prvGenerateRunTimeStatsForTasksInList(pcWriteBuffer, (xList *) &(pxReadyTasksLists[ uxQueue ]), ulTotalRunTime);
1199 }
1200 } while (uxQueue > (unsigned short) tskIDLE_PRIORITY);
1201
1202 if (!listLIST_IS_EMPTY(pxDelayedTaskList)) {
1203 prvGenerateRunTimeStatsForTasksInList(pcWriteBuffer, (xList *) pxDelayedTaskList, ulTotalRunTime);
1204 }
1205
1206 if (!listLIST_IS_EMPTY(pxOverflowDelayedTaskList)) {
1207 prvGenerateRunTimeStatsForTasksInList(pcWriteBuffer, (xList *) pxOverflowDelayedTaskList, ulTotalRunTime);
1208 }
1209
1210#if ( INCLUDE_vTaskDelete == 1 )
1211 {
1212 if (!listLIST_IS_EMPTY(&xTasksWaitingTermination)) {
1213 prvGenerateRunTimeStatsForTasksInList(pcWriteBuffer, (xList *) &xTasksWaitingTermination, ulTotalRunTime);
1214 }
1215 }
1216#endif
1217
1218#if ( INCLUDE_vTaskSuspend == 1 )
1219 {
1220 if (!listLIST_IS_EMPTY(&xSuspendedTaskList)) {
1221 prvGenerateRunTimeStatsForTasksInList(pcWriteBuffer, (xList *) &xSuspendedTaskList, ulTotalRunTime);
1222 }
1223 }
1224#endif
1225 }
1226 xTaskResumeAll();
1227}
1228
1229#endif
1230/*----------------------------------------------------------*/
1231
1232#if ( configUSE_TRACE_FACILITY == 1 )
1233
1234void vTaskStartTrace(signed char * pcBuffer, unsigned long ulBufferSize)
1235{
1236 portENTER_CRITICAL();
1237 {
1238 pcTraceBuffer = (signed char *)pcBuffer;
1239 pcTraceBufferStart = pcBuffer;
1240 pcTraceBufferEnd = pcBuffer + (ulBufferSize - tskSIZE_OF_EACH_TRACE_LINE);
1241 xTracing = pdTRUE;
1242 }
1243 portEXIT_CRITICAL();
1244}
1245
1246#endif
1247/*----------------------------------------------------------*/
1248
1249#if ( configUSE_TRACE_FACILITY == 1 )
1250
1251unsigned long ulTaskEndTrace(void)
1252{
1253 unsigned long ulBufferLength;
1254
1255 portENTER_CRITICAL();
1256 xTracing = pdFALSE;
1257 portEXIT_CRITICAL();
1258
1259 ulBufferLength = (unsigned long)(pcTraceBuffer - pcTraceBufferStart);
1260
1261 return ulBufferLength;
1262}
1263
1264#endif
1265
1266
1267
1268/*-----------------------------------------------------------
1269 * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES
1270 * documented in task.h
1271 *----------------------------------------------------------*/
1272
1273
1274void vTaskIncrementTick(void)
1275{
1276 /* Called by the portable layer each time a tick interrupt occurs.
1277 Increments the tick then checks to see if the new tick value will cause any
1278 tasks to be unblocked. */
1279 if (uxSchedulerSuspended == (unsigned portBASE_TYPE) pdFALSE) {
1280 ++xTickCount;
1281 if (xTickCount == (portTickType) 0) {
1282 xList *pxTemp;
1283
1284 /* Tick count has overflowed so we need to swap the delay lists.
1285 If there are any items in pxDelayedTaskList here then there is
1286 an error! */
1287 pxTemp = pxDelayedTaskList;
1288 pxDelayedTaskList = pxOverflowDelayedTaskList;
1289 pxOverflowDelayedTaskList = pxTemp;
1290 xNumOfOverflows++;
1291 }
1292
1293 /* See if this tick has made a timeout expire. */
1294 prvCheckDelayedTasks();
1295 } else {
1296 ++uxMissedTicks;
1297
1298 /* The tick hook gets called at regular intervals, even if the
1299 scheduler is locked. */
1300#if ( configUSE_TICK_HOOK == 1 )
1301 {
1302 extern void vApplicationTickHook(void);
1303
1304 vApplicationTickHook();
1305 }
1306#endif
1307 }
1308
1309#if ( configUSE_TICK_HOOK == 1 )
1310 {
1311 extern void vApplicationTickHook(void);
1312
1313 /* Guard against the tick hook being called when the missed tick
1314 count is being unwound (when the scheduler is being unlocked. */
1315 if (uxMissedTicks == 0) {
1316 vApplicationTickHook();
1317 }
1318 }
1319#endif
1320
1321 traceTASK_INCREMENT_TICK(xTickCount);
1322}
1323/*-----------------------------------------------------------*/
1324
1325#if ( ( INCLUDE_vTaskCleanUpResources == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
1326
1327void vTaskCleanUpResources(void)
1328{
1329 unsigned short usQueue;
1330 volatile tskTCB *pxTCB;
1331
1332 usQueue = (unsigned short) uxTopUsedPriority + (unsigned short) 1;
1333
1334 /* Remove any TCB's from the ready queues. */
1335 do {
1336 usQueue--;
1337
1338 while (!listLIST_IS_EMPTY(&(pxReadyTasksLists[ usQueue ]))) {
1339 listGET_OWNER_OF_NEXT_ENTRY(pxTCB, &(pxReadyTasksLists[ usQueue ]));
1340 vListRemove((xListItem *) &(pxTCB->xGenericListItem));
1341
1342 prvDeleteTCB((tskTCB *) pxTCB);
1343 }
1344 } while (usQueue > (unsigned short) tskIDLE_PRIORITY);
1345
1346 /* Remove any TCB's from the delayed queue. */
1347 while (!listLIST_IS_EMPTY(&xDelayedTaskList1)) {
1348 listGET_OWNER_OF_NEXT_ENTRY(pxTCB, &xDelayedTaskList1);
1349 vListRemove((xListItem *) &(pxTCB->xGenericListItem));
1350
1351 prvDeleteTCB((tskTCB *) pxTCB);
1352 }
1353
1354 /* Remove any TCB's from the overflow delayed queue. */
1355 while (!listLIST_IS_EMPTY(&xDelayedTaskList2)) {
1356 listGET_OWNER_OF_NEXT_ENTRY(pxTCB, &xDelayedTaskList2);
1357 vListRemove((xListItem *) &(pxTCB->xGenericListItem));
1358
1359 prvDeleteTCB((tskTCB *) pxTCB);
1360 }
1361
1362 while (!listLIST_IS_EMPTY(&xSuspendedTaskList)) {
1363 listGET_OWNER_OF_NEXT_ENTRY(pxTCB, &xSuspendedTaskList);
1364 vListRemove((xListItem *) &(pxTCB->xGenericListItem));
1365
1366 prvDeleteTCB((tskTCB *) pxTCB);
1367 }
1368}
1369
1370#endif
1371/*-----------------------------------------------------------*/
1372
1373#if ( configUSE_APPLICATION_TASK_TAG == 1 )
1374
1375void vTaskSetApplicationTaskTag(xTaskHandle xTask, pdTASK_HOOK_CODE pxTagValue)
1376{
1377 tskTCB *xTCB;
1378
1379 /* If xTask is NULL then we are setting our own task hook. */
1380 if (xTask == NULL) {
1381 xTCB = (tskTCB *) pxCurrentTCB;
1382 } else {
1383 xTCB = (tskTCB *) xTask;
1384 }
1385
1386 /* Save the hook function in the TCB. A critical section is required as
1387 the value can be accessed from an interrupt. */
1388 portENTER_CRITICAL();
1389 xTCB->pxTaskTag = pxTagValue;
1390 portEXIT_CRITICAL();
1391}
1392
1393#endif
1394/*-----------------------------------------------------------*/
1395
1396#if ( configUSE_APPLICATION_TASK_TAG == 1 )
1397
1398pdTASK_HOOK_CODE xTaskGetApplicationTaskTag(xTaskHandle xTask)
1399{
1400 tskTCB *xTCB;
1401 pdTASK_HOOK_CODE xReturn;
1402
1403 /* If xTask is NULL then we are setting our own task hook. */
1404 if (xTask == NULL) {
1405 xTCB = (tskTCB *) pxCurrentTCB;
1406 } else {
1407 xTCB = (tskTCB *) xTask;
1408 }
1409
1410 /* Save the hook function in the TCB. A critical section is required as
1411 the value can be accessed from an interrupt. */
1412 portENTER_CRITICAL();
1413 xReturn = xTCB->pxTaskTag;
1414 portEXIT_CRITICAL();
1415
1416 return xReturn;
1417}
1418
1419#endif
1420/*-----------------------------------------------------------*/
1421
1422#if ( configUSE_APPLICATION_TASK_TAG == 1 )
1423
1424portBASE_TYPE xTaskCallApplicationTaskHook(xTaskHandle xTask, void *pvParameter)
1425{
1426 tskTCB *xTCB;
1427 portBASE_TYPE xReturn;
1428
1429 /* If xTask is NULL then we are calling our own task hook. */
1430 if (xTask == NULL) {
1431 xTCB = (tskTCB *) pxCurrentTCB;
1432 } else {
1433 xTCB = (tskTCB *) xTask;
1434 }
1435
1436 if (xTCB->pxTaskTag != NULL) {
1437 xReturn = xTCB->pxTaskTag(pvParameter);
1438 } else {
1439 xReturn = pdFAIL;
1440 }
1441
1442 return xReturn;
1443}
1444
1445#endif
1446/*-----------------------------------------------------------*/
1447
1448void vTaskSwitchContext(void)
1449{
1450 if (uxSchedulerSuspended != (unsigned portBASE_TYPE) pdFALSE) {
1451 /* The scheduler is currently suspended - do not allow a context
1452 switch. */
1453 xMissedYield = pdTRUE;
1454 return;
1455 }
1456
1457 traceTASK_SWITCHED_OUT();
1458
1459#if ( configGENERATE_RUN_TIME_STATS == 1 )
1460 {
1461 unsigned long ulTempCounter = portGET_RUN_TIME_COUNTER_VALUE();
1462
1463 /* Add the amount of time the task has been running to the accumulated
1464 time so far. The time the task started running was stored in
1465 ulTaskSwitchedInTime. Note that there is no overflow protection here
1466 so count values are only valid until the timer overflows. Generally
1467 this will be about 1 hour assuming a 1uS timer increment. */
1468 pxCurrentTCB->ulRunTimeCounter += (ulTempCounter - ulTaskSwitchedInTime);
1469 ulTaskSwitchedInTime = ulTempCounter;
1470 }
1471#endif
1472
1473 taskFIRST_CHECK_FOR_STACK_OVERFLOW();
1474 taskSECOND_CHECK_FOR_STACK_OVERFLOW();
1475
1476 /* Find the highest priority queue that contains ready tasks. */
1477 while (listLIST_IS_EMPTY(&(pxReadyTasksLists[ uxTopReadyPriority ]))) {
1478 --uxTopReadyPriority;
1479 }
1480
1481 /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the tasks of the
1482 same priority get an equal share of the processor time. */
1483 listGET_OWNER_OF_NEXT_ENTRY(pxCurrentTCB, &(pxReadyTasksLists[ uxTopReadyPriority ]));
1484
1485 traceTASK_SWITCHED_IN();
1486 vWriteTraceToBuffer();
1487}
1488/*-----------------------------------------------------------*/
1489
1490void vTaskPlaceOnEventList(const xList * const pxEventList, portTickType xTicksToWait)
1491{
1492 portTickType xTimeToWake;
1493
1494 /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
1495 SCHEDULER SUSPENDED. */
1496
1497 /* Place the event list item of the TCB in the appropriate event list.
1498 This is placed in the list in priority order so the highest priority task
1499 is the first to be woken by the event. */
1500 vListInsert((xList *) pxEventList, (xListItem *) &(pxCurrentTCB->xEventListItem));
1501
1502 /* We must remove ourselves from the ready list before adding ourselves
1503 to the blocked list as the same list item is used for both lists. We have
1504 exclusive access to the ready lists as the scheduler is locked. */
1505 vListRemove((xListItem *) &(pxCurrentTCB->xGenericListItem));
1506
1507
1508#if ( INCLUDE_vTaskSuspend == 1 )
1509 {
1510 if (xTicksToWait == portMAX_DELAY) {
1511 /* Add ourselves to the suspended task list instead of a delayed task
1512 list to ensure we are not woken by a timing event. We will block
1513 indefinitely. */
1514 vListInsertEnd((xList *) &xSuspendedTaskList, (xListItem *) &(pxCurrentTCB->xGenericListItem));
1515 } else {
1516 /* Calculate the time at which the task should be woken if the event does
1517 not occur. This may overflow but this doesn't matter. */
1518 xTimeToWake = xTickCount + xTicksToWait;
1519
1520 listSET_LIST_ITEM_VALUE(&(pxCurrentTCB->xGenericListItem), xTimeToWake);
1521
1522 if (xTimeToWake < xTickCount) {
1523 /* Wake time has overflowed. Place this item in the overflow list. */
1524 vListInsert((xList *) pxOverflowDelayedTaskList, (xListItem *) &(pxCurrentTCB->xGenericListItem));
1525 } else {
1526 /* The wake time has not overflowed, so we can use the current block list. */
1527 vListInsert((xList *) pxDelayedTaskList, (xListItem *) &(pxCurrentTCB->xGenericListItem));
1528 }
1529 }
1530 }
1531#else
1532 {
1533 /* Calculate the time at which the task should be woken if the event does
1534 not occur. This may overflow but this doesn't matter. */
1535 xTimeToWake = xTickCount + xTicksToWait;
1536
1537 listSET_LIST_ITEM_VALUE(&(pxCurrentTCB->xGenericListItem), xTimeToWake);
1538
1539 if (xTimeToWake < xTickCount) {
1540 /* Wake time has overflowed. Place this item in the overflow list. */
1541 vListInsert((xList *) pxOverflowDelayedTaskList, (xListItem *) &(pxCurrentTCB->xGenericListItem));
1542 } else {
1543 /* The wake time has not overflowed, so we can use the current block list. */
1544 vListInsert((xList *) pxDelayedTaskList, (xListItem *) &(pxCurrentTCB->xGenericListItem));
1545 }
1546 }
1547#endif
1548}
1549/*-----------------------------------------------------------*/
1550
1551signed portBASE_TYPE xTaskRemoveFromEventList(const xList * const pxEventList)
1552{
1553 tskTCB *pxUnblockedTCB;
1554 portBASE_TYPE xReturn;
1555
1556 /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
1557 SCHEDULER SUSPENDED. It can also be called from within an ISR. */
1558
1559 /* The event list is sorted in priority order, so we can remove the
1560 first in the list, remove the TCB from the delayed list, and add
1561 it to the ready list.
1562
1563 If an event is for a queue that is locked then this function will never
1564 get called - the lock count on the queue will get modified instead. This
1565 means we can always expect exclusive access to the event list here. */
1566 pxUnblockedTCB = (tskTCB *) listGET_OWNER_OF_HEAD_ENTRY(pxEventList);
1567 vListRemove(&(pxUnblockedTCB->xEventListItem));
1568
1569 if (uxSchedulerSuspended == (unsigned portBASE_TYPE) pdFALSE) {
1570 vListRemove(&(pxUnblockedTCB->xGenericListItem));
1571 prvAddTaskToReadyQueue(pxUnblockedTCB);
1572 } else {
1573 /* We cannot access the delayed or ready lists, so will hold this
1574 task pending until the scheduler is resumed. */
1575 vListInsertEnd((xList *) &(xPendingReadyList), &(pxUnblockedTCB->xEventListItem));
1576 }
1577
1578 if (pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority) {
1579 /* Return true if the task removed from the event list has
1580 a higher priority than the calling task. This allows
1581 the calling task to know if it should force a context
1582 switch now. */
1583 xReturn = pdTRUE;
1584 } else {
1585 xReturn = pdFALSE;
1586 }
1587
1588 return xReturn;
1589}
1590/*-----------------------------------------------------------*/
1591
1592void vTaskSetTimeOutState(xTimeOutType * const pxTimeOut)
1593{
1594 pxTimeOut->xOverflowCount = xNumOfOverflows;
1595 pxTimeOut->xTimeOnEntering = xTickCount;
1596}
1597/*-----------------------------------------------------------*/
1598
1599portBASE_TYPE xTaskCheckForTimeOut(xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait)
1600{
1601 portBASE_TYPE xReturn;
1602
1603 portENTER_CRITICAL();
1604 {
1605#if ( INCLUDE_vTaskSuspend == 1 )
1606 /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is
1607 the maximum block time then the task should block indefinitely, and
1608 therefore never time out. */
1609 if (*pxTicksToWait == portMAX_DELAY) {
1610 xReturn = pdFALSE;
1611 } else /* We are not blocking indefinitely, perform the checks below. */
1612#endif
1613
1614 if ((xNumOfOverflows != pxTimeOut->xOverflowCount) && ((portTickType) xTickCount >= (portTickType) pxTimeOut->xTimeOnEntering)) {
1615 /* The tick count is greater than the time at which vTaskSetTimeout()
1616 was called, but has also overflowed since vTaskSetTimeOut() was called.
1617 It must have wrapped all the way around and gone past us again. This
1618 passed since vTaskSetTimeout() was called. */
1619 xReturn = pdTRUE;
1620 } else if (((portTickType)((portTickType) xTickCount - (portTickType) pxTimeOut->xTimeOnEntering)) < (portTickType) *pxTicksToWait) {
1621 /* Not a genuine timeout. Adjust parameters for time remaining. */
1622 *pxTicksToWait -= ((portTickType) xTickCount - (portTickType) pxTimeOut->xTimeOnEntering);
1623 vTaskSetTimeOutState(pxTimeOut);
1624 xReturn = pdFALSE;
1625 } else {
1626 xReturn = pdTRUE;
1627 }
1628 }
1629 portEXIT_CRITICAL();
1630
1631 return xReturn;
1632}
1633/*-----------------------------------------------------------*/
1634
1635void vTaskMissedYield(void)
1636{
1637 xMissedYield = pdTRUE;
1638}
1639
1640/*
1641 * -----------------------------------------------------------
1642 * The Idle task.
1643 * ----------------------------------------------------------
1644 *
1645 * The portTASK_FUNCTION() macro is used to allow port/compiler specific
1646 * language extensions. The equivalent prototype for this function is:
1647 *
1648 * void prvIdleTask( void *pvParameters );
1649 *
1650 */
1651static portTASK_FUNCTION(prvIdleTask, pvParameters)
1652{
1653 /* Stop warnings. */
1654 (void) pvParameters;
1655
1656 for (;;) {
1657 /* See if any tasks have been deleted. */
1658 prvCheckTasksWaitingTermination();
1659
1660#if ( configUSE_PREEMPTION == 0 )
1661 {
1662 /* If we are not using preemption we keep forcing a task switch to
1663 see if any other task has become available. If we are using
1664 preemption we don't need to do this as any task becoming available
1665 will automatically get the processor anyway. */
1666 taskYIELD();
1667 }
1668#endif
1669
1670#if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
1671 {
1672 /* When using preemption tasks of equal priority will be
1673 timesliced. If a task that is sharing the idle priority is ready
1674 to run then the idle task should yield before the end of the
1675 timeslice.
1676
1677 A critical region is not required here as we are just reading from
1678 the list, and an occasional incorrect value will not matter. If
1679 the ready list at the idle priority contains more than one task
1680 then a task other than the idle task is ready to execute. */
1681 if (listCURRENT_LIST_LENGTH(&(pxReadyTasksLists[ tskIDLE_PRIORITY ])) > (unsigned portBASE_TYPE) 1) {
1682 taskYIELD();
1683 }
1684 }
1685#endif
1686
1687#if ( configUSE_IDLE_HOOK == 1 )
1688 {
1689 extern void vApplicationIdleHook(void);
1690
1691 /* Call the user defined function from within the idle task. This
1692 allows the application designer to add background functionality
1693 without the overhead of a separate task.
1694 NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
1695 CALL A FUNCTION THAT MIGHT BLOCK. */
1696 vApplicationIdleHook();
1697 }
1698#endif
1699 }
1700} /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */
1701
1702
1703
1704
1705
1706
1707
1708/*-----------------------------------------------------------
1709 * File private functions documented at the top of the file.
1710 *----------------------------------------------------------*/
1711
1712
1713
1714static void prvInitialiseTCBVariables(tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth)
1715{
1716 /* Store the function name in the TCB. */
1717#if configMAX_TASK_NAME_LEN > 1
1718 {
1719 /* Don't bring strncpy into the build unnecessarily. */
1720 strncpy((char *) pxTCB->pcTaskName, (const char *) pcName, (unsigned short) configMAX_TASK_NAME_LEN);
1721 }
1722#endif
1723 pxTCB->pcTaskName[(unsigned short) configMAX_TASK_NAME_LEN - (unsigned short) 1 ] = '\0';
1724
1725 /* This is used as an array index so must ensure it's not too large. First
1726 remove the privilege bit if one is present. */
1727 if (uxPriority >= configMAX_PRIORITIES) {
1728 uxPriority = configMAX_PRIORITIES - 1;
1729 }
1730
1731 pxTCB->uxPriority = uxPriority;
1732#if ( configUSE_MUTEXES == 1 )
1733 {
1734 pxTCB->uxBasePriority = uxPriority;
1735 }
1736#endif
1737
1738 vListInitialiseItem(&(pxTCB->xGenericListItem));
1739 vListInitialiseItem(&(pxTCB->xEventListItem));
1740
1741 /* Set the pxTCB as a link back from the xListItem. This is so we can get
1742 back to the containing TCB from a generic item in a list. */
1743 listSET_LIST_ITEM_OWNER(&(pxTCB->xGenericListItem), pxTCB);
1744
1745 /* Event lists are always in priority order. */
1746 listSET_LIST_ITEM_VALUE(&(pxTCB->xEventListItem), configMAX_PRIORITIES - (portTickType) uxPriority);
1747 listSET_LIST_ITEM_OWNER(&(pxTCB->xEventListItem), pxTCB);
1748
1749#if ( portCRITICAL_NESTING_IN_TCB == 1 )
1750 {
1751 pxTCB->uxCriticalNesting = (unsigned portBASE_TYPE) 0;
1752 }
1753#endif
1754
1755#if ( configUSE_APPLICATION_TASK_TAG == 1 )
1756 {
1757 pxTCB->pxTaskTag = NULL;
1758 }
1759#endif
1760
1761#if ( configGENERATE_RUN_TIME_STATS == 1 )
1762 {
1763 pxTCB->ulRunTimeCounter = 0UL;
1764 }
1765#endif
1766
1767#if ( portUSING_MPU_WRAPPERS == 1 )
1768 {
1769 vPortStoreTaskMPUSettings(&(pxTCB->xMPUSettings), xRegions, pxTCB->pxStack, usStackDepth);
1770 }
1771#else
1772 {
1773 (void) xRegions;
1774 (void) usStackDepth;
1775 }
1776#endif
1777}
1778/*-----------------------------------------------------------*/
1779
1780#if ( portUSING_MPU_WRAPPERS == 1 )
1781
1782void vTaskAllocateMPURegions(xTaskHandle xTaskToModify, const xMemoryRegion * const xRegions)
1783{
1784 tskTCB *pxTCB;
1785
1786 if (xTaskToModify == pxCurrentTCB) {
1787 xTaskToModify = NULL;
1788 }
1789
1790 /* If null is passed in here then we are deleting ourselves. */
1791 pxTCB = prvGetTCBFromHandle(xTaskToModify);
1792
1793 vPortStoreTaskMPUSettings(&(pxTCB->xMPUSettings), xRegions, NULL, 0);
1794}
1795/*-----------------------------------------------------------*/
1796#endif
1797
1798static void prvInitialiseTaskLists(void)
1799{
1800 unsigned portBASE_TYPE uxPriority;
1801
1802 for (uxPriority = 0; uxPriority < configMAX_PRIORITIES; uxPriority++) {
1803 vListInitialise((xList *) &(pxReadyTasksLists[ uxPriority ]));
1804 }
1805
1806 vListInitialise((xList *) &xDelayedTaskList1);
1807 vListInitialise((xList *) &xDelayedTaskList2);
1808 vListInitialise((xList *) &xPendingReadyList);
1809
1810#if ( INCLUDE_vTaskDelete == 1 )
1811 {
1812 vListInitialise((xList *) &xTasksWaitingTermination);
1813 }
1814#endif
1815
1816#if ( INCLUDE_vTaskSuspend == 1 )
1817 {
1818 vListInitialise((xList *) &xSuspendedTaskList);
1819 }
1820#endif
1821
1822 /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
1823 using list2. */
1824 pxDelayedTaskList = &xDelayedTaskList1;
1825 pxOverflowDelayedTaskList = &xDelayedTaskList2;
1826}
1827/*-----------------------------------------------------------*/
1828
1829static void prvCheckTasksWaitingTermination(void)
1830{
1831#if ( INCLUDE_vTaskDelete == 1 )
1832 {
1833 portBASE_TYPE xListIsEmpty;
1834
1835 /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
1836 too often in the idle task. */
1837 if (uxTasksDeleted > (unsigned portBASE_TYPE) 0) {
1838 vTaskSuspendAll();
1839 xListIsEmpty = listLIST_IS_EMPTY(&xTasksWaitingTermination);
1840 xTaskResumeAll();
1841
1842 if (!xListIsEmpty) {
1843 tskTCB *pxTCB;
1844
1845 portENTER_CRITICAL();
1846 {
1847 pxTCB = (tskTCB *) listGET_OWNER_OF_HEAD_ENTRY(((xList *) & xTasksWaitingTermination));
1848 vListRemove(&(pxTCB->xGenericListItem));
1849 --uxCurrentNumberOfTasks;
1850 --uxTasksDeleted;
1851 }
1852 portEXIT_CRITICAL();
1853
1854 prvDeleteTCB(pxTCB);
1855 }
1856 }
1857 }
1858#endif
1859}
1860/*-----------------------------------------------------------*/
1861
1862static tskTCB *prvAllocateTCBAndStack(unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer)
1863{
1864 tskTCB *pxNewTCB;
1865
1866 /* Allocate space for the TCB. Where the memory comes from depends on
1867 the implementation of the port malloc function. */
1868 pxNewTCB = (tskTCB *) pvPortMalloc(sizeof(tskTCB));
1869
1870 if (pxNewTCB != NULL) {
1871 /* Allocate space for the stack used by the task being created.
1872 The base of the stack memory stored in the TCB so the task can
1873 be deleted later if required. */
1874 pxNewTCB->pxStack = (portSTACK_TYPE *) pvPortMallocAligned((((size_t)usStackDepth) * sizeof(portSTACK_TYPE)), puxStackBuffer);
1875
1876 if (pxNewTCB->pxStack == NULL) {
1877 /* Could not allocate the stack. Delete the allocated TCB. */
1878 vPortFree(pxNewTCB);
1879 pxNewTCB = NULL;
1880 } else {
1881 /* Just to help debugging. */
1882 memset(pxNewTCB->pxStack, tskSTACK_FILL_BYTE, usStackDepth * sizeof(portSTACK_TYPE));
1883 }
1884 }
1885
1886 return pxNewTCB;
1887}
1888/*-----------------------------------------------------------*/
1889
1890#if ( configUSE_TRACE_FACILITY == 1 )
1891
1892static void prvListTaskWithinSingleList(const signed char *pcWriteBuffer, xList *pxList, signed char cStatus)
1893{
1894 volatile tskTCB *pxNextTCB, *pxFirstTCB;
1895 unsigned short usStackRemaining;
1896
1897 /* Write the details of all the TCB's in pxList into the buffer. */
1898 listGET_OWNER_OF_NEXT_ENTRY(pxFirstTCB, pxList);
1899 do {
1900 listGET_OWNER_OF_NEXT_ENTRY(pxNextTCB, pxList);
1901#if ( portSTACK_GROWTH > 0 )
1902 {
1903 usStackRemaining = usTaskCheckFreeStackSpace((unsigned char *) pxNextTCB->pxEndOfStack);
1904 }
1905#else
1906 {
1907 usStackRemaining = usTaskCheckFreeStackSpace((unsigned char *) pxNextTCB->pxStack);
1908 }
1909#endif
1910
1911 sprintf(pcStatusString, (char *) "%s\t\t%c\t%u\t%u\t%u\r\n", pxNextTCB->pcTaskName, cStatus, (unsigned int) pxNextTCB->uxPriority, usStackRemaining, (unsigned int) pxNextTCB->uxTCBNumber);
1912 strcat((char *) pcWriteBuffer, (char *) pcStatusString);
1913
1914 } while (pxNextTCB != pxFirstTCB);
1915}
1916
1917#endif
1918/*-----------------------------------------------------------*/
1919
1920#if ( configGENERATE_RUN_TIME_STATS == 1 )
1921
1922static void prvGenerateRunTimeStatsForTasksInList(const signed char *pcWriteBuffer, xList *pxList, unsigned long ulTotalRunTime)
1923{
1924 volatile tskTCB *pxNextTCB, *pxFirstTCB;
1925 unsigned long ulStatsAsPercentage;
1926
1927 /* Write the run time stats of all the TCB's in pxList into the buffer. */
1928 listGET_OWNER_OF_NEXT_ENTRY(pxFirstTCB, pxList);
1929 do {
1930 /* Get next TCB in from the list. */
1931 listGET_OWNER_OF_NEXT_ENTRY(pxNextTCB, pxList);
1932
1933 /* Divide by zero check. */
1934 if (ulTotalRunTime > 0UL) {
1935 /* Has the task run at all? */
1936 if (pxNextTCB->ulRunTimeCounter == 0) {
1937 /* The task has used no CPU time at all. */
1938 sprintf(pcStatsString, (char *) "%s\t\t0\t\t0%%\r\n", pxNextTCB->pcTaskName);
1939 } else {
1940 /* What percentage of the total run time as the task used?
1941 This will always be rounded down to the nearest integer. */
1942 ulStatsAsPercentage = (100UL * pxNextTCB->ulRunTimeCounter) / ulTotalRunTime;
1943
1944 if (ulStatsAsPercentage > 0UL) {
1945 sprintf(pcStatsString, (char *) "%s\t\t%u\t\t%u%%\r\n", pxNextTCB->pcTaskName, (unsigned int) pxNextTCB->ulRunTimeCounter, (unsigned int) ulStatsAsPercentage);
1946 } else {
1947 /* If the percentage is zero here then the task has
1948 consumed less than 1% of the total run time. */
1949 sprintf(pcStatsString, (char *) "%s\t\t%u\t\t<1%%\r\n", pxNextTCB->pcTaskName, (unsigned int) pxNextTCB->ulRunTimeCounter);
1950 }
1951 }
1952
1953 strcat((char *) pcWriteBuffer, (char *) pcStatsString);
1954 }
1955
1956 } while (pxNextTCB != pxFirstTCB);
1957}
1958
1959#endif
1960/*-----------------------------------------------------------*/
1961
1962#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
1963
1964static unsigned short usTaskCheckFreeStackSpace(const unsigned char * pucStackByte)
1965{
1966 register unsigned short usCount = 0;
1967
1968 while (*pucStackByte == tskSTACK_FILL_BYTE) {
1969 pucStackByte -= portSTACK_GROWTH;
1970 usCount++;
1971 }
1972
1973 usCount /= sizeof(portSTACK_TYPE);
1974
1975 return usCount;
1976}
1977
1978#endif
1979/*-----------------------------------------------------------*/
1980
1981#if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )
1982
1983unsigned portBASE_TYPE uxTaskGetStackHighWaterMark(xTaskHandle xTask)
1984{
1985 tskTCB *pxTCB;
1986 unsigned char *pcEndOfStack;
1987 unsigned portBASE_TYPE uxReturn;
1988
1989 pxTCB = prvGetTCBFromHandle(xTask);
1990
1991#if portSTACK_GROWTH < 0
1992 {
1993 pcEndOfStack = (unsigned char *) pxTCB->pxStack;
1994 }
1995#else
1996 {
1997 pcEndOfStack = (unsigned char *) pxTCB->pxEndOfStack;
1998 }
1999#endif
2000
2001 uxReturn = (unsigned portBASE_TYPE) usTaskCheckFreeStackSpace(pcEndOfStack);
2002
2003 return uxReturn;
2004}
2005
2006#endif
2007/*-----------------------------------------------------------*/
2008
2009#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
2010
2011static void prvDeleteTCB(tskTCB *pxTCB)
2012{
2013 /* Free up the memory allocated by the scheduler for the task. It is up to
2014 the task to free any memory allocated at the application level. */
2015 vPortFreeAligned(pxTCB->pxStack);
2016 vPortFree(pxTCB);
2017}
2018
2019#endif
2020
2021
2022/*-----------------------------------------------------------*/
2023
2024#if ( INCLUDE_xTaskGetCurrentTaskHandle == 1 )
2025
2026xTaskHandle xTaskGetCurrentTaskHandle(void)
2027{
2028 xTaskHandle xReturn;
2029
2030 /* A critical section is not required as this is not called from
2031 an interrupt and the current TCB will always be the same for any
2032 individual execution thread. */
2033 xReturn = pxCurrentTCB;
2034
2035 return xReturn;
2036}
2037
2038#endif
2039
2040/*-----------------------------------------------------------*/
2041
2042#if ( INCLUDE_xTaskGetSchedulerState == 1 )
2043
2044portBASE_TYPE xTaskGetSchedulerState(void)
2045{
2046 portBASE_TYPE xReturn;
2047
2048 if (xSchedulerRunning == pdFALSE) {
2049 xReturn = taskSCHEDULER_NOT_STARTED;
2050 } else {
2051 if (uxSchedulerSuspended == (unsigned portBASE_TYPE) pdFALSE) {
2052 xReturn = taskSCHEDULER_RUNNING;
2053 } else {
2054 xReturn = taskSCHEDULER_SUSPENDED;
2055 }
2056 }
2057
2058 return xReturn;
2059}
2060
2061#endif
2062/*-----------------------------------------------------------*/
2063
2064#if ( configUSE_MUTEXES == 1 )
2065
2066void vTaskPriorityInherit(xTaskHandle * const pxMutexHolder)
2067{
2068 tskTCB * const pxTCB = (tskTCB *) pxMutexHolder;
2069
2070 if (pxTCB->uxPriority < pxCurrentTCB->uxPriority) {
2071 /* Adjust the mutex holder state to account for its new priority. */
2072 listSET_LIST_ITEM_VALUE(&(pxTCB->xEventListItem), configMAX_PRIORITIES - (portTickType) pxCurrentTCB->uxPriority);
2073
2074 /* If the task being modified is in the ready state it will need to
2075 be moved in to a new list. */
2076 if (listIS_CONTAINED_WITHIN(&(pxReadyTasksLists[ pxTCB->uxPriority ]), &(pxTCB->xGenericListItem))) {
2077 vListRemove(&(pxTCB->xGenericListItem));
2078
2079 /* Inherit the priority before being moved into the new list. */
2080 pxTCB->uxPriority = pxCurrentTCB->uxPriority;
2081 prvAddTaskToReadyQueue(pxTCB);
2082 } else {
2083 /* Just inherit the priority. */
2084 pxTCB->uxPriority = pxCurrentTCB->uxPriority;
2085 }
2086 }
2087}
2088
2089#endif
2090/*-----------------------------------------------------------*/
2091
2092#if ( configUSE_MUTEXES == 1 )
2093
2094void vTaskPriorityDisinherit(xTaskHandle * const pxMutexHolder)
2095{
2096 tskTCB * const pxTCB = (tskTCB *) pxMutexHolder;
2097
2098 if (pxMutexHolder != NULL) {
2099 if (pxTCB->uxPriority != pxTCB->uxBasePriority) {
2100 /* We must be the running task to be able to give the mutex back.
2101 Remove ourselves from the ready list we currently appear in. */
2102 vListRemove(&(pxTCB->xGenericListItem));
2103
2104 /* Disinherit the priority before adding ourselves into the new
2105 ready list. */
2106 pxTCB->uxPriority = pxTCB->uxBasePriority;
2107 listSET_LIST_ITEM_VALUE(&(pxTCB->xEventListItem), configMAX_PRIORITIES - (portTickType) pxTCB->uxPriority);
2108 prvAddTaskToReadyQueue(pxTCB);
2109 }
2110 }
2111}
2112
2113#endif
2114/*-----------------------------------------------------------*/
2115
2116#if ( portCRITICAL_NESTING_IN_TCB == 1 )
2117
2118void vTaskEnterCritical(void)
2119{
2120 portDISABLE_INTERRUPTS();
2121
2122 if (xSchedulerRunning != pdFALSE) {
2123 pxCurrentTCB->uxCriticalNesting++;
2124 }
2125}
2126
2127#endif
2128/*-----------------------------------------------------------*/
2129
2130#if ( portCRITICAL_NESTING_IN_TCB == 1 )
2131
2132void vTaskExitCritical(void)
2133{
2134 if (xSchedulerRunning != pdFALSE) {
2135 if (pxCurrentTCB->uxCriticalNesting > 0) {
2136 pxCurrentTCB->uxCriticalNesting--;
2137
2138 if (pxCurrentTCB->uxCriticalNesting == 0) {
2139 portENABLE_INTERRUPTS();
2140 }
2141 }
2142 }
2143}
2144
2145#endif
2146/*-----------------------------------------------------------*/
2147
2148
2149
2150