2 FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
\r
4 This file is part of the FreeRTOS distribution.
\r
6 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
7 the terms of the GNU General Public License (version 2) as published by the
\r
8 Free Software Foundation and modified by the FreeRTOS exception.
\r
9 **NOTE** The exception to the GPL is included to allow you to distribute a
\r
10 combined work that includes FreeRTOS without being obliged to provide the
\r
11 source code for proprietary components outside of the FreeRTOS kernel.
\r
12 Alternative commercial license and support terms are also available upon
\r
13 request. See the licensing section of http://www.FreeRTOS.org for full
\r
16 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
\r
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
\r
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
\r
21 You should have received a copy of the GNU General Public License along
\r
22 with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
\r
23 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
\r
26 ***************************************************************************
\r
28 * Looking for a quick start? Then check out the FreeRTOS eBook! *
\r
29 * See http://www.FreeRTOS.org/Documentation for details *
\r
31 ***************************************************************************
\r
35 Please ensure to read the configuration and relevant port sections of the
\r
36 online documentation.
\r
38 http://www.FreeRTOS.org - Documentation, latest information, license and
\r
41 http://www.SafeRTOS.com - A version that is certified for use in safety
\r
44 http://www.OpenRTOS.com - Commercial support, development, porting,
\r
45 licensing and training services.
\r
53 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
\r
54 all the API functions to use the MPU wrappers. That should only be done when
\r
55 task.h is included from an application file. */
\r
56 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
\r
58 #include "FreeRTOS.h"
\r
60 #include "StackMacros.h"
\r
62 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
\r
65 * Macro to define the amount of stack available to the idle task.
\r
67 #define tskIDLE_STACK_SIZE configMINIMAL_STACK_SIZE
\r
69 #define tskIDLE_PRIORITY ( ( unsigned portBASE_TYPE ) 0 )
\r
72 * Task control block. A task control block (TCB) is allocated to each task,
\r
73 * and stores the context of the task.
\r
75 typedef struct tskTaskControlBlock
\r
77 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. */
\r
79 #if ( portUSING_MPU_WRAPPERS == 1 )
\r
80 xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE STRUCT. */
\r
83 xListItem xGenericListItem; /*< List item used to place the TCB in ready and blocked queues. */
\r
84 xListItem xEventListItem; /*< List item used to place the TCB in event lists. */
\r
85 unsigned portBASE_TYPE uxPriority; /*< The priority of the task where 0 is the lowest priority. */
\r
86 portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */
\r
87 signed portCHAR pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */
\r
89 #if ( portSTACK_GROWTH > 0 )
\r
90 portSTACK_TYPE *pxEndOfStack; /*< Used for stack overflow checking on architectures where the stack grows up from low memory. */
\r
93 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
\r
94 unsigned portBASE_TYPE uxCriticalNesting;
\r
97 #if ( configUSE_TRACE_FACILITY == 1 )
\r
98 unsigned portBASE_TYPE uxTCBNumber; /*< This is used for tracing the scheduler and making debugging easier only. */
\r
101 #if ( configUSE_MUTEXES == 1 )
\r
102 unsigned portBASE_TYPE uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
\r
105 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
106 pdTASK_HOOK_CODE pxTaskTag;
\r
109 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
110 unsigned portLONG ulRunTimeCounter; /*< Used for calculating how much CPU time each task is utilising. */
\r
117 * Some kernel aware debuggers require data to be viewed to be global, rather
\r
120 #ifdef portREMOVE_STATIC_QUALIFIER
\r
125 PRIVILEGED_DATA tskTCB * volatile pxCurrentTCB = NULL;
\r
127 /* Lists for ready and blocked tasks. --------------------*/
\r
129 PRIVILEGED_DATA static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */
\r
130 PRIVILEGED_DATA static xList xDelayedTaskList1; /*< Delayed tasks. */
\r
131 PRIVILEGED_DATA static xList xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
\r
132 PRIVILEGED_DATA static xList * volatile pxDelayedTaskList ; /*< Points to the delayed task list currently being used. */
\r
133 PRIVILEGED_DATA static xList * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
\r
134 PRIVILEGED_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. */
\r
136 #if ( INCLUDE_vTaskDelete == 1 )
\r
138 PRIVILEGED_DATA static volatile xList xTasksWaitingTermination; /*< Tasks that have been deleted - but the their memory not yet freed. */
\r
139 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTasksDeleted = ( unsigned portBASE_TYPE ) 0;
\r
143 #if ( INCLUDE_vTaskSuspend == 1 )
\r
145 PRIVILEGED_DATA static xList xSuspendedTaskList; /*< Tasks that are currently suspended. */
\r
149 /* File private variables. --------------------------------*/
\r
150 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks = ( unsigned portBASE_TYPE ) 0;
\r
151 PRIVILEGED_DATA static volatile portTickType xTickCount = ( portTickType ) 0;
\r
152 PRIVILEGED_DATA static unsigned portBASE_TYPE uxTopUsedPriority = tskIDLE_PRIORITY;
\r
153 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTopReadyPriority = tskIDLE_PRIORITY;
\r
154 PRIVILEGED_DATA static volatile signed portBASE_TYPE xSchedulerRunning = pdFALSE;
\r
155 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxSchedulerSuspended = ( unsigned portBASE_TYPE ) pdFALSE;
\r
156 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxMissedTicks = ( unsigned portBASE_TYPE ) 0;
\r
157 PRIVILEGED_DATA static volatile portBASE_TYPE xMissedYield = ( portBASE_TYPE ) pdFALSE;
\r
158 PRIVILEGED_DATA static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0;
\r
159 PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber = ( unsigned portBASE_TYPE ) 0;
\r
161 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
163 PRIVILEGED_DATA static portCHAR pcStatsString[ 50 ] ;
\r
164 PRIVILEGED_DATA static unsigned portLONG ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */
\r
165 static void prvGenerateRunTimeStatsForTasksInList( const signed portCHAR *pcWriteBuffer, xList *pxList, unsigned portLONG ulTotalRunTime ) PRIVILEGED_FUNCTION;
\r
169 /* Debugging and trace facilities private variables and macros. ------------*/
\r
172 * The value used to fill the stack of a task when the task is created. This
\r
173 * is used purely for checking the high water mark for tasks.
\r
175 #define tskSTACK_FILL_BYTE ( 0xa5 )
\r
178 * Macros used by vListTask to indicate which state a task is in.
\r
180 #define tskBLOCKED_CHAR ( ( signed portCHAR ) 'B' )
\r
181 #define tskREADY_CHAR ( ( signed portCHAR ) 'R' )
\r
182 #define tskDELETED_CHAR ( ( signed portCHAR ) 'D' )
\r
183 #define tskSUSPENDED_CHAR ( ( signed portCHAR ) 'S' )
\r
186 * Macros and private variables used by the trace facility.
\r
188 #if ( configUSE_TRACE_FACILITY == 1 )
\r
190 #define tskSIZE_OF_EACH_TRACE_LINE ( ( unsigned portLONG ) ( sizeof( unsigned portLONG ) + sizeof( unsigned portLONG ) ) )
\r
191 PRIVILEGED_DATA static volatile signed portCHAR * volatile pcTraceBuffer;
\r
192 PRIVILEGED_DATA static signed portCHAR *pcTraceBufferStart;
\r
193 PRIVILEGED_DATA static signed portCHAR *pcTraceBufferEnd;
\r
194 PRIVILEGED_DATA static signed portBASE_TYPE xTracing = pdFALSE;
\r
195 static unsigned portBASE_TYPE uxPreviousTask = 255;
\r
196 PRIVILEGED_DATA static portCHAR pcStatusString[ 50 ];
\r
200 /*-----------------------------------------------------------*/
\r
203 * Macro that writes a trace of scheduler activity to a buffer. This trace
\r
204 * shows which task is running when and is very useful as a debugging tool.
\r
205 * As this macro is called each context switch it is a good idea to undefine
\r
206 * it if not using the facility.
\r
208 #if ( configUSE_TRACE_FACILITY == 1 )
\r
210 #define vWriteTraceToBuffer() \
\r
214 if( uxPreviousTask != pxCurrentTCB->uxTCBNumber ) \
\r
216 if( ( pcTraceBuffer + tskSIZE_OF_EACH_TRACE_LINE ) < pcTraceBufferEnd ) \
\r
218 uxPreviousTask = pxCurrentTCB->uxTCBNumber; \
\r
219 *( unsigned portLONG * ) pcTraceBuffer = ( unsigned portLONG ) xTickCount; \
\r
220 pcTraceBuffer += sizeof( unsigned portLONG ); \
\r
221 *( unsigned portLONG * ) pcTraceBuffer = ( unsigned portLONG ) uxPreviousTask; \
\r
222 pcTraceBuffer += sizeof( unsigned portLONG ); \
\r
226 xTracing = pdFALSE; \
\r
234 #define vWriteTraceToBuffer()
\r
237 /*-----------------------------------------------------------*/
\r
240 * Place the task represented by pxTCB into the appropriate ready queue for
\r
241 * the task. It is inserted at the end of the list. One quirk of this is
\r
242 * that if the task being inserted is at the same priority as the currently
\r
243 * executing task, then it will only be rescheduled after the currently
\r
244 * executing task has been rescheduled.
\r
246 #define prvAddTaskToReadyQueue( pxTCB ) \
\r
248 if( pxTCB->uxPriority > uxTopReadyPriority ) \
\r
250 uxTopReadyPriority = pxTCB->uxPriority; \
\r
252 vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ); \
\r
254 /*-----------------------------------------------------------*/
\r
257 * Macro that looks at the list of tasks that are currently delayed to see if
\r
258 * any require waking.
\r
260 * Tasks are stored in the queue in the order of their wake time - meaning
\r
261 * once one tasks has been found whose timer has not expired we need not look
\r
262 * any further down the list.
\r
264 #define prvCheckDelayedTasks() \
\r
266 register tskTCB *pxTCB; \
\r
268 while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ) ) != NULL ) \
\r
270 if( xTickCount < listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ) ) \
\r
274 vListRemove( &( pxTCB->xGenericListItem ) ); \
\r
275 /* Is the task waiting on an event also? */ \
\r
276 if( pxTCB->xEventListItem.pvContainer ) \
\r
278 vListRemove( &( pxTCB->xEventListItem ) ); \
\r
280 prvAddTaskToReadyQueue( pxTCB ); \
\r
283 /*-----------------------------------------------------------*/
\r
286 * Several functions take an xTaskHandle parameter that can optionally be NULL,
\r
287 * where NULL is used to indicate that the handle of the currently executing
\r
288 * task should be used in place of the parameter. This macro simply checks to
\r
289 * see if the parameter is NULL and returns a pointer to the appropriate TCB.
\r
291 #define prvGetTCBFromHandle( pxHandle ) ( ( pxHandle == NULL ) ? ( tskTCB * ) pxCurrentTCB : ( tskTCB * ) pxHandle )
\r
294 /* File private functions. --------------------------------*/
\r
297 * Utility to ready a TCB for a given task. Mainly just copies the parameters
\r
298 * into the TCB structure.
\r
300 static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed portCHAR * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned portSHORT usStackDepth ) PRIVILEGED_FUNCTION;
\r
303 * Utility to ready all the lists used by the scheduler. This is called
\r
304 * automatically upon the creation of the first task.
\r
306 static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION;
\r
309 * The idle task, which as all tasks is implemented as a never ending loop.
\r
310 * The idle task is automatically created and added to the ready lists upon
\r
311 * creation of the first user task.
\r
313 * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific
\r
314 * language extensions. The equivalent prototype for this function is:
\r
316 * void prvIdleTask( void *pvParameters );
\r
319 static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters );
\r
322 * Utility to free all memory allocated by the scheduler to hold a TCB,
\r
323 * including the stack pointed to by the TCB.
\r
325 * This does not free memory allocated by the task itself (i.e. memory
\r
326 * allocated by calls to pvPortMalloc from within the tasks application code).
\r
328 #if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
\r
330 static void prvDeleteTCB( tskTCB *pxTCB ) PRIVILEGED_FUNCTION;
\r
335 * Used only by the idle task. This checks to see if anything has been placed
\r
336 * in the list of tasks waiting to be deleted. If so the task is cleaned up
\r
337 * and its TCB deleted.
\r
339 static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION;
\r
342 * Allocates memory from the heap for a TCB and associated stack. Checks the
\r
343 * allocation was successful.
\r
345 static tskTCB *prvAllocateTCBAndStack( unsigned portSHORT usStackDepth, portSTACK_TYPE *puxStackBuffer ) PRIVILEGED_FUNCTION;
\r
348 * Called from vTaskList. vListTasks details all the tasks currently under
\r
349 * control of the scheduler. The tasks may be in one of a number of lists.
\r
350 * prvListTaskWithinSingleList accepts a list and details the tasks from
\r
351 * within just that list.
\r
353 * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM
\r
354 * NORMAL APPLICATION CODE.
\r
356 #if ( configUSE_TRACE_FACILITY == 1 )
\r
358 static void prvListTaskWithinSingleList( const signed portCHAR *pcWriteBuffer, xList *pxList, signed portCHAR cStatus ) PRIVILEGED_FUNCTION;
\r
363 * When a task is created, the stack of the task is filled with a known value.
\r
364 * This function determines the 'high water mark' of the task stack by
\r
365 * determining how much of the stack remains at the original preset value.
\r
367 #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
\r
369 static unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR * pucStackByte ) PRIVILEGED_FUNCTION;
\r
378 /*-----------------------------------------------------------
\r
379 * TASK CREATION API documented in task.h
\r
380 *----------------------------------------------------------*/
\r
382 signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode, const signed portCHAR * const pcName, unsigned portSHORT usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion * const xRegions )
\r
384 signed portBASE_TYPE xReturn;
\r
386 portBASE_TYPE xRunPrivileged;
\r
388 /* Allocate the memory required by the TCB and stack for the new task,
\r
389 checking that the allocation was successful. */
\r
390 pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer );
\r
392 if( pxNewTCB != NULL )
\r
394 portSTACK_TYPE *pxTopOfStack;
\r
396 /* Should the task be created in privileged mode? */
\r
397 if( ( uxPriority & portPRIVILEGE_BIT ) != 0x00 )
\r
399 xRunPrivileged = pdTRUE;
\r
403 xRunPrivileged = pdFALSE;
\r
405 uxPriority &= ~portPRIVILEGE_BIT;
\r
407 /* Calculate the top of stack address. This depends on whether the
\r
408 stack grows from high memory to low (as per the 80x86) or visa versa.
\r
409 portSTACK_GROWTH is used to make the result positive or negative as
\r
410 required by the port. */
\r
411 #if( portSTACK_GROWTH < 0 )
\r
413 pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
\r
414 pxTopOfStack = ( portSTACK_TYPE * ) ( ( ( unsigned portLONG ) pxTopOfStack ) & ( ( unsigned portLONG ) ~portBYTE_ALIGNMENT_MASK ) );
\r
418 pxTopOfStack = pxNewTCB->pxStack;
\r
420 /* If we want to use stack checking on architectures that use
\r
421 a positive stack growth direction then we also need to store the
\r
422 other extreme of the stack space. */
\r
423 pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
\r
427 /* Setup the newly allocated TCB with the initial state of the task. */
\r
428 prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth );
\r
430 /* Initialize the TCB stack to look as if the task was already running,
\r
431 but had been interrupted by the scheduler. The return address is set
\r
432 to the start of the task function. Once the stack has been initialised
\r
433 the top of stack variable is updated. */
\r
434 #if( portUSING_MPU_WRAPPERS == 1 )
\r
436 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
\r
440 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
\r
441 ( void ) xRunPrivileged;
\r
445 /* We are going to manipulate the task queues to add this task to a
\r
446 ready list, so must make sure no interrupts occur. */
\r
447 portENTER_CRITICAL();
\r
449 uxCurrentNumberOfTasks++;
\r
450 if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )
\r
452 /* As this is the first task it must also be the current task. */
\r
453 pxCurrentTCB = pxNewTCB;
\r
455 /* This is the first task to be created so do the preliminary
\r
456 initialisation required. We will not recover if this call
\r
457 fails, but we will report the failure. */
\r
458 prvInitialiseTaskLists();
\r
462 /* If the scheduler is not already running, make this task the
\r
463 current task if it is the highest priority task to be created
\r
465 if( xSchedulerRunning == pdFALSE )
\r
467 if( pxCurrentTCB->uxPriority <= uxPriority )
\r
469 pxCurrentTCB = pxNewTCB;
\r
474 /* Remember the top priority to make context switching faster. Use
\r
475 the priority in pxNewTCB as this has been capped to a valid value. */
\r
476 if( pxNewTCB->uxPriority > uxTopUsedPriority )
\r
478 uxTopUsedPriority = pxNewTCB->uxPriority;
\r
481 #if ( configUSE_TRACE_FACILITY == 1 )
\r
483 /* Add a counter into the TCB for tracing only. */
\r
484 pxNewTCB->uxTCBNumber = uxTaskNumber;
\r
489 prvAddTaskToReadyQueue( pxNewTCB );
\r
492 traceTASK_CREATE( pxNewTCB );
\r
494 portEXIT_CRITICAL();
\r
498 xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
\r
499 traceTASK_CREATE_FAILED( pxNewTCB );
\r
502 if( xReturn == pdPASS )
\r
504 if( ( void * ) pxCreatedTask != NULL )
\r
506 /* Pass the TCB out - in an anonymous way. The calling function/
\r
507 task can use this as a handle to delete the task later if
\r
509 *pxCreatedTask = ( xTaskHandle ) pxNewTCB;
\r
512 if( xSchedulerRunning != pdFALSE )
\r
514 /* If the created task is of a higher priority than the current task
\r
515 then it should run now. */
\r
516 if( pxCurrentTCB->uxPriority < uxPriority )
\r
518 portYIELD_WITHIN_API();
\r
525 /*-----------------------------------------------------------*/
\r
527 #if ( INCLUDE_vTaskDelete == 1 )
\r
529 void vTaskDelete( xTaskHandle pxTaskToDelete )
\r
533 portENTER_CRITICAL();
\r
535 /* Ensure a yield is performed if the current task is being
\r
537 if( pxTaskToDelete == pxCurrentTCB )
\r
539 pxTaskToDelete = NULL;
\r
542 /* If null is passed in here then we are deleting ourselves. */
\r
543 pxTCB = prvGetTCBFromHandle( pxTaskToDelete );
\r
545 /* Remove task from the ready list and place in the termination list.
\r
546 This will stop the task from be scheduled. The idle task will check
\r
547 the termination list and free up any memory allocated by the
\r
548 scheduler for the TCB and stack. */
\r
549 vListRemove( &( pxTCB->xGenericListItem ) );
\r
551 /* Is the task waiting on an event also? */
\r
552 if( pxTCB->xEventListItem.pvContainer )
\r
554 vListRemove( &( pxTCB->xEventListItem ) );
\r
557 vListInsertEnd( ( xList * ) &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );
\r
559 /* Increment the ucTasksDeleted variable so the idle task knows
\r
560 there is a task that has been deleted and that it should therefore
\r
561 check the xTasksWaitingTermination list. */
\r
564 /* Increment the uxTaskNumberVariable also so kernel aware debuggers
\r
565 can detect that the task lists need re-generating. */
\r
568 traceTASK_DELETE( pxTCB );
\r
570 portEXIT_CRITICAL();
\r
572 /* Force a reschedule if we have just deleted the current task. */
\r
573 if( xSchedulerRunning != pdFALSE )
\r
575 if( ( void * ) pxTaskToDelete == NULL )
\r
577 portYIELD_WITHIN_API();
\r
589 /*-----------------------------------------------------------
\r
590 * TASK CONTROL API documented in task.h
\r
591 *----------------------------------------------------------*/
\r
593 #if ( INCLUDE_vTaskDelayUntil == 1 )
\r
595 void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement )
\r
597 portTickType xTimeToWake;
\r
598 portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE;
\r
602 /* Generate the tick time at which the task wants to wake. */
\r
603 xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
\r
605 if( xTickCount < *pxPreviousWakeTime )
\r
607 /* The tick count has overflowed since this function was
\r
608 lasted called. In this case the only time we should ever
\r
609 actually delay is if the wake time has also overflowed,
\r
610 and the wake time is greater than the tick time. When this
\r
611 is the case it is as if neither time had overflowed. */
\r
612 if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xTickCount ) )
\r
614 xShouldDelay = pdTRUE;
\r
619 /* The tick time has not overflowed. In this case we will
\r
620 delay if either the wake time has overflowed, and/or the
\r
621 tick time is less than the wake time. */
\r
622 if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xTickCount ) )
\r
624 xShouldDelay = pdTRUE;
\r
628 /* Update the wake time ready for the next call. */
\r
629 *pxPreviousWakeTime = xTimeToWake;
\r
633 traceTASK_DELAY_UNTIL();
\r
635 /* We must remove ourselves from the ready list before adding
\r
636 ourselves to the blocked list as the same list item is used for
\r
638 vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
640 /* The list item will be inserted in wake time order. */
\r
641 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
\r
643 if( xTimeToWake < xTickCount )
\r
645 /* Wake time has overflowed. Place this item in the
\r
647 vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
651 /* The wake time has not overflowed, so we can use the
\r
652 current block list. */
\r
653 vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
657 xAlreadyYielded = xTaskResumeAll();
\r
659 /* Force a reschedule if xTaskResumeAll has not already done so, we may
\r
660 have put ourselves to sleep. */
\r
661 if( !xAlreadyYielded )
\r
663 portYIELD_WITHIN_API();
\r
668 /*-----------------------------------------------------------*/
\r
670 #if ( INCLUDE_vTaskDelay == 1 )
\r
672 void vTaskDelay( portTickType xTicksToDelay )
\r
674 portTickType xTimeToWake;
\r
675 signed portBASE_TYPE xAlreadyYielded = pdFALSE;
\r
677 /* A delay time of zero just forces a reschedule. */
\r
678 if( xTicksToDelay > ( portTickType ) 0 )
\r
684 /* A task that is removed from the event list while the
\r
685 scheduler is suspended will not get placed in the ready
\r
686 list or removed from the blocked list until the scheduler
\r
689 This task cannot be in an event list as it is the currently
\r
692 /* Calculate the time to wake - this may overflow but this is
\r
694 xTimeToWake = xTickCount + xTicksToDelay;
\r
696 /* We must remove ourselves from the ready list before adding
\r
697 ourselves to the blocked list as the same list item is used for
\r
699 vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
701 /* The list item will be inserted in wake time order. */
\r
702 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
\r
704 if( xTimeToWake < xTickCount )
\r
706 /* Wake time has overflowed. Place this item in the
\r
708 vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
712 /* The wake time has not overflowed, so we can use the
\r
713 current block list. */
\r
714 vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
717 xAlreadyYielded = xTaskResumeAll();
\r
720 /* Force a reschedule if xTaskResumeAll has not already done so, we may
\r
721 have put ourselves to sleep. */
\r
722 if( !xAlreadyYielded )
\r
724 portYIELD_WITHIN_API();
\r
729 /*-----------------------------------------------------------*/
\r
731 #if ( INCLUDE_uxTaskPriorityGet == 1 )
\r
733 unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask )
\r
736 unsigned portBASE_TYPE uxReturn;
\r
738 portENTER_CRITICAL();
\r
740 /* If null is passed in here then we are changing the
\r
741 priority of the calling function. */
\r
742 pxTCB = prvGetTCBFromHandle( pxTask );
\r
743 uxReturn = pxTCB->uxPriority;
\r
745 portEXIT_CRITICAL();
\r
751 /*-----------------------------------------------------------*/
\r
753 #if ( INCLUDE_vTaskPrioritySet == 1 )
\r
755 void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority )
\r
758 unsigned portBASE_TYPE uxCurrentPriority, xYieldRequired = pdFALSE;
\r
760 /* Ensure the new priority is valid. */
\r
761 if( uxNewPriority >= configMAX_PRIORITIES )
\r
763 uxNewPriority = configMAX_PRIORITIES - 1;
\r
766 portENTER_CRITICAL();
\r
768 if( pxTask == pxCurrentTCB )
\r
773 /* If null is passed in here then we are changing the
\r
774 priority of the calling function. */
\r
775 pxTCB = prvGetTCBFromHandle( pxTask );
\r
777 traceTASK_PRIORITY_SET( pxTask, uxNewPriority );
\r
779 #if ( configUSE_MUTEXES == 1 )
\r
781 uxCurrentPriority = pxTCB->uxBasePriority;
\r
785 uxCurrentPriority = pxTCB->uxPriority;
\r
789 if( uxCurrentPriority != uxNewPriority )
\r
791 /* The priority change may have readied a task of higher
\r
792 priority than the calling task. */
\r
793 if( uxNewPriority > uxCurrentPriority )
\r
795 if( pxTask != NULL )
\r
797 /* The priority of another task is being raised. If we
\r
798 were raising the priority of the currently running task
\r
799 there would be no need to switch as it must have already
\r
800 been the highest priority task. */
\r
801 xYieldRequired = pdTRUE;
\r
804 else if( pxTask == NULL )
\r
806 /* Setting our own priority down means there may now be another
\r
807 task of higher priority that is ready to execute. */
\r
808 xYieldRequired = pdTRUE;
\r
813 #if ( configUSE_MUTEXES == 1 )
\r
815 /* Only change the priority being used if the task is not
\r
816 currently using an inherited priority. */
\r
817 if( pxTCB->uxBasePriority == pxTCB->uxPriority )
\r
819 pxTCB->uxPriority = uxNewPriority;
\r
822 /* The base priority gets set whatever. */
\r
823 pxTCB->uxBasePriority = uxNewPriority;
\r
827 pxTCB->uxPriority = uxNewPriority;
\r
831 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( configMAX_PRIORITIES - ( portTickType ) uxNewPriority ) );
\r
833 /* If the task is in the blocked or suspended list we need do
\r
834 nothing more than change it's priority variable. However, if
\r
835 the task is in a ready list it needs to be removed and placed
\r
836 in the queue appropriate to its new priority. */
\r
837 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxCurrentPriority ] ), &( pxTCB->xGenericListItem ) ) )
\r
839 /* The task is currently in its ready list - remove before adding
\r
840 it to it's new ready list. As we are in a critical section we
\r
841 can do this even if the scheduler is suspended. */
\r
842 vListRemove( &( pxTCB->xGenericListItem ) );
\r
843 prvAddTaskToReadyQueue( pxTCB );
\r
846 if( xYieldRequired == pdTRUE )
\r
848 portYIELD_WITHIN_API();
\r
852 portEXIT_CRITICAL();
\r
856 /*-----------------------------------------------------------*/
\r
858 #if ( INCLUDE_vTaskSuspend == 1 )
\r
860 void vTaskSuspend( xTaskHandle pxTaskToSuspend )
\r
864 portENTER_CRITICAL();
\r
866 /* Ensure a yield is performed if the current task is being
\r
868 if( pxTaskToSuspend == pxCurrentTCB )
\r
870 pxTaskToSuspend = NULL;
\r
873 /* If null is passed in here then we are suspending ourselves. */
\r
874 pxTCB = prvGetTCBFromHandle( pxTaskToSuspend );
\r
876 traceTASK_SUSPEND( pxTCB );
\r
878 /* Remove task from the ready/delayed list and place in the suspended list. */
\r
879 vListRemove( &( pxTCB->xGenericListItem ) );
\r
881 /* Is the task waiting on an event also? */
\r
882 if( pxTCB->xEventListItem.pvContainer )
\r
884 vListRemove( &( pxTCB->xEventListItem ) );
\r
887 vListInsertEnd( ( xList * ) &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );
\r
889 portEXIT_CRITICAL();
\r
891 /* We may have just suspended the current task. */
\r
892 if( ( void * ) pxTaskToSuspend == NULL )
\r
894 portYIELD_WITHIN_API();
\r
899 /*-----------------------------------------------------------*/
\r
901 #if ( INCLUDE_vTaskSuspend == 1 )
\r
903 signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask )
\r
905 portBASE_TYPE xReturn = pdFALSE;
\r
906 const tskTCB * const pxTCB = ( tskTCB * ) xTask;
\r
908 /* Is the task we are attempting to resume actually in the
\r
910 if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE )
\r
912 /* Has the task already been resumed from within an ISR? */
\r
913 if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) != pdTRUE )
\r
915 /* Is it in the suspended list because it is in the
\r
916 Suspended state? It is possible to be in the suspended
\r
917 list because it is blocked on a task with no timeout
\r
919 if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) == pdTRUE )
\r
930 /*-----------------------------------------------------------*/
\r
932 #if ( INCLUDE_vTaskSuspend == 1 )
\r
934 void vTaskResume( xTaskHandle pxTaskToResume )
\r
938 /* Remove the task from whichever list it is currently in, and place
\r
939 it in the ready list. */
\r
940 pxTCB = ( tskTCB * ) pxTaskToResume;
\r
942 /* The parameter cannot be NULL as it is impossible to resume the
\r
943 currently executing task. */
\r
944 if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
\r
946 portENTER_CRITICAL();
\r
948 if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
\r
950 traceTASK_RESUME( pxTCB );
\r
952 /* As we are in a critical section we can access the ready
\r
953 lists even if the scheduler is suspended. */
\r
954 vListRemove( &( pxTCB->xGenericListItem ) );
\r
955 prvAddTaskToReadyQueue( pxTCB );
\r
957 /* We may have just resumed a higher priority task. */
\r
958 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
\r
960 /* This yield may not cause the task just resumed to run, but
\r
961 will leave the lists in the correct state for the next yield. */
\r
962 portYIELD_WITHIN_API();
\r
966 portEXIT_CRITICAL();
\r
972 /*-----------------------------------------------------------*/
\r
974 #if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
\r
976 portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume )
\r
978 portBASE_TYPE xYieldRequired = pdFALSE;
\r
981 pxTCB = ( tskTCB * ) pxTaskToResume;
\r
983 if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
\r
985 traceTASK_RESUME_FROM_ISR( pxTCB );
\r
987 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
989 xYieldRequired = ( pxTCB->uxPriority >= pxCurrentTCB->uxPriority );
\r
990 vListRemove( &( pxTCB->xGenericListItem ) );
\r
991 prvAddTaskToReadyQueue( pxTCB );
\r
995 /* We cannot access the delayed or ready lists, so will hold this
\r
996 task pending until the scheduler is resumed, at which point a
\r
997 yield will be performed if necessary. */
\r
998 vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
\r
1002 return xYieldRequired;
\r
1010 /*-----------------------------------------------------------
\r
1011 * PUBLIC SCHEDULER CONTROL documented in task.h
\r
1012 *----------------------------------------------------------*/
\r
1015 void vTaskStartScheduler( void )
\r
1017 portBASE_TYPE xReturn;
\r
1019 /* Add the idle task at the lowest priority. */
\r
1020 xReturn = xTaskCreate( prvIdleTask, ( signed portCHAR * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), ( xTaskHandle * ) NULL );
\r
1022 if( xReturn == pdPASS )
\r
1024 /* Interrupts are turned off here, to ensure a tick does not occur
\r
1025 before or during the call to xPortStartScheduler(). The stacks of
\r
1026 the created tasks contain a status word with interrupts switched on
\r
1027 so interrupts will automatically get re-enabled when the first task
\r
1030 STEPPING THROUGH HERE USING A DEBUGGER CAN CAUSE BIG PROBLEMS IF THE
\r
1031 DEBUGGER ALLOWS INTERRUPTS TO BE PROCESSED. */
\r
1032 portDISABLE_INTERRUPTS();
\r
1034 xSchedulerRunning = pdTRUE;
\r
1035 xTickCount = ( portTickType ) 0;
\r
1037 /* If configGENERATE_RUN_TIME_STATS is defined then the following
\r
1038 macro must be defined to configure the timer/counter used to generate
\r
1039 the run time counter time base. */
\r
1040 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();
\r
1042 /* Setting up the timer tick is hardware specific and thus in the
\r
1043 portable interface. */
\r
1044 if( xPortStartScheduler() )
\r
1046 /* Should not reach here as if the scheduler is running the
\r
1047 function will not return. */
\r
1051 /* Should only reach here if a task calls xTaskEndScheduler(). */
\r
1055 /*-----------------------------------------------------------*/
\r
1057 void vTaskEndScheduler( void )
\r
1059 /* Stop the scheduler interrupts and call the portable scheduler end
\r
1060 routine so the original ISRs can be restored if necessary. The port
\r
1061 layer must ensure interrupts enable bit is left in the correct state. */
\r
1062 portDISABLE_INTERRUPTS();
\r
1063 xSchedulerRunning = pdFALSE;
\r
1064 vPortEndScheduler();
\r
1066 /*----------------------------------------------------------*/
\r
1068 void vTaskSuspendAll( void )
\r
1070 /* A critical section is not required as the variable is of type
\r
1072 ++uxSchedulerSuspended;
\r
1074 /*----------------------------------------------------------*/
\r
1076 signed portBASE_TYPE xTaskResumeAll( void )
\r
1078 register tskTCB *pxTCB;
\r
1079 signed portBASE_TYPE xAlreadyYielded = pdFALSE;
\r
1081 /* It is possible that an ISR caused a task to be removed from an event
\r
1082 list while the scheduler was suspended. If this was the case then the
\r
1083 removed task will have been added to the xPendingReadyList. Once the
\r
1084 scheduler has been resumed it is safe to move all the pending ready
\r
1085 tasks from this list into their appropriate ready list. */
\r
1086 portENTER_CRITICAL();
\r
1088 --uxSchedulerSuspended;
\r
1090 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
1092 if( uxCurrentNumberOfTasks > ( unsigned portBASE_TYPE ) 0 )
\r
1094 portBASE_TYPE xYieldRequired = pdFALSE;
\r
1096 /* Move any readied tasks from the pending list into the
\r
1097 appropriate ready list. */
\r
1098 while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xPendingReadyList ) ) ) != NULL )
\r
1100 vListRemove( &( pxTCB->xEventListItem ) );
\r
1101 vListRemove( &( pxTCB->xGenericListItem ) );
\r
1102 prvAddTaskToReadyQueue( pxTCB );
\r
1104 /* If we have moved a task that has a priority higher than
\r
1105 the current task then we should yield. */
\r
1106 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
\r
1108 xYieldRequired = pdTRUE;
\r
1112 /* If any ticks occurred while the scheduler was suspended then
\r
1113 they should be processed now. This ensures the tick count does not
\r
1114 slip, and that any delayed tasks are resumed at the correct time. */
\r
1115 if( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
\r
1117 while( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
\r
1119 vTaskIncrementTick();
\r
1123 /* As we have processed some ticks it is appropriate to yield
\r
1124 to ensure the highest priority task that is ready to run is
\r
1125 the task actually running. */
\r
1126 #if configUSE_PREEMPTION == 1
\r
1128 xYieldRequired = pdTRUE;
\r
1133 if( ( xYieldRequired == pdTRUE ) || ( xMissedYield == pdTRUE ) )
\r
1135 xAlreadyYielded = pdTRUE;
\r
1136 xMissedYield = pdFALSE;
\r
1137 portYIELD_WITHIN_API();
\r
1142 portEXIT_CRITICAL();
\r
1144 return xAlreadyYielded;
\r
1152 /*-----------------------------------------------------------
\r
1153 * PUBLIC TASK UTILITIES documented in task.h
\r
1154 *----------------------------------------------------------*/
\r
1158 portTickType xTaskGetTickCount( void )
\r
1160 portTickType xTicks;
\r
1162 /* Critical section required if running on a 16 bit processor. */
\r
1163 portENTER_CRITICAL();
\r
1165 xTicks = xTickCount;
\r
1167 portEXIT_CRITICAL();
\r
1171 /*-----------------------------------------------------------*/
\r
1173 unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void )
\r
1175 /* A critical section is not required because the variables are of type
\r
1177 return uxCurrentNumberOfTasks;
\r
1179 /*-----------------------------------------------------------*/
\r
1181 #if ( configUSE_TRACE_FACILITY == 1 )
\r
1183 void vTaskList( signed portCHAR *pcWriteBuffer )
\r
1185 unsigned portBASE_TYPE uxQueue;
\r
1187 /* This is a VERY costly function that should be used for debug only.
\r
1188 It leaves interrupts disabled for a LONG time. */
\r
1190 vTaskSuspendAll();
\r
1192 /* Run through all the lists that could potentially contain a TCB and
\r
1193 report the task name, state and stack high water mark. */
\r
1195 pcWriteBuffer[ 0 ] = ( signed portCHAR ) 0x00;
\r
1196 strcat( ( portCHAR * ) pcWriteBuffer, ( const portCHAR * ) "\r\n" );
\r
1198 uxQueue = uxTopUsedPriority + 1;
\r
1204 if( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) )
\r
1206 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), tskREADY_CHAR );
\r
1208 }while( uxQueue > ( unsigned portSHORT ) tskIDLE_PRIORITY );
\r
1210 if( !listLIST_IS_EMPTY( pxDelayedTaskList ) )
\r
1212 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, tskBLOCKED_CHAR );
\r
1215 if( !listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) )
\r
1217 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, tskBLOCKED_CHAR );
\r
1220 #if( INCLUDE_vTaskDelete == 1 )
\r
1222 if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) )
\r
1224 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, tskDELETED_CHAR );
\r
1229 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1231 if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
\r
1233 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, tskSUSPENDED_CHAR );
\r
1242 /*----------------------------------------------------------*/
\r
1244 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
1246 void vTaskGetRunTimeStats( signed portCHAR *pcWriteBuffer )
\r
1248 unsigned portBASE_TYPE uxQueue;
\r
1249 unsigned portLONG ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
\r
1251 /* This is a VERY costly function that should be used for debug only.
\r
1252 It leaves interrupts disabled for a LONG time. */
\r
1254 vTaskSuspendAll();
\r
1256 /* Run through all the lists that could potentially contain a TCB,
\r
1257 generating a table of run timer percentages in the provided
\r
1260 pcWriteBuffer[ 0 ] = ( signed portCHAR ) 0x00;
\r
1261 strcat( ( portCHAR * ) pcWriteBuffer, ( const portCHAR * ) "\r\n" );
\r
1263 uxQueue = uxTopUsedPriority + 1;
\r
1269 if( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) )
\r
1271 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), ulTotalRunTime );
\r
1273 }while( uxQueue > ( unsigned portSHORT ) tskIDLE_PRIORITY );
\r
1275 if( !listLIST_IS_EMPTY( pxDelayedTaskList ) )
\r
1277 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, ulTotalRunTime );
\r
1280 if( !listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) )
\r
1282 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, ulTotalRunTime );
\r
1285 #if ( INCLUDE_vTaskDelete == 1 )
\r
1287 if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) )
\r
1289 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, ulTotalRunTime );
\r
1294 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1296 if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
\r
1298 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, ulTotalRunTime );
\r
1307 /*----------------------------------------------------------*/
\r
1309 #if ( configUSE_TRACE_FACILITY == 1 )
\r
1311 void vTaskStartTrace( signed portCHAR * pcBuffer, unsigned portLONG ulBufferSize )
\r
1313 portENTER_CRITICAL();
\r
1315 pcTraceBuffer = ( signed portCHAR * )pcBuffer;
\r
1316 pcTraceBufferStart = pcBuffer;
\r
1317 pcTraceBufferEnd = pcBuffer + ( ulBufferSize - tskSIZE_OF_EACH_TRACE_LINE );
\r
1318 xTracing = pdTRUE;
\r
1320 portEXIT_CRITICAL();
\r
1324 /*----------------------------------------------------------*/
\r
1326 #if ( configUSE_TRACE_FACILITY == 1 )
\r
1328 unsigned portLONG ulTaskEndTrace( void )
\r
1330 unsigned portLONG ulBufferLength;
\r
1332 portENTER_CRITICAL();
\r
1333 xTracing = pdFALSE;
\r
1334 portEXIT_CRITICAL();
\r
1336 ulBufferLength = ( unsigned portLONG ) ( pcTraceBuffer - pcTraceBufferStart );
\r
1338 return ulBufferLength;
\r
1345 /*-----------------------------------------------------------
\r
1346 * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES
\r
1347 * documented in task.h
\r
1348 *----------------------------------------------------------*/
\r
1351 void vTaskIncrementTick( void )
\r
1353 /* Called by the portable layer each time a tick interrupt occurs.
\r
1354 Increments the tick then checks to see if the new tick value will cause any
\r
1355 tasks to be unblocked. */
\r
1356 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
1359 if( xTickCount == ( portTickType ) 0 )
\r
1363 /* Tick count has overflowed so we need to swap the delay lists.
\r
1364 If there are any items in pxDelayedTaskList here then there is
\r
1366 pxTemp = pxDelayedTaskList;
\r
1367 pxDelayedTaskList = pxOverflowDelayedTaskList;
\r
1368 pxOverflowDelayedTaskList = pxTemp;
\r
1369 xNumOfOverflows++;
\r
1372 /* See if this tick has made a timeout expire. */
\r
1373 prvCheckDelayedTasks();
\r
1379 /* The tick hook gets called at regular intervals, even if the
\r
1380 scheduler is locked. */
\r
1381 #if ( configUSE_TICK_HOOK == 1 )
\r
1383 extern void vApplicationTickHook( void );
\r
1385 vApplicationTickHook();
\r
1390 #if ( configUSE_TICK_HOOK == 1 )
\r
1392 extern void vApplicationTickHook( void );
\r
1394 /* Guard against the tick hook being called when the missed tick
\r
1395 count is being unwound (when the scheduler is being unlocked. */
\r
1396 if( uxMissedTicks == 0 )
\r
1398 vApplicationTickHook();
\r
1403 traceTASK_INCREMENT_TICK( xTickCount );
\r
1405 /*-----------------------------------------------------------*/
\r
1407 #if ( ( INCLUDE_vTaskCleanUpResources == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
\r
1409 void vTaskCleanUpResources( void )
\r
1411 unsigned portSHORT usQueue;
\r
1412 volatile tskTCB *pxTCB;
\r
1414 usQueue = ( unsigned portSHORT ) uxTopUsedPriority + ( unsigned portSHORT ) 1;
\r
1416 /* Remove any TCB's from the ready queues. */
\r
1421 while( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ usQueue ] ) ) )
\r
1423 listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &( pxReadyTasksLists[ usQueue ] ) );
\r
1424 vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
\r
1426 prvDeleteTCB( ( tskTCB * ) pxTCB );
\r
1428 }while( usQueue > ( unsigned portSHORT ) tskIDLE_PRIORITY );
\r
1430 /* Remove any TCB's from the delayed queue. */
\r
1431 while( !listLIST_IS_EMPTY( &xDelayedTaskList1 ) )
\r
1433 listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList1 );
\r
1434 vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
\r
1436 prvDeleteTCB( ( tskTCB * ) pxTCB );
\r
1439 /* Remove any TCB's from the overflow delayed queue. */
\r
1440 while( !listLIST_IS_EMPTY( &xDelayedTaskList2 ) )
\r
1442 listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList2 );
\r
1443 vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
\r
1445 prvDeleteTCB( ( tskTCB * ) pxTCB );
\r
1448 while( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
\r
1450 listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xSuspendedTaskList );
\r
1451 vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
\r
1453 prvDeleteTCB( ( tskTCB * ) pxTCB );
\r
1458 /*-----------------------------------------------------------*/
\r
1460 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
1462 void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxTagValue )
\r
1466 /* If xTask is NULL then we are setting our own task hook. */
\r
1467 if( xTask == NULL )
\r
1469 xTCB = ( tskTCB * ) pxCurrentTCB;
\r
1473 xTCB = ( tskTCB * ) xTask;
\r
1476 /* Save the hook function in the TCB. A critical section is required as
\r
1477 the value can be accessed from an interrupt. */
\r
1478 portENTER_CRITICAL();
\r
1479 xTCB->pxTaskTag = pxTagValue;
\r
1480 portEXIT_CRITICAL();
\r
1484 /*-----------------------------------------------------------*/
\r
1486 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
1488 pdTASK_HOOK_CODE xTaskGetApplicationTaskTag( xTaskHandle xTask )
\r
1491 pdTASK_HOOK_CODE xReturn;
\r
1493 /* If xTask is NULL then we are setting our own task hook. */
\r
1494 if( xTask == NULL )
\r
1496 xTCB = ( tskTCB * ) pxCurrentTCB;
\r
1500 xTCB = ( tskTCB * ) xTask;
\r
1503 /* Save the hook function in the TCB. A critical section is required as
\r
1504 the value can be accessed from an interrupt. */
\r
1505 portENTER_CRITICAL();
\r
1506 xReturn = xTCB->pxTaskTag;
\r
1507 portEXIT_CRITICAL();
\r
1513 /*-----------------------------------------------------------*/
\r
1515 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
1517 portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParameter )
\r
1520 portBASE_TYPE xReturn;
\r
1522 /* If xTask is NULL then we are calling our own task hook. */
\r
1523 if( xTask == NULL )
\r
1525 xTCB = ( tskTCB * ) pxCurrentTCB;
\r
1529 xTCB = ( tskTCB * ) xTask;
\r
1532 if( xTCB->pxTaskTag != NULL )
\r
1534 xReturn = xTCB->pxTaskTag( pvParameter );
\r
1545 /*-----------------------------------------------------------*/
\r
1547 void vTaskSwitchContext( void )
\r
1549 if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )
\r
1551 /* The scheduler is currently suspended - do not allow a context
\r
1553 xMissedYield = pdTRUE;
\r
1557 traceTASK_SWITCHED_OUT();
\r
1559 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
1561 unsigned portLONG ulTempCounter = portGET_RUN_TIME_COUNTER_VALUE();
\r
1563 /* Add the amount of time the task has been running to the accumulated
\r
1564 time so far. The time the task started running was stored in
\r
1565 ulTaskSwitchedInTime. Note that there is no overflow protection here
\r
1566 so count values are only valid until the timer overflows. Generally
\r
1567 this will be about 1 hour assuming a 1uS timer increment. */
\r
1568 pxCurrentTCB->ulRunTimeCounter += ( ulTempCounter - ulTaskSwitchedInTime );
\r
1569 ulTaskSwitchedInTime = ulTempCounter;
\r
1573 taskFIRST_CHECK_FOR_STACK_OVERFLOW();
\r
1574 taskSECOND_CHECK_FOR_STACK_OVERFLOW();
\r
1576 /* Find the highest priority queue that contains ready tasks. */
\r
1577 while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) )
\r
1579 --uxTopReadyPriority;
\r
1582 /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the tasks of the
\r
1583 same priority get an equal share of the processor time. */
\r
1584 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) );
\r
1586 traceTASK_SWITCHED_IN();
\r
1587 vWriteTraceToBuffer();
\r
1589 /*-----------------------------------------------------------*/
\r
1591 void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait )
\r
1593 portTickType xTimeToWake;
\r
1595 /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
\r
1596 SCHEDULER SUSPENDED. */
\r
1598 /* Place the event list item of the TCB in the appropriate event list.
\r
1599 This is placed in the list in priority order so the highest priority task
\r
1600 is the first to be woken by the event. */
\r
1601 vListInsert( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );
\r
1603 /* We must remove ourselves from the ready list before adding ourselves
\r
1604 to the blocked list as the same list item is used for both lists. We have
\r
1605 exclusive access to the ready lists as the scheduler is locked. */
\r
1606 vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
1609 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1611 if( xTicksToWait == portMAX_DELAY )
\r
1613 /* Add ourselves to the suspended task list instead of a delayed task
\r
1614 list to ensure we are not woken by a timing event. We will block
\r
1616 vListInsertEnd( ( xList * ) &xSuspendedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
1620 /* Calculate the time at which the task should be woken if the event does
\r
1621 not occur. This may overflow but this doesn't matter. */
\r
1622 xTimeToWake = xTickCount + xTicksToWait;
\r
1624 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
\r
1626 if( xTimeToWake < xTickCount )
\r
1628 /* Wake time has overflowed. Place this item in the overflow list. */
\r
1629 vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
1633 /* The wake time has not overflowed, so we can use the current block list. */
\r
1634 vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
1640 /* Calculate the time at which the task should be woken if the event does
\r
1641 not occur. This may overflow but this doesn't matter. */
\r
1642 xTimeToWake = xTickCount + xTicksToWait;
\r
1644 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
\r
1646 if( xTimeToWake < xTickCount )
\r
1648 /* Wake time has overflowed. Place this item in the overflow list. */
\r
1649 vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
1653 /* The wake time has not overflowed, so we can use the current block list. */
\r
1654 vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
1659 /*-----------------------------------------------------------*/
\r
1661 signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList )
\r
1663 tskTCB *pxUnblockedTCB;
\r
1664 portBASE_TYPE xReturn;
\r
1666 /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
\r
1667 SCHEDULER SUSPENDED. It can also be called from within an ISR. */
\r
1669 /* The event list is sorted in priority order, so we can remove the
\r
1670 first in the list, remove the TCB from the delayed list, and add
\r
1671 it to the ready list.
\r
1673 If an event is for a queue that is locked then this function will never
\r
1674 get called - the lock count on the queue will get modified instead. This
\r
1675 means we can always expect exclusive access to the event list here. */
\r
1676 pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
\r
1677 vListRemove( &( pxUnblockedTCB->xEventListItem ) );
\r
1679 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
1681 vListRemove( &( pxUnblockedTCB->xGenericListItem ) );
\r
1682 prvAddTaskToReadyQueue( pxUnblockedTCB );
\r
1686 /* We cannot access the delayed or ready lists, so will hold this
\r
1687 task pending until the scheduler is resumed. */
\r
1688 vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );
\r
1691 if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority )
\r
1693 /* Return true if the task removed from the event list has
\r
1694 a higher priority than the calling task. This allows
\r
1695 the calling task to know if it should force a context
\r
1701 xReturn = pdFALSE;
\r
1706 /*-----------------------------------------------------------*/
\r
1708 void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut )
\r
1710 pxTimeOut->xOverflowCount = xNumOfOverflows;
\r
1711 pxTimeOut->xTimeOnEntering = xTickCount;
\r
1713 /*-----------------------------------------------------------*/
\r
1715 portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait )
\r
1717 portBASE_TYPE xReturn;
\r
1719 portENTER_CRITICAL();
\r
1721 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1722 /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is
\r
1723 the maximum block time then the task should block indefinitely, and
\r
1724 therefore never time out. */
\r
1725 if( *pxTicksToWait == portMAX_DELAY )
\r
1727 xReturn = pdFALSE;
\r
1729 else /* We are not blocking indefinitely, perform the checks below. */
\r
1732 if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( ( portTickType ) xTickCount >= ( portTickType ) pxTimeOut->xTimeOnEntering ) )
\r
1734 /* The tick count is greater than the time at which vTaskSetTimeout()
\r
1735 was called, but has also overflowed since vTaskSetTimeOut() was called.
\r
1736 It must have wrapped all the way around and gone past us again. This
\r
1737 passed since vTaskSetTimeout() was called. */
\r
1740 else if( ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering ) < ( portTickType ) *pxTicksToWait )
\r
1742 /* Not a genuine timeout. Adjust parameters for time remaining. */
\r
1743 *pxTicksToWait -= ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering );
\r
1744 vTaskSetTimeOutState( pxTimeOut );
\r
1745 xReturn = pdFALSE;
\r
1752 portEXIT_CRITICAL();
\r
1756 /*-----------------------------------------------------------*/
\r
1758 void vTaskMissedYield( void )
\r
1760 xMissedYield = pdTRUE;
\r
1764 * -----------------------------------------------------------
\r
1766 * ----------------------------------------------------------
\r
1768 * The portTASK_FUNCTION() macro is used to allow port/compiler specific
\r
1769 * language extensions. The equivalent prototype for this function is:
\r
1771 * void prvIdleTask( void *pvParameters );
\r
1774 static portTASK_FUNCTION( prvIdleTask, pvParameters )
\r
1776 /* Stop warnings. */
\r
1777 ( void ) pvParameters;
\r
1781 /* See if any tasks have been deleted. */
\r
1782 prvCheckTasksWaitingTermination();
\r
1784 #if ( configUSE_PREEMPTION == 0 )
\r
1786 /* If we are not using preemption we keep forcing a task switch to
\r
1787 see if any other task has become available. If we are using
\r
1788 preemption we don't need to do this as any task becoming available
\r
1789 will automatically get the processor anyway. */
\r
1794 #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
\r
1796 /* When using preemption tasks of equal priority will be
\r
1797 timesliced. If a task that is sharing the idle priority is ready
\r
1798 to run then the idle task should yield before the end of the
\r
1801 A critical region is not required here as we are just reading from
\r
1802 the list, and an occasional incorrect value will not matter. If
\r
1803 the ready list at the idle priority contains more than one task
\r
1804 then a task other than the idle task is ready to execute. */
\r
1805 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( unsigned portBASE_TYPE ) 1 )
\r
1812 #if ( configUSE_IDLE_HOOK == 1 )
\r
1814 extern void vApplicationIdleHook( void );
\r
1816 /* Call the user defined function from within the idle task. This
\r
1817 allows the application designer to add background functionality
\r
1818 without the overhead of a separate task.
\r
1819 NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
\r
1820 CALL A FUNCTION THAT MIGHT BLOCK. */
\r
1821 vApplicationIdleHook();
\r
1825 } /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */
\r
1833 /*-----------------------------------------------------------
\r
1834 * File private functions documented at the top of the file.
\r
1835 *----------------------------------------------------------*/
\r
1839 static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed portCHAR * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned portSHORT usStackDepth )
\r
1841 /* Store the function name in the TCB. */
\r
1842 #if configMAX_TASK_NAME_LEN > 1
\r
1844 /* Don't bring strncpy into the build unnecessarily. */
\r
1845 strncpy( ( char * ) pxTCB->pcTaskName, ( const char * ) pcName, ( unsigned portSHORT ) configMAX_TASK_NAME_LEN );
\r
1848 pxTCB->pcTaskName[ ( unsigned portSHORT ) configMAX_TASK_NAME_LEN - ( unsigned portSHORT ) 1 ] = '\0';
\r
1850 /* This is used as an array index so must ensure it's not too large. First
\r
1851 remove the privilege bit if one is present. */
\r
1852 if( uxPriority >= configMAX_PRIORITIES )
\r
1854 uxPriority = configMAX_PRIORITIES - 1;
\r
1857 pxTCB->uxPriority = uxPriority;
\r
1858 #if ( configUSE_MUTEXES == 1 )
\r
1860 pxTCB->uxBasePriority = uxPriority;
\r
1864 vListInitialiseItem( &( pxTCB->xGenericListItem ) );
\r
1865 vListInitialiseItem( &( pxTCB->xEventListItem ) );
\r
1867 /* Set the pxTCB as a link back from the xListItem. This is so we can get
\r
1868 back to the containing TCB from a generic item in a list. */
\r
1869 listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB );
\r
1871 /* Event lists are always in priority order. */
\r
1872 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );
\r
1873 listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB );
\r
1875 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
\r
1877 pxTCB->uxCriticalNesting = ( unsigned portBASE_TYPE ) 0;
\r
1881 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
1883 pxTCB->pxTaskTag = NULL;
\r
1887 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
1889 pxTCB->ulRunTimeCounter = 0UL;
\r
1893 #if ( portUSING_MPU_WRAPPERS == 1 )
\r
1895 vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth );
\r
1899 ( void ) xRegions;
\r
1900 ( void ) usStackDepth;
\r
1904 /*-----------------------------------------------------------*/
\r
1906 #if ( portUSING_MPU_WRAPPERS == 1 )
\r
1908 void vTaskAllocateMPURegions( xTaskHandle xTaskToModify, const xMemoryRegion * const xRegions )
\r
1912 if( xTaskToModify == pxCurrentTCB )
\r
1914 xTaskToModify = NULL;
\r
1917 /* If null is passed in here then we are deleting ourselves. */
\r
1918 pxTCB = prvGetTCBFromHandle( xTaskToModify );
\r
1920 vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 );
\r
1922 /*-----------------------------------------------------------*/
\r
1925 static void prvInitialiseTaskLists( void )
\r
1927 unsigned portBASE_TYPE uxPriority;
\r
1929 for( uxPriority = 0; uxPriority < configMAX_PRIORITIES; uxPriority++ )
\r
1931 vListInitialise( ( xList * ) &( pxReadyTasksLists[ uxPriority ] ) );
\r
1934 vListInitialise( ( xList * ) &xDelayedTaskList1 );
\r
1935 vListInitialise( ( xList * ) &xDelayedTaskList2 );
\r
1936 vListInitialise( ( xList * ) &xPendingReadyList );
\r
1938 #if ( INCLUDE_vTaskDelete == 1 )
\r
1940 vListInitialise( ( xList * ) &xTasksWaitingTermination );
\r
1944 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1946 vListInitialise( ( xList * ) &xSuspendedTaskList );
\r
1950 /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
\r
1952 pxDelayedTaskList = &xDelayedTaskList1;
\r
1953 pxOverflowDelayedTaskList = &xDelayedTaskList2;
\r
1955 /*-----------------------------------------------------------*/
\r
1957 static void prvCheckTasksWaitingTermination( void )
\r
1959 #if ( INCLUDE_vTaskDelete == 1 )
\r
1961 portBASE_TYPE xListIsEmpty;
\r
1963 /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
\r
1964 too often in the idle task. */
\r
1965 if( uxTasksDeleted > ( unsigned portBASE_TYPE ) 0 )
\r
1967 vTaskSuspendAll();
\r
1968 xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
\r
1971 if( !xListIsEmpty )
\r
1975 portENTER_CRITICAL();
\r
1977 pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xTasksWaitingTermination ) );
\r
1978 vListRemove( &( pxTCB->xGenericListItem ) );
\r
1979 --uxCurrentNumberOfTasks;
\r
1982 portEXIT_CRITICAL();
\r
1984 prvDeleteTCB( pxTCB );
\r
1990 /*-----------------------------------------------------------*/
\r
1992 static tskTCB *prvAllocateTCBAndStack( unsigned portSHORT usStackDepth, portSTACK_TYPE *puxStackBuffer )
\r
1996 /* Allocate space for the TCB. Where the memory comes from depends on
\r
1997 the implementation of the port malloc function. */
\r
1998 pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) );
\r
2000 if( pxNewTCB != NULL )
\r
2002 /* Allocate space for the stack used by the task being created.
\r
2003 The base of the stack memory stored in the TCB so the task can
\r
2004 be deleted later if required. */
\r
2005 pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMallocAligned( ( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) ), puxStackBuffer );
\r
2007 if( pxNewTCB->pxStack == NULL )
\r
2009 /* Could not allocate the stack. Delete the allocated TCB. */
\r
2010 vPortFree( pxNewTCB );
\r
2015 /* Just to help debugging. */
\r
2016 memset( pxNewTCB->pxStack, tskSTACK_FILL_BYTE, usStackDepth * sizeof( portSTACK_TYPE ) );
\r
2022 /*-----------------------------------------------------------*/
\r
2024 #if ( configUSE_TRACE_FACILITY == 1 )
\r
2026 static void prvListTaskWithinSingleList( const signed portCHAR *pcWriteBuffer, xList *pxList, signed portCHAR cStatus )
\r
2028 volatile tskTCB *pxNextTCB, *pxFirstTCB;
\r
2029 unsigned portSHORT usStackRemaining;
\r
2031 /* Write the details of all the TCB's in pxList into the buffer. */
\r
2032 listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
\r
2035 listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
\r
2036 usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned portCHAR * ) pxNextTCB->pxStack );
\r
2037 sprintf( pcStatusString, ( portCHAR * ) "%s\t\t%c\t%u\t%u\t%u\r\n", pxNextTCB->pcTaskName, cStatus, ( unsigned int ) pxNextTCB->uxPriority, usStackRemaining, ( unsigned int ) pxNextTCB->uxTCBNumber );
\r
2038 strcat( ( portCHAR * ) pcWriteBuffer, ( portCHAR * ) pcStatusString );
\r
2040 } while( pxNextTCB != pxFirstTCB );
\r
2044 /*-----------------------------------------------------------*/
\r
2046 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
2048 static void prvGenerateRunTimeStatsForTasksInList( const signed portCHAR *pcWriteBuffer, xList *pxList, unsigned portLONG ulTotalRunTime )
\r
2050 volatile tskTCB *pxNextTCB, *pxFirstTCB;
\r
2051 unsigned portLONG ulStatsAsPercentage;
\r
2053 /* Write the run time stats of all the TCB's in pxList into the buffer. */
\r
2054 listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
\r
2057 /* Get next TCB in from the list. */
\r
2058 listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
\r
2060 /* Divide by zero check. */
\r
2061 if( ulTotalRunTime > 0UL )
\r
2063 /* Has the task run at all? */
\r
2064 if( pxNextTCB->ulRunTimeCounter == 0 )
\r
2066 /* The task has used no CPU time at all. */
\r
2067 sprintf( pcStatsString, ( portCHAR * ) "%s\t\t0\t\t0%%\r\n", pxNextTCB->pcTaskName );
\r
2071 /* What percentage of the total run time as the task used?
\r
2072 This will always be rounded down to the nearest integer. */
\r
2073 ulStatsAsPercentage = ( 100UL * pxNextTCB->ulRunTimeCounter ) / ulTotalRunTime;
\r
2075 if( ulStatsAsPercentage > 0UL )
\r
2077 sprintf( pcStatsString, ( portCHAR * ) "%s\t\t%u\t\t%u%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage );
\r
2081 /* If the percentage is zero here then the task has
\r
2082 consumed less than 1% of the total run time. */
\r
2083 sprintf( pcStatsString, ( portCHAR * ) "%s\t\t%u\t\t<1%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter );
\r
2087 strcat( ( portCHAR * ) pcWriteBuffer, ( portCHAR * ) pcStatsString );
\r
2090 } while( pxNextTCB != pxFirstTCB );
\r
2094 /*-----------------------------------------------------------*/
\r
2096 #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
\r
2098 static unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR * pucStackByte )
\r
2100 register unsigned portSHORT usCount = 0;
\r
2102 while( *pucStackByte == tskSTACK_FILL_BYTE )
\r
2104 pucStackByte -= portSTACK_GROWTH;
\r
2108 usCount /= sizeof( portSTACK_TYPE );
\r
2114 /*-----------------------------------------------------------*/
\r
2116 #if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )
\r
2118 unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask )
\r
2121 unsigned portCHAR *pcEndOfStack;
\r
2122 unsigned portBASE_TYPE uxReturn;
\r
2124 pxTCB = prvGetTCBFromHandle( xTask );
\r
2126 #if portSTACK_GROWTH < 0
\r
2128 pcEndOfStack = ( unsigned portCHAR * ) pxTCB->pxStack;
\r
2132 pcEndOfStack = ( unsigned portCHAR * ) pxTCB->pxEndOfStack;
\r
2136 uxReturn = ( unsigned portBASE_TYPE ) usTaskCheckFreeStackSpace( pcEndOfStack );
\r
2142 /*-----------------------------------------------------------*/
\r
2144 #if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
\r
2146 static void prvDeleteTCB( tskTCB *pxTCB )
\r
2148 /* Free up the memory allocated by the scheduler for the task. It is up to
\r
2149 the task to free any memory allocated at the application level. */
\r
2150 vPortFreeAligned( pxTCB->pxStack );
\r
2151 vPortFree( pxTCB );
\r
2157 /*-----------------------------------------------------------*/
\r
2159 #if ( INCLUDE_xTaskGetCurrentTaskHandle == 1 )
\r
2161 xTaskHandle xTaskGetCurrentTaskHandle( void )
\r
2163 xTaskHandle xReturn;
\r
2165 /* A critical section is not required as this is not called from
\r
2166 an interrupt and the current TCB will always be the same for any
\r
2167 individual execution thread. */
\r
2168 xReturn = pxCurrentTCB;
\r
2175 /*-----------------------------------------------------------*/
\r
2177 #if ( INCLUDE_xTaskGetSchedulerState == 1 )
\r
2179 portBASE_TYPE xTaskGetSchedulerState( void )
\r
2181 portBASE_TYPE xReturn;
\r
2183 if( xSchedulerRunning == pdFALSE )
\r
2185 xReturn = taskSCHEDULER_NOT_STARTED;
\r
2189 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
2191 xReturn = taskSCHEDULER_RUNNING;
\r
2195 xReturn = taskSCHEDULER_SUSPENDED;
\r
2203 /*-----------------------------------------------------------*/
\r
2205 #if ( configUSE_MUTEXES == 1 )
\r
2207 void vTaskPriorityInherit( xTaskHandle * const pxMutexHolder )
\r
2209 tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
\r
2211 if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )
\r
2213 /* Adjust the mutex holder state to account for its new priority. */
\r
2214 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxCurrentTCB->uxPriority );
\r
2216 /* If the task being modified is in the ready state it will need to
\r
2217 be moved in to a new list. */
\r
2218 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) )
\r
2220 vListRemove( &( pxTCB->xGenericListItem ) );
\r
2222 /* Inherit the priority before being moved into the new list. */
\r
2223 pxTCB->uxPriority = pxCurrentTCB->uxPriority;
\r
2224 prvAddTaskToReadyQueue( pxTCB );
\r
2228 /* Just inherit the priority. */
\r
2229 pxTCB->uxPriority = pxCurrentTCB->uxPriority;
\r
2235 /*-----------------------------------------------------------*/
\r
2237 #if ( configUSE_MUTEXES == 1 )
\r
2239 void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder )
\r
2241 tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
\r
2243 if( pxMutexHolder != NULL )
\r
2245 if( pxTCB->uxPriority != pxTCB->uxBasePriority )
\r
2247 /* We must be the running task to be able to give the mutex back.
\r
2248 Remove ourselves from the ready list we currently appear in. */
\r
2249 vListRemove( &( pxTCB->xGenericListItem ) );
\r
2251 /* Disinherit the priority before adding ourselves into the new
\r
2253 pxTCB->uxPriority = pxTCB->uxBasePriority;
\r
2254 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxTCB->uxPriority );
\r
2255 prvAddTaskToReadyQueue( pxTCB );
\r
2261 /*-----------------------------------------------------------*/
\r
2263 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
\r
2265 void vTaskEnterCritical( void )
\r
2267 portDISABLE_INTERRUPTS();
\r
2269 if( xSchedulerRunning != pdFALSE )
\r
2271 pxCurrentTCB->uxCriticalNesting++;
\r
2276 /*-----------------------------------------------------------*/
\r
2278 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
\r
2280 void vTaskExitCritical( void )
\r
2282 if( xSchedulerRunning != pdFALSE )
\r
2284 if( pxCurrentTCB->uxCriticalNesting > 0 )
\r
2286 pxCurrentTCB->uxCriticalNesting--;
\r
2288 if( pxCurrentTCB->uxCriticalNesting == 0 )
\r
2290 portENABLE_INTERRUPTS();
\r
2297 /*-----------------------------------------------------------*/
\r