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 PRIVILEGED_DATA 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 ) - ( ( usStackDepth - 1 ) % portBYTE_ALIGNMENT );
\r
417 pxTopOfStack = pxNewTCB->pxStack;
\r
419 /* If we want to use stack checking on architectures that use
\r
420 a positive stack growth direction then we also need to store the
\r
421 other extreme of the stack space. */
\r
422 pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
\r
426 /* Setup the newly allocated TCB with the initial state of the task. */
\r
427 prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth );
\r
429 /* Initialize the TCB stack to look as if the task was already running,
\r
430 but had been interrupted by the scheduler. The return address is set
\r
431 to the start of the task function. Once the stack has been initialised
\r
432 the top of stack variable is updated. */
\r
433 #if( portUSING_MPU_WRAPPERS == 1 )
\r
435 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
\r
439 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
\r
440 ( void ) xRunPrivileged;
\r
444 /* We are going to manipulate the task queues to add this task to a
\r
445 ready list, so must make sure no interrupts occur. */
\r
446 portENTER_CRITICAL();
\r
448 uxCurrentNumberOfTasks++;
\r
449 if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )
\r
451 /* As this is the first task it must also be the current task. */
\r
452 pxCurrentTCB = pxNewTCB;
\r
454 /* This is the first task to be created so do the preliminary
\r
455 initialisation required. We will not recover if this call
\r
456 fails, but we will report the failure. */
\r
457 prvInitialiseTaskLists();
\r
461 /* If the scheduler is not already running, make this task the
\r
462 current task if it is the highest priority task to be created
\r
464 if( xSchedulerRunning == pdFALSE )
\r
466 if( pxCurrentTCB->uxPriority <= uxPriority )
\r
468 pxCurrentTCB = pxNewTCB;
\r
473 /* Remember the top priority to make context switching faster. Use
\r
474 the priority in pxNewTCB as this has been capped to a valid value. */
\r
475 if( pxNewTCB->uxPriority > uxTopUsedPriority )
\r
477 uxTopUsedPriority = pxNewTCB->uxPriority;
\r
480 #if ( configUSE_TRACE_FACILITY == 1 )
\r
482 /* Add a counter into the TCB for tracing only. */
\r
483 pxNewTCB->uxTCBNumber = uxTaskNumber;
\r
488 prvAddTaskToReadyQueue( pxNewTCB );
\r
491 traceTASK_CREATE( pxNewTCB );
\r
493 portEXIT_CRITICAL();
\r
497 xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
\r
498 traceTASK_CREATE_FAILED( pxNewTCB );
\r
501 if( xReturn == pdPASS )
\r
503 if( ( void * ) pxCreatedTask != NULL )
\r
505 /* Pass the TCB out - in an anonymous way. The calling function/
\r
506 task can use this as a handle to delete the task later if
\r
508 *pxCreatedTask = ( xTaskHandle ) pxNewTCB;
\r
511 if( xSchedulerRunning != pdFALSE )
\r
513 /* If the created task is of a higher priority than the current task
\r
514 then it should run now. */
\r
515 if( pxCurrentTCB->uxPriority < uxPriority )
\r
517 portYIELD_WITHIN_API();
\r
524 /*-----------------------------------------------------------*/
\r
526 #if ( INCLUDE_vTaskDelete == 1 )
\r
528 void vTaskDelete( xTaskHandle pxTaskToDelete )
\r
532 portENTER_CRITICAL();
\r
534 /* Ensure a yield is performed if the current task is being
\r
536 if( pxTaskToDelete == pxCurrentTCB )
\r
538 pxTaskToDelete = NULL;
\r
541 /* If null is passed in here then we are deleting ourselves. */
\r
542 pxTCB = prvGetTCBFromHandle( pxTaskToDelete );
\r
544 /* Remove task from the ready list and place in the termination list.
\r
545 This will stop the task from be scheduled. The idle task will check
\r
546 the termination list and free up any memory allocated by the
\r
547 scheduler for the TCB and stack. */
\r
548 vListRemove( &( pxTCB->xGenericListItem ) );
\r
550 /* Is the task waiting on an event also? */
\r
551 if( pxTCB->xEventListItem.pvContainer )
\r
553 vListRemove( &( pxTCB->xEventListItem ) );
\r
556 vListInsertEnd( ( xList * ) &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );
\r
558 /* Increment the ucTasksDeleted variable so the idle task knows
\r
559 there is a task that has been deleted and that it should therefore
\r
560 check the xTasksWaitingTermination list. */
\r
563 /* Increment the uxTaskNumberVariable also so kernel aware debuggers
\r
564 can detect that the task lists need re-generating. */
\r
567 traceTASK_DELETE( pxTCB );
\r
569 portEXIT_CRITICAL();
\r
571 /* Force a reschedule if we have just deleted the current task. */
\r
572 if( xSchedulerRunning != pdFALSE )
\r
574 if( ( void * ) pxTaskToDelete == NULL )
\r
576 portYIELD_WITHIN_API();
\r
588 /*-----------------------------------------------------------
\r
589 * TASK CONTROL API documented in task.h
\r
590 *----------------------------------------------------------*/
\r
592 #if ( INCLUDE_vTaskDelayUntil == 1 )
\r
594 void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement )
\r
596 portTickType xTimeToWake;
\r
597 portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE;
\r
601 /* Generate the tick time at which the task wants to wake. */
\r
602 xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
\r
604 if( xTickCount < *pxPreviousWakeTime )
\r
606 /* The tick count has overflowed since this function was
\r
607 lasted called. In this case the only time we should ever
\r
608 actually delay is if the wake time has also overflowed,
\r
609 and the wake time is greater than the tick time. When this
\r
610 is the case it is as if neither time had overflowed. */
\r
611 if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xTickCount ) )
\r
613 xShouldDelay = pdTRUE;
\r
618 /* The tick time has not overflowed. In this case we will
\r
619 delay if either the wake time has overflowed, and/or the
\r
620 tick time is less than the wake time. */
\r
621 if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xTickCount ) )
\r
623 xShouldDelay = pdTRUE;
\r
627 /* Update the wake time ready for the next call. */
\r
628 *pxPreviousWakeTime = xTimeToWake;
\r
632 traceTASK_DELAY_UNTIL();
\r
634 /* We must remove ourselves from the ready list before adding
\r
635 ourselves to the blocked list as the same list item is used for
\r
637 vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
639 /* The list item will be inserted in wake time order. */
\r
640 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
\r
642 if( xTimeToWake < xTickCount )
\r
644 /* Wake time has overflowed. Place this item in the
\r
646 vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
650 /* The wake time has not overflowed, so we can use the
\r
651 current block list. */
\r
652 vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
656 xAlreadyYielded = xTaskResumeAll();
\r
658 /* Force a reschedule if xTaskResumeAll has not already done so, we may
\r
659 have put ourselves to sleep. */
\r
660 if( !xAlreadyYielded )
\r
662 portYIELD_WITHIN_API();
\r
667 /*-----------------------------------------------------------*/
\r
669 #if ( INCLUDE_vTaskDelay == 1 )
\r
671 void vTaskDelay( portTickType xTicksToDelay )
\r
673 portTickType xTimeToWake;
\r
674 signed portBASE_TYPE xAlreadyYielded = pdFALSE;
\r
676 /* A delay time of zero just forces a reschedule. */
\r
677 if( xTicksToDelay > ( portTickType ) 0 )
\r
683 /* A task that is removed from the event list while the
\r
684 scheduler is suspended will not get placed in the ready
\r
685 list or removed from the blocked list until the scheduler
\r
688 This task cannot be in an event list as it is the currently
\r
691 /* Calculate the time to wake - this may overflow but this is
\r
693 xTimeToWake = xTickCount + xTicksToDelay;
\r
695 /* We must remove ourselves from the ready list before adding
\r
696 ourselves to the blocked list as the same list item is used for
\r
698 vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
700 /* The list item will be inserted in wake time order. */
\r
701 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
\r
703 if( xTimeToWake < xTickCount )
\r
705 /* Wake time has overflowed. Place this item in the
\r
707 vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
711 /* The wake time has not overflowed, so we can use the
\r
712 current block list. */
\r
713 vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
716 xAlreadyYielded = xTaskResumeAll();
\r
719 /* Force a reschedule if xTaskResumeAll has not already done so, we may
\r
720 have put ourselves to sleep. */
\r
721 if( !xAlreadyYielded )
\r
723 portYIELD_WITHIN_API();
\r
728 /*-----------------------------------------------------------*/
\r
730 #if ( INCLUDE_uxTaskPriorityGet == 1 )
\r
732 unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask )
\r
735 unsigned portBASE_TYPE uxReturn;
\r
737 portENTER_CRITICAL();
\r
739 /* If null is passed in here then we are changing the
\r
740 priority of the calling function. */
\r
741 pxTCB = prvGetTCBFromHandle( pxTask );
\r
742 uxReturn = pxTCB->uxPriority;
\r
744 portEXIT_CRITICAL();
\r
750 /*-----------------------------------------------------------*/
\r
752 #if ( INCLUDE_vTaskPrioritySet == 1 )
\r
754 void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority )
\r
757 unsigned portBASE_TYPE uxCurrentPriority, xYieldRequired = pdFALSE;
\r
759 /* Ensure the new priority is valid. */
\r
760 if( uxNewPriority >= configMAX_PRIORITIES )
\r
762 uxNewPriority = configMAX_PRIORITIES - 1;
\r
765 portENTER_CRITICAL();
\r
767 if( pxTask == pxCurrentTCB )
\r
772 /* If null is passed in here then we are changing the
\r
773 priority of the calling function. */
\r
774 pxTCB = prvGetTCBFromHandle( pxTask );
\r
776 traceTASK_PRIORITY_SET( pxTask, uxNewPriority );
\r
778 #if ( configUSE_MUTEXES == 1 )
\r
780 uxCurrentPriority = pxTCB->uxBasePriority;
\r
784 uxCurrentPriority = pxTCB->uxPriority;
\r
788 if( uxCurrentPriority != uxNewPriority )
\r
790 /* The priority change may have readied a task of higher
\r
791 priority than the calling task. */
\r
792 if( uxNewPriority > uxCurrentPriority )
\r
794 if( pxTask != NULL )
\r
796 /* The priority of another task is being raised. If we
\r
797 were raising the priority of the currently running task
\r
798 there would be no need to switch as it must have already
\r
799 been the highest priority task. */
\r
800 xYieldRequired = pdTRUE;
\r
803 else if( pxTask == NULL )
\r
805 /* Setting our own priority down means there may now be another
\r
806 task of higher priority that is ready to execute. */
\r
807 xYieldRequired = pdTRUE;
\r
812 #if ( configUSE_MUTEXES == 1 )
\r
814 /* Only change the priority being used if the task is not
\r
815 currently using an inherited priority. */
\r
816 if( pxTCB->uxBasePriority == pxTCB->uxPriority )
\r
818 pxTCB->uxPriority = uxNewPriority;
\r
821 /* The base priority gets set whatever. */
\r
822 pxTCB->uxBasePriority = uxNewPriority;
\r
826 pxTCB->uxPriority = uxNewPriority;
\r
830 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( configMAX_PRIORITIES - ( portTickType ) uxNewPriority ) );
\r
832 /* If the task is in the blocked or suspended list we need do
\r
833 nothing more than change it's priority variable. However, if
\r
834 the task is in a ready list it needs to be removed and placed
\r
835 in the queue appropriate to its new priority. */
\r
836 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxCurrentPriority ] ), &( pxTCB->xGenericListItem ) ) )
\r
838 /* The task is currently in its ready list - remove before adding
\r
839 it to it's new ready list. As we are in a critical section we
\r
840 can do this even if the scheduler is suspended. */
\r
841 vListRemove( &( pxTCB->xGenericListItem ) );
\r
842 prvAddTaskToReadyQueue( pxTCB );
\r
845 if( xYieldRequired == pdTRUE )
\r
847 portYIELD_WITHIN_API();
\r
851 portEXIT_CRITICAL();
\r
855 /*-----------------------------------------------------------*/
\r
857 #if ( INCLUDE_vTaskSuspend == 1 )
\r
859 void vTaskSuspend( xTaskHandle pxTaskToSuspend )
\r
863 portENTER_CRITICAL();
\r
865 /* Ensure a yield is performed if the current task is being
\r
867 if( pxTaskToSuspend == pxCurrentTCB )
\r
869 pxTaskToSuspend = NULL;
\r
872 /* If null is passed in here then we are suspending ourselves. */
\r
873 pxTCB = prvGetTCBFromHandle( pxTaskToSuspend );
\r
875 traceTASK_SUSPEND( pxTCB );
\r
877 /* Remove task from the ready/delayed list and place in the suspended list. */
\r
878 vListRemove( &( pxTCB->xGenericListItem ) );
\r
880 /* Is the task waiting on an event also? */
\r
881 if( pxTCB->xEventListItem.pvContainer )
\r
883 vListRemove( &( pxTCB->xEventListItem ) );
\r
886 vListInsertEnd( ( xList * ) &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );
\r
888 portEXIT_CRITICAL();
\r
890 /* We may have just suspended the current task. */
\r
891 if( ( void * ) pxTaskToSuspend == NULL )
\r
893 portYIELD_WITHIN_API();
\r
898 /*-----------------------------------------------------------*/
\r
900 #if ( INCLUDE_vTaskSuspend == 1 )
\r
902 signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask )
\r
904 portBASE_TYPE xReturn = pdFALSE;
\r
905 const tskTCB * const pxTCB = ( tskTCB * ) xTask;
\r
907 /* Is the task we are attempting to resume actually in the
\r
909 if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE )
\r
911 /* Has the task already been resumed from within an ISR? */
\r
912 if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) != pdTRUE )
\r
914 /* Is it in the suspended list because it is in the
\r
915 Suspended state? It is possible to be in the suspended
\r
916 list because it is blocked on a task with no timeout
\r
918 if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) == pdTRUE )
\r
929 /*-----------------------------------------------------------*/
\r
931 #if ( INCLUDE_vTaskSuspend == 1 )
\r
933 void vTaskResume( xTaskHandle pxTaskToResume )
\r
937 /* Remove the task from whichever list it is currently in, and place
\r
938 it in the ready list. */
\r
939 pxTCB = ( tskTCB * ) pxTaskToResume;
\r
941 /* The parameter cannot be NULL as it is impossible to resume the
\r
942 currently executing task. */
\r
943 if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
\r
945 portENTER_CRITICAL();
\r
947 if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
\r
949 traceTASK_RESUME( pxTCB );
\r
951 /* As we are in a critical section we can access the ready
\r
952 lists even if the scheduler is suspended. */
\r
953 vListRemove( &( pxTCB->xGenericListItem ) );
\r
954 prvAddTaskToReadyQueue( pxTCB );
\r
956 /* We may have just resumed a higher priority task. */
\r
957 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
\r
959 /* This yield may not cause the task just resumed to run, but
\r
960 will leave the lists in the correct state for the next yield. */
\r
961 portYIELD_WITHIN_API();
\r
965 portEXIT_CRITICAL();
\r
971 /*-----------------------------------------------------------*/
\r
973 #if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
\r
975 portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume )
\r
977 portBASE_TYPE xYieldRequired = pdFALSE;
\r
980 pxTCB = ( tskTCB * ) pxTaskToResume;
\r
982 if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
\r
984 traceTASK_RESUME_FROM_ISR( pxTCB );
\r
986 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
988 xYieldRequired = ( pxTCB->uxPriority >= pxCurrentTCB->uxPriority );
\r
989 vListRemove( &( pxTCB->xGenericListItem ) );
\r
990 prvAddTaskToReadyQueue( pxTCB );
\r
994 /* We cannot access the delayed or ready lists, so will hold this
\r
995 task pending until the scheduler is resumed, at which point a
\r
996 yield will be performed if necessary. */
\r
997 vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
\r
1001 return xYieldRequired;
\r
1009 /*-----------------------------------------------------------
\r
1010 * PUBLIC SCHEDULER CONTROL documented in task.h
\r
1011 *----------------------------------------------------------*/
\r
1014 void vTaskStartScheduler( void )
\r
1016 portBASE_TYPE xReturn;
\r
1018 /* Add the idle task at the lowest priority. */
\r
1019 xReturn = xTaskCreate( prvIdleTask, ( signed portCHAR * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), ( xTaskHandle * ) NULL );
\r
1021 if( xReturn == pdPASS )
\r
1023 /* Interrupts are turned off here, to ensure a tick does not occur
\r
1024 before or during the call to xPortStartScheduler(). The stacks of
\r
1025 the created tasks contain a status word with interrupts switched on
\r
1026 so interrupts will automatically get re-enabled when the first task
\r
1029 STEPPING THROUGH HERE USING A DEBUGGER CAN CAUSE BIG PROBLEMS IF THE
\r
1030 DEBUGGER ALLOWS INTERRUPTS TO BE PROCESSED. */
\r
1031 portDISABLE_INTERRUPTS();
\r
1033 xSchedulerRunning = pdTRUE;
\r
1034 xTickCount = ( portTickType ) 0;
\r
1036 /* If configGENERATE_RUN_TIME_STATS is defined then the following
\r
1037 macro must be defined to configure the timer/counter used to generate
\r
1038 the run time counter time base. */
\r
1039 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();
\r
1041 /* Setting up the timer tick is hardware specific and thus in the
\r
1042 portable interface. */
\r
1043 if( xPortStartScheduler() )
\r
1045 /* Should not reach here as if the scheduler is running the
\r
1046 function will not return. */
\r
1050 /* Should only reach here if a task calls xTaskEndScheduler(). */
\r
1054 /*-----------------------------------------------------------*/
\r
1056 void vTaskEndScheduler( void )
\r
1058 /* Stop the scheduler interrupts and call the portable scheduler end
\r
1059 routine so the original ISRs can be restored if necessary. The port
\r
1060 layer must ensure interrupts enable bit is left in the correct state. */
\r
1061 portDISABLE_INTERRUPTS();
\r
1062 xSchedulerRunning = pdFALSE;
\r
1063 vPortEndScheduler();
\r
1065 /*----------------------------------------------------------*/
\r
1067 void vTaskSuspendAll( void )
\r
1069 /* A critical section is not required as the variable is of type
\r
1071 ++uxSchedulerSuspended;
\r
1073 /*----------------------------------------------------------*/
\r
1075 signed portBASE_TYPE xTaskResumeAll( void )
\r
1077 register tskTCB *pxTCB;
\r
1078 signed portBASE_TYPE xAlreadyYielded = pdFALSE;
\r
1080 /* It is possible that an ISR caused a task to be removed from an event
\r
1081 list while the scheduler was suspended. If this was the case then the
\r
1082 removed task will have been added to the xPendingReadyList. Once the
\r
1083 scheduler has been resumed it is safe to move all the pending ready
\r
1084 tasks from this list into their appropriate ready list. */
\r
1085 portENTER_CRITICAL();
\r
1087 --uxSchedulerSuspended;
\r
1089 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
1091 if( uxCurrentNumberOfTasks > ( unsigned portBASE_TYPE ) 0 )
\r
1093 portBASE_TYPE xYieldRequired = pdFALSE;
\r
1095 /* Move any readied tasks from the pending list into the
\r
1096 appropriate ready list. */
\r
1097 while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xPendingReadyList ) ) ) != NULL )
\r
1099 vListRemove( &( pxTCB->xEventListItem ) );
\r
1100 vListRemove( &( pxTCB->xGenericListItem ) );
\r
1101 prvAddTaskToReadyQueue( pxTCB );
\r
1103 /* If we have moved a task that has a priority higher than
\r
1104 the current task then we should yield. */
\r
1105 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
\r
1107 xYieldRequired = pdTRUE;
\r
1111 /* If any ticks occurred while the scheduler was suspended then
\r
1112 they should be processed now. This ensures the tick count does not
\r
1113 slip, and that any delayed tasks are resumed at the correct time. */
\r
1114 if( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
\r
1116 while( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
\r
1118 vTaskIncrementTick();
\r
1122 /* As we have processed some ticks it is appropriate to yield
\r
1123 to ensure the highest priority task that is ready to run is
\r
1124 the task actually running. */
\r
1125 #if configUSE_PREEMPTION == 1
\r
1127 xYieldRequired = pdTRUE;
\r
1132 if( ( xYieldRequired == pdTRUE ) || ( xMissedYield == pdTRUE ) )
\r
1134 xAlreadyYielded = pdTRUE;
\r
1135 xMissedYield = pdFALSE;
\r
1136 portYIELD_WITHIN_API();
\r
1141 portEXIT_CRITICAL();
\r
1143 return xAlreadyYielded;
\r
1151 /*-----------------------------------------------------------
\r
1152 * PUBLIC TASK UTILITIES documented in task.h
\r
1153 *----------------------------------------------------------*/
\r
1157 portTickType xTaskGetTickCount( void )
\r
1159 portTickType xTicks;
\r
1161 /* Critical section required if running on a 16 bit processor. */
\r
1162 portENTER_CRITICAL();
\r
1164 xTicks = xTickCount;
\r
1166 portEXIT_CRITICAL();
\r
1170 /*-----------------------------------------------------------*/
\r
1172 unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void )
\r
1174 /* A critical section is not required because the variables are of type
\r
1176 return uxCurrentNumberOfTasks;
\r
1178 /*-----------------------------------------------------------*/
\r
1180 #if ( configUSE_TRACE_FACILITY == 1 )
\r
1182 void vTaskList( signed portCHAR *pcWriteBuffer )
\r
1184 unsigned portBASE_TYPE uxQueue;
\r
1186 /* This is a VERY costly function that should be used for debug only.
\r
1187 It leaves interrupts disabled for a LONG time. */
\r
1189 vTaskSuspendAll();
\r
1191 /* Run through all the lists that could potentially contain a TCB and
\r
1192 report the task name, state and stack high water mark. */
\r
1194 pcWriteBuffer[ 0 ] = ( signed portCHAR ) 0x00;
\r
1195 strcat( ( portCHAR * ) pcWriteBuffer, ( const portCHAR * ) "\r\n" );
\r
1197 uxQueue = uxTopUsedPriority + 1;
\r
1203 if( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) )
\r
1205 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), tskREADY_CHAR );
\r
1207 }while( uxQueue > ( unsigned portSHORT ) tskIDLE_PRIORITY );
\r
1209 if( !listLIST_IS_EMPTY( pxDelayedTaskList ) )
\r
1211 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, tskBLOCKED_CHAR );
\r
1214 if( !listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) )
\r
1216 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, tskBLOCKED_CHAR );
\r
1219 #if( INCLUDE_vTaskDelete == 1 )
\r
1221 if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) )
\r
1223 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, tskDELETED_CHAR );
\r
1228 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1230 if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
\r
1232 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, tskSUSPENDED_CHAR );
\r
1241 /*----------------------------------------------------------*/
\r
1243 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
1245 void vTaskGetRunTimeStats( signed portCHAR *pcWriteBuffer )
\r
1247 unsigned portBASE_TYPE uxQueue;
\r
1248 unsigned portLONG ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
\r
1250 /* This is a VERY costly function that should be used for debug only.
\r
1251 It leaves interrupts disabled for a LONG time. */
\r
1253 vTaskSuspendAll();
\r
1255 /* Run through all the lists that could potentially contain a TCB,
\r
1256 generating a table of run timer percentages in the provided
\r
1259 pcWriteBuffer[ 0 ] = ( signed portCHAR ) 0x00;
\r
1260 strcat( ( portCHAR * ) pcWriteBuffer, ( const portCHAR * ) "\r\n" );
\r
1262 uxQueue = uxTopUsedPriority + 1;
\r
1268 if( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) )
\r
1270 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), ulTotalRunTime );
\r
1272 }while( uxQueue > ( unsigned portSHORT ) tskIDLE_PRIORITY );
\r
1274 if( !listLIST_IS_EMPTY( pxDelayedTaskList ) )
\r
1276 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, ulTotalRunTime );
\r
1279 if( !listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) )
\r
1281 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, ulTotalRunTime );
\r
1284 #if ( INCLUDE_vTaskDelete == 1 )
\r
1286 if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) )
\r
1288 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, ulTotalRunTime );
\r
1293 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1295 if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
\r
1297 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, ulTotalRunTime );
\r
1306 /*----------------------------------------------------------*/
\r
1308 #if ( configUSE_TRACE_FACILITY == 1 )
\r
1310 void vTaskStartTrace( signed portCHAR * pcBuffer, unsigned portLONG ulBufferSize )
\r
1312 portENTER_CRITICAL();
\r
1314 pcTraceBuffer = ( signed portCHAR * )pcBuffer;
\r
1315 pcTraceBufferStart = pcBuffer;
\r
1316 pcTraceBufferEnd = pcBuffer + ( ulBufferSize - tskSIZE_OF_EACH_TRACE_LINE );
\r
1317 xTracing = pdTRUE;
\r
1319 portEXIT_CRITICAL();
\r
1323 /*----------------------------------------------------------*/
\r
1325 #if ( configUSE_TRACE_FACILITY == 1 )
\r
1327 unsigned portLONG ulTaskEndTrace( void )
\r
1329 unsigned portLONG ulBufferLength;
\r
1331 portENTER_CRITICAL();
\r
1332 xTracing = pdFALSE;
\r
1333 portEXIT_CRITICAL();
\r
1335 ulBufferLength = ( unsigned portLONG ) ( pcTraceBuffer - pcTraceBufferStart );
\r
1337 return ulBufferLength;
\r
1344 /*-----------------------------------------------------------
\r
1345 * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES
\r
1346 * documented in task.h
\r
1347 *----------------------------------------------------------*/
\r
1350 void vTaskIncrementTick( void )
\r
1352 /* Called by the portable layer each time a tick interrupt occurs.
\r
1353 Increments the tick then checks to see if the new tick value will cause any
\r
1354 tasks to be unblocked. */
\r
1355 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
1358 if( xTickCount == ( portTickType ) 0 )
\r
1362 /* Tick count has overflowed so we need to swap the delay lists.
\r
1363 If there are any items in pxDelayedTaskList here then there is
\r
1365 pxTemp = pxDelayedTaskList;
\r
1366 pxDelayedTaskList = pxOverflowDelayedTaskList;
\r
1367 pxOverflowDelayedTaskList = pxTemp;
\r
1368 xNumOfOverflows++;
\r
1371 /* See if this tick has made a timeout expire. */
\r
1372 prvCheckDelayedTasks();
\r
1378 /* The tick hook gets called at regular intervals, even if the
\r
1379 scheduler is locked. */
\r
1380 #if ( configUSE_TICK_HOOK == 1 )
\r
1382 extern void vApplicationTickHook( void );
\r
1384 vApplicationTickHook();
\r
1389 #if ( configUSE_TICK_HOOK == 1 )
\r
1391 extern void vApplicationTickHook( void );
\r
1393 /* Guard against the tick hook being called when the missed tick
\r
1394 count is being unwound (when the scheduler is being unlocked. */
\r
1395 if( uxMissedTicks == 0 )
\r
1397 vApplicationTickHook();
\r
1402 traceTASK_INCREMENT_TICK( xTickCount );
\r
1404 /*-----------------------------------------------------------*/
\r
1406 #if ( ( INCLUDE_vTaskCleanUpResources == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
\r
1408 void vTaskCleanUpResources( void )
\r
1410 unsigned portSHORT usQueue;
\r
1411 volatile tskTCB *pxTCB;
\r
1413 usQueue = ( unsigned portSHORT ) uxTopUsedPriority + ( unsigned portSHORT ) 1;
\r
1415 /* Remove any TCB's from the ready queues. */
\r
1420 while( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ usQueue ] ) ) )
\r
1422 listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &( pxReadyTasksLists[ usQueue ] ) );
\r
1423 vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
\r
1425 prvDeleteTCB( ( tskTCB * ) pxTCB );
\r
1427 }while( usQueue > ( unsigned portSHORT ) tskIDLE_PRIORITY );
\r
1429 /* Remove any TCB's from the delayed queue. */
\r
1430 while( !listLIST_IS_EMPTY( &xDelayedTaskList1 ) )
\r
1432 listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList1 );
\r
1433 vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
\r
1435 prvDeleteTCB( ( tskTCB * ) pxTCB );
\r
1438 /* Remove any TCB's from the overflow delayed queue. */
\r
1439 while( !listLIST_IS_EMPTY( &xDelayedTaskList2 ) )
\r
1441 listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList2 );
\r
1442 vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
\r
1444 prvDeleteTCB( ( tskTCB * ) pxTCB );
\r
1447 while( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
\r
1449 listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xSuspendedTaskList );
\r
1450 vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
\r
1452 prvDeleteTCB( ( tskTCB * ) pxTCB );
\r
1457 /*-----------------------------------------------------------*/
\r
1459 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
1461 void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxTagValue )
\r
1465 /* If xTask is NULL then we are setting our own task hook. */
\r
1466 if( xTask == NULL )
\r
1468 xTCB = ( tskTCB * ) pxCurrentTCB;
\r
1472 xTCB = ( tskTCB * ) xTask;
\r
1475 /* Save the hook function in the TCB. A critical section is required as
\r
1476 the value can be accessed from an interrupt. */
\r
1477 portENTER_CRITICAL();
\r
1478 xTCB->pxTaskTag = pxTagValue;
\r
1479 portEXIT_CRITICAL();
\r
1483 /*-----------------------------------------------------------*/
\r
1485 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
1487 pdTASK_HOOK_CODE xTaskGetApplicationTaskTag( xTaskHandle xTask )
\r
1490 pdTASK_HOOK_CODE xReturn;
\r
1492 /* If xTask is NULL then we are setting our own task hook. */
\r
1493 if( xTask == NULL )
\r
1495 xTCB = ( tskTCB * ) pxCurrentTCB;
\r
1499 xTCB = ( tskTCB * ) xTask;
\r
1502 /* Save the hook function in the TCB. A critical section is required as
\r
1503 the value can be accessed from an interrupt. */
\r
1504 portENTER_CRITICAL();
\r
1505 xReturn = xTCB->pxTaskTag;
\r
1506 portEXIT_CRITICAL();
\r
1512 /*-----------------------------------------------------------*/
\r
1514 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
1516 portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParameter )
\r
1519 portBASE_TYPE xReturn;
\r
1521 /* If xTask is NULL then we are calling our own task hook. */
\r
1522 if( xTask == NULL )
\r
1524 xTCB = ( tskTCB * ) pxCurrentTCB;
\r
1528 xTCB = ( tskTCB * ) xTask;
\r
1531 if( xTCB->pxTaskTag != NULL )
\r
1533 xReturn = xTCB->pxTaskTag( pvParameter );
\r
1544 /*-----------------------------------------------------------*/
\r
1546 void vTaskSwitchContext( void )
\r
1548 if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )
\r
1550 /* The scheduler is currently suspended - do not allow a context
\r
1552 xMissedYield = pdTRUE;
\r
1556 traceTASK_SWITCHED_OUT();
\r
1558 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
1560 unsigned portLONG ulTempCounter = portGET_RUN_TIME_COUNTER_VALUE();
\r
1562 /* Add the amount of time the task has been running to the accumulated
\r
1563 time so far. The time the task started running was stored in
\r
1564 ulTaskSwitchedInTime. Note that there is no overflow protection here
\r
1565 so count values are only valid until the timer overflows. Generally
\r
1566 this will be about 1 hour assuming a 1uS timer increment. */
\r
1567 pxCurrentTCB->ulRunTimeCounter += ( ulTempCounter - ulTaskSwitchedInTime );
\r
1568 ulTaskSwitchedInTime = ulTempCounter;
\r
1572 taskFIRST_CHECK_FOR_STACK_OVERFLOW();
\r
1573 taskSECOND_CHECK_FOR_STACK_OVERFLOW();
\r
1575 /* Find the highest priority queue that contains ready tasks. */
\r
1576 while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) )
\r
1578 --uxTopReadyPriority;
\r
1581 /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the tasks of the
\r
1582 same priority get an equal share of the processor time. */
\r
1583 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) );
\r
1585 traceTASK_SWITCHED_IN();
\r
1586 vWriteTraceToBuffer();
\r
1588 /*-----------------------------------------------------------*/
\r
1590 void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait )
\r
1592 portTickType xTimeToWake;
\r
1594 /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
\r
1595 SCHEDULER SUSPENDED. */
\r
1597 /* Place the event list item of the TCB in the appropriate event list.
\r
1598 This is placed in the list in priority order so the highest priority task
\r
1599 is the first to be woken by the event. */
\r
1600 vListInsert( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );
\r
1602 /* We must remove ourselves from the ready list before adding ourselves
\r
1603 to the blocked list as the same list item is used for both lists. We have
\r
1604 exclusive access to the ready lists as the scheduler is locked. */
\r
1605 vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
1608 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1610 if( xTicksToWait == portMAX_DELAY )
\r
1612 /* Add ourselves to the suspended task list instead of a delayed task
\r
1613 list to ensure we are not woken by a timing event. We will block
\r
1615 vListInsertEnd( ( xList * ) &xSuspendedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
1619 /* Calculate the time at which the task should be woken if the event does
\r
1620 not occur. This may overflow but this doesn't matter. */
\r
1621 xTimeToWake = xTickCount + xTicksToWait;
\r
1623 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
\r
1625 if( xTimeToWake < xTickCount )
\r
1627 /* Wake time has overflowed. Place this item in the overflow list. */
\r
1628 vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
1632 /* The wake time has not overflowed, so we can use the current block list. */
\r
1633 vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
1639 /* Calculate the time at which the task should be woken if the event does
\r
1640 not occur. This may overflow but this doesn't matter. */
\r
1641 xTimeToWake = xTickCount + xTicksToWait;
\r
1643 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
\r
1645 if( xTimeToWake < xTickCount )
\r
1647 /* Wake time has overflowed. Place this item in the overflow list. */
\r
1648 vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
1652 /* The wake time has not overflowed, so we can use the current block list. */
\r
1653 vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
1658 /*-----------------------------------------------------------*/
\r
1660 signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList )
\r
1662 tskTCB *pxUnblockedTCB;
\r
1663 portBASE_TYPE xReturn;
\r
1665 /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
\r
1666 SCHEDULER SUSPENDED. It can also be called from within an ISR. */
\r
1668 /* The event list is sorted in priority order, so we can remove the
\r
1669 first in the list, remove the TCB from the delayed list, and add
\r
1670 it to the ready list.
\r
1672 If an event is for a queue that is locked then this function will never
\r
1673 get called - the lock count on the queue will get modified instead. This
\r
1674 means we can always expect exclusive access to the event list here. */
\r
1675 pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
\r
1676 vListRemove( &( pxUnblockedTCB->xEventListItem ) );
\r
1678 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
1680 vListRemove( &( pxUnblockedTCB->xGenericListItem ) );
\r
1681 prvAddTaskToReadyQueue( pxUnblockedTCB );
\r
1685 /* We cannot access the delayed or ready lists, so will hold this
\r
1686 task pending until the scheduler is resumed. */
\r
1687 vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );
\r
1690 if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority )
\r
1692 /* Return true if the task removed from the event list has
\r
1693 a higher priority than the calling task. This allows
\r
1694 the calling task to know if it should force a context
\r
1700 xReturn = pdFALSE;
\r
1705 /*-----------------------------------------------------------*/
\r
1707 void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut )
\r
1709 pxTimeOut->xOverflowCount = xNumOfOverflows;
\r
1710 pxTimeOut->xTimeOnEntering = xTickCount;
\r
1712 /*-----------------------------------------------------------*/
\r
1714 portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait )
\r
1716 portBASE_TYPE xReturn;
\r
1718 portENTER_CRITICAL();
\r
1720 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1721 /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is
\r
1722 the maximum block time then the task should block indefinitely, and
\r
1723 therefore never time out. */
\r
1724 if( *pxTicksToWait == portMAX_DELAY )
\r
1726 xReturn = pdFALSE;
\r
1728 else /* We are not blocking indefinitely, perform the checks below. */
\r
1731 if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( ( portTickType ) xTickCount >= ( portTickType ) pxTimeOut->xTimeOnEntering ) )
\r
1733 /* The tick count is greater than the time at which vTaskSetTimeout()
\r
1734 was called, but has also overflowed since vTaskSetTimeOut() was called.
\r
1735 It must have wrapped all the way around and gone past us again. This
\r
1736 passed since vTaskSetTimeout() was called. */
\r
1739 else if( ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering ) < ( portTickType ) *pxTicksToWait )
\r
1741 /* Not a genuine timeout. Adjust parameters for time remaining. */
\r
1742 *pxTicksToWait -= ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering );
\r
1743 vTaskSetTimeOutState( pxTimeOut );
\r
1744 xReturn = pdFALSE;
\r
1751 portEXIT_CRITICAL();
\r
1755 /*-----------------------------------------------------------*/
\r
1757 void vTaskMissedYield( void )
\r
1759 xMissedYield = pdTRUE;
\r
1763 * -----------------------------------------------------------
\r
1765 * ----------------------------------------------------------
\r
1767 * The portTASK_FUNCTION() macro is used to allow port/compiler specific
\r
1768 * language extensions. The equivalent prototype for this function is:
\r
1770 * void prvIdleTask( void *pvParameters );
\r
1773 static portTASK_FUNCTION( prvIdleTask, pvParameters )
\r
1775 /* Stop warnings. */
\r
1776 ( void ) pvParameters;
\r
1780 /* See if any tasks have been deleted. */
\r
1781 prvCheckTasksWaitingTermination();
\r
1783 #if ( configUSE_PREEMPTION == 0 )
\r
1785 /* If we are not using preemption we keep forcing a task switch to
\r
1786 see if any other task has become available. If we are using
\r
1787 preemption we don't need to do this as any task becoming available
\r
1788 will automatically get the processor anyway. */
\r
1793 #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
\r
1795 /* When using preemption tasks of equal priority will be
\r
1796 timesliced. If a task that is sharing the idle priority is ready
\r
1797 to run then the idle task should yield before the end of the
\r
1800 A critical region is not required here as we are just reading from
\r
1801 the list, and an occasional incorrect value will not matter. If
\r
1802 the ready list at the idle priority contains more than one task
\r
1803 then a task other than the idle task is ready to execute. */
\r
1804 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( unsigned portBASE_TYPE ) 1 )
\r
1811 #if ( configUSE_IDLE_HOOK == 1 )
\r
1813 extern void vApplicationIdleHook( void );
\r
1815 /* Call the user defined function from within the idle task. This
\r
1816 allows the application designer to add background functionality
\r
1817 without the overhead of a separate task.
\r
1818 NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
\r
1819 CALL A FUNCTION THAT MIGHT BLOCK. */
\r
1820 vApplicationIdleHook();
\r
1824 } /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */
\r
1832 /*-----------------------------------------------------------
\r
1833 * File private functions documented at the top of the file.
\r
1834 *----------------------------------------------------------*/
\r
1838 static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed portCHAR * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned portSHORT usStackDepth )
\r
1840 /* Store the function name in the TCB. */
\r
1841 #if configMAX_TASK_NAME_LEN > 1
\r
1843 /* Don't bring strncpy into the build unnecessarily. */
\r
1844 strncpy( ( char * ) pxTCB->pcTaskName, ( const char * ) pcName, ( unsigned portSHORT ) configMAX_TASK_NAME_LEN );
\r
1847 pxTCB->pcTaskName[ ( unsigned portSHORT ) configMAX_TASK_NAME_LEN - ( unsigned portSHORT ) 1 ] = '\0';
\r
1849 /* This is used as an array index so must ensure it's not too large. First
\r
1850 remove the privilege bit if one is present. */
\r
1851 if( uxPriority >= configMAX_PRIORITIES )
\r
1853 uxPriority = configMAX_PRIORITIES - 1;
\r
1856 pxTCB->uxPriority = uxPriority;
\r
1857 #if ( configUSE_MUTEXES == 1 )
\r
1859 pxTCB->uxBasePriority = uxPriority;
\r
1863 vListInitialiseItem( &( pxTCB->xGenericListItem ) );
\r
1864 vListInitialiseItem( &( pxTCB->xEventListItem ) );
\r
1866 /* Set the pxTCB as a link back from the xListItem. This is so we can get
\r
1867 back to the containing TCB from a generic item in a list. */
\r
1868 listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB );
\r
1870 /* Event lists are always in priority order. */
\r
1871 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );
\r
1872 listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB );
\r
1874 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
\r
1876 pxTCB->uxCriticalNesting = ( unsigned portBASE_TYPE ) 0;
\r
1880 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
1882 pxTCB->pxTaskTag = NULL;
\r
1886 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
1888 pxTCB->ulRunTimeCounter = 0UL;
\r
1892 #if ( portUSING_MPU_WRAPPERS == 1 )
\r
1894 vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth );
\r
1898 ( void ) xRegions;
\r
1899 ( void ) usStackDepth;
\r
1903 /*-----------------------------------------------------------*/
\r
1905 #if ( portUSING_MPU_WRAPPERS == 1 )
\r
1907 void vTaskAllocateMPURegions( xTaskHandle xTaskToModify, const xMemoryRegion * const xRegions )
\r
1911 if( xTaskToModify == pxCurrentTCB )
\r
1913 xTaskToModify = NULL;
\r
1916 /* If null is passed in here then we are deleting ourselves. */
\r
1917 pxTCB = prvGetTCBFromHandle( xTaskToModify );
\r
1919 vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 );
\r
1921 /*-----------------------------------------------------------*/
\r
1924 static void prvInitialiseTaskLists( void )
\r
1926 unsigned portBASE_TYPE uxPriority;
\r
1928 for( uxPriority = 0; uxPriority < configMAX_PRIORITIES; uxPriority++ )
\r
1930 vListInitialise( ( xList * ) &( pxReadyTasksLists[ uxPriority ] ) );
\r
1933 vListInitialise( ( xList * ) &xDelayedTaskList1 );
\r
1934 vListInitialise( ( xList * ) &xDelayedTaskList2 );
\r
1935 vListInitialise( ( xList * ) &xPendingReadyList );
\r
1937 #if ( INCLUDE_vTaskDelete == 1 )
\r
1939 vListInitialise( ( xList * ) &xTasksWaitingTermination );
\r
1943 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1945 vListInitialise( ( xList * ) &xSuspendedTaskList );
\r
1949 /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
\r
1951 pxDelayedTaskList = &xDelayedTaskList1;
\r
1952 pxOverflowDelayedTaskList = &xDelayedTaskList2;
\r
1954 /*-----------------------------------------------------------*/
\r
1956 static void prvCheckTasksWaitingTermination( void )
\r
1958 #if ( INCLUDE_vTaskDelete == 1 )
\r
1960 portBASE_TYPE xListIsEmpty;
\r
1962 /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
\r
1963 too often in the idle task. */
\r
1964 if( uxTasksDeleted > ( unsigned portBASE_TYPE ) 0 )
\r
1966 vTaskSuspendAll();
\r
1967 xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
\r
1970 if( !xListIsEmpty )
\r
1974 portENTER_CRITICAL();
\r
1976 pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xTasksWaitingTermination ) );
\r
1977 vListRemove( &( pxTCB->xGenericListItem ) );
\r
1978 --uxCurrentNumberOfTasks;
\r
1981 portEXIT_CRITICAL();
\r
1983 prvDeleteTCB( pxTCB );
\r
1989 /*-----------------------------------------------------------*/
\r
1991 static tskTCB *prvAllocateTCBAndStack( unsigned portSHORT usStackDepth, portSTACK_TYPE *puxStackBuffer )
\r
1995 /* Allocate space for the TCB. Where the memory comes from depends on
\r
1996 the implementation of the port malloc function. */
\r
1997 pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) );
\r
1999 if( pxNewTCB != NULL )
\r
2001 /* Allocate space for the stack used by the task being created.
\r
2002 The base of the stack memory stored in the TCB so the task can
\r
2003 be deleted later if required. */
\r
2004 pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMallocAligned( ( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) ), puxStackBuffer );
\r
2006 if( pxNewTCB->pxStack == NULL )
\r
2008 /* Could not allocate the stack. Delete the allocated TCB. */
\r
2009 vPortFree( pxNewTCB );
\r
2014 /* Just to help debugging. */
\r
2015 memset( pxNewTCB->pxStack, tskSTACK_FILL_BYTE, usStackDepth * sizeof( portSTACK_TYPE ) );
\r
2021 /*-----------------------------------------------------------*/
\r
2023 #if ( configUSE_TRACE_FACILITY == 1 )
\r
2025 static void prvListTaskWithinSingleList( const signed portCHAR *pcWriteBuffer, xList *pxList, signed portCHAR cStatus )
\r
2027 volatile tskTCB *pxNextTCB, *pxFirstTCB;
\r
2028 unsigned portSHORT usStackRemaining;
\r
2030 /* Write the details of all the TCB's in pxList into the buffer. */
\r
2031 listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
\r
2034 listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
\r
2035 usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned portCHAR * ) pxNextTCB->pxStack );
\r
2036 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
2037 strcat( ( portCHAR * ) pcWriteBuffer, ( portCHAR * ) pcStatusString );
\r
2039 } while( pxNextTCB != pxFirstTCB );
\r
2043 /*-----------------------------------------------------------*/
\r
2045 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
2047 static void prvGenerateRunTimeStatsForTasksInList( const signed portCHAR *pcWriteBuffer, xList *pxList, unsigned portLONG ulTotalRunTime )
\r
2049 volatile tskTCB *pxNextTCB, *pxFirstTCB;
\r
2050 unsigned portLONG ulStatsAsPercentage;
\r
2052 /* Write the run time stats of all the TCB's in pxList into the buffer. */
\r
2053 listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
\r
2056 /* Get next TCB in from the list. */
\r
2057 listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
\r
2059 /* Divide by zero check. */
\r
2060 if( ulTotalRunTime > 0UL )
\r
2062 /* Has the task run at all? */
\r
2063 if( pxNextTCB->ulRunTimeCounter == 0 )
\r
2065 /* The task has used no CPU time at all. */
\r
2066 sprintf( pcStatsString, ( portCHAR * ) "%s\t\t0\t\t0%%\r\n", pxNextTCB->pcTaskName );
\r
2070 /* What percentage of the total run time as the task used?
\r
2071 This will always be rounded down to the nearest integer. */
\r
2072 ulStatsAsPercentage = ( 100UL * pxNextTCB->ulRunTimeCounter ) / ulTotalRunTime;
\r
2074 if( ulStatsAsPercentage > 0UL )
\r
2076 sprintf( pcStatsString, ( portCHAR * ) "%s\t\t%u\t\t%u%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage );
\r
2080 /* If the percentage is zero here then the task has
\r
2081 consumed less than 1% of the total run time. */
\r
2082 sprintf( pcStatsString, ( portCHAR * ) "%s\t\t%u\t\t<1%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter );
\r
2086 strcat( ( portCHAR * ) pcWriteBuffer, ( portCHAR * ) pcStatsString );
\r
2089 } while( pxNextTCB != pxFirstTCB );
\r
2093 /*-----------------------------------------------------------*/
\r
2095 #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
\r
2097 static unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR * pucStackByte )
\r
2099 register unsigned portSHORT usCount = 0;
\r
2101 while( *pucStackByte == tskSTACK_FILL_BYTE )
\r
2103 pucStackByte -= portSTACK_GROWTH;
\r
2107 usCount /= sizeof( portSTACK_TYPE );
\r
2113 /*-----------------------------------------------------------*/
\r
2115 #if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )
\r
2117 unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask )
\r
2120 unsigned portCHAR *pcEndOfStack;
\r
2121 unsigned portBASE_TYPE uxReturn;
\r
2123 pxTCB = prvGetTCBFromHandle( xTask );
\r
2125 #if portSTACK_GROWTH < 0
\r
2127 pcEndOfStack = ( unsigned portCHAR * ) pxTCB->pxStack;
\r
2131 pcEndOfStack = ( unsigned portCHAR * ) pxTCB->pxEndOfStack;
\r
2135 uxReturn = ( unsigned portBASE_TYPE ) usTaskCheckFreeStackSpace( pcEndOfStack );
\r
2141 /*-----------------------------------------------------------*/
\r
2143 #if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
\r
2145 static void prvDeleteTCB( tskTCB *pxTCB )
\r
2147 /* Free up the memory allocated by the scheduler for the task. It is up to
\r
2148 the task to free any memory allocated at the application level. */
\r
2149 vPortFreeAligned( pxTCB->pxStack );
\r
2150 vPortFree( pxTCB );
\r
2156 /*-----------------------------------------------------------*/
\r
2158 #if ( INCLUDE_xTaskGetCurrentTaskHandle == 1 )
\r
2160 xTaskHandle xTaskGetCurrentTaskHandle( void )
\r
2162 xTaskHandle xReturn;
\r
2164 /* A critical section is not required as this is not called from
\r
2165 an interrupt and the current TCB will always be the same for any
\r
2166 individual execution thread. */
\r
2167 xReturn = pxCurrentTCB;
\r
2174 /*-----------------------------------------------------------*/
\r
2176 #if ( INCLUDE_xTaskGetSchedulerState == 1 )
\r
2178 portBASE_TYPE xTaskGetSchedulerState( void )
\r
2180 portBASE_TYPE xReturn;
\r
2182 if( xSchedulerRunning == pdFALSE )
\r
2184 xReturn = taskSCHEDULER_NOT_STARTED;
\r
2188 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
2190 xReturn = taskSCHEDULER_RUNNING;
\r
2194 xReturn = taskSCHEDULER_SUSPENDED;
\r
2202 /*-----------------------------------------------------------*/
\r
2204 #if ( configUSE_MUTEXES == 1 )
\r
2206 void vTaskPriorityInherit( xTaskHandle * const pxMutexHolder )
\r
2208 tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
\r
2210 if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )
\r
2212 /* Adjust the mutex holder state to account for its new priority. */
\r
2213 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxCurrentTCB->uxPriority );
\r
2215 /* If the task being modified is in the ready state it will need to
\r
2216 be moved in to a new list. */
\r
2217 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) )
\r
2219 vListRemove( &( pxTCB->xGenericListItem ) );
\r
2221 /* Inherit the priority before being moved into the new list. */
\r
2222 pxTCB->uxPriority = pxCurrentTCB->uxPriority;
\r
2223 prvAddTaskToReadyQueue( pxTCB );
\r
2227 /* Just inherit the priority. */
\r
2228 pxTCB->uxPriority = pxCurrentTCB->uxPriority;
\r
2234 /*-----------------------------------------------------------*/
\r
2236 #if ( configUSE_MUTEXES == 1 )
\r
2238 void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder )
\r
2240 tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
\r
2242 if( pxMutexHolder != NULL )
\r
2244 if( pxTCB->uxPriority != pxTCB->uxBasePriority )
\r
2246 /* We must be the running task to be able to give the mutex back.
\r
2247 Remove ourselves from the ready list we currently appear in. */
\r
2248 vListRemove( &( pxTCB->xGenericListItem ) );
\r
2250 /* Disinherit the priority before adding ourselves into the new
\r
2252 pxTCB->uxPriority = pxTCB->uxBasePriority;
\r
2253 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxTCB->uxPriority );
\r
2254 prvAddTaskToReadyQueue( pxTCB );
\r
2260 /*-----------------------------------------------------------*/
\r
2262 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
\r
2264 void vTaskEnterCritical( void )
\r
2266 portDISABLE_INTERRUPTS();
\r
2268 if( xSchedulerRunning != pdFALSE )
\r
2270 pxCurrentTCB->uxCriticalNesting++;
\r
2275 /*-----------------------------------------------------------*/
\r
2277 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
\r
2279 void vTaskExitCritical( void )
\r
2281 if( xSchedulerRunning != pdFALSE )
\r
2283 if( pxCurrentTCB->uxCriticalNesting > 0 )
\r
2285 pxCurrentTCB->uxCriticalNesting--;
\r
2287 if( pxCurrentTCB->uxCriticalNesting == 0 )
\r
2289 portENABLE_INTERRUPTS();
\r
2296 /*-----------------------------------------------------------*/
\r