2 FreeRTOS.org V5.0.4 - Copyright (C) 2003-2008 Richard Barry.
\r
4 This file is part of the FreeRTOS.org distribution.
\r
6 FreeRTOS.org is free software; you can redistribute it and/or modify
\r
7 it under the terms of the GNU General Public License as published by
\r
8 the Free Software Foundation; either version 2 of the License, or
\r
9 (at your option) any later version.
\r
11 FreeRTOS.org is distributed in the hope that it will be useful,
\r
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 GNU General Public License for more details.
\r
16 You should have received a copy of the GNU General Public License
\r
17 along with FreeRTOS.org; if not, write to the Free Software
\r
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\r
20 A special exception to the GPL can be applied should you wish to distribute
\r
21 a combined work that includes FreeRTOS.org, without being obliged to provide
\r
22 the source code for any proprietary components. See the licensing section
\r
23 of http://www.FreeRTOS.org for full details of how and when the exception
\r
26 ***************************************************************************
\r
27 ***************************************************************************
\r
29 * SAVE TIME AND MONEY! We can port FreeRTOS.org to your own hardware, *
\r
30 * and even write all or part of your application on your behalf. *
\r
31 * See http://www.OpenRTOS.com for details of the services we provide to *
\r
32 * expedite your project. *
\r
34 ***************************************************************************
\r
35 ***************************************************************************
\r
37 Please ensure to read the configuration and relevant port sections of the
\r
38 online documentation.
\r
40 http://www.FreeRTOS.org - Documentation, latest information, license and
\r
43 http://www.SafeRTOS.com - A version that is certified for use in safety
\r
46 http://www.OpenRTOS.com - Commercial support, development, porting,
\r
47 licensing and training services.
\r
55 #include "FreeRTOS.h"
\r
59 * Macro to define the amount of stack available to the idle task.
\r
61 #define tskIDLE_STACK_SIZE configMINIMAL_STACK_SIZE
\r
64 * Task control block. A task control block (TCB) is allocated to each task,
\r
65 * and stores the context of the task.
\r
67 typedef struct tskTaskControlBlock
\r
69 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
70 xListItem xGenericListItem; /*< List item used to place the TCB in ready and blocked queues. */
\r
71 xListItem xEventListItem; /*< List item used to place the TCB in event lists. */
\r
72 unsigned portBASE_TYPE uxPriority; /*< The priority of the task where 0 is the lowest priority. */
\r
73 portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */
\r
74 signed portCHAR pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */
\r
76 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
\r
77 unsigned portBASE_TYPE uxCriticalNesting;
\r
80 #if ( configUSE_TRACE_FACILITY == 1 )
\r
81 unsigned portBASE_TYPE uxTCBNumber; /*< This is used for tracing the scheduler and making debugging easier only. */
\r
84 #if ( configUSE_MUTEXES == 1 )
\r
85 unsigned portBASE_TYPE uxBasePriority;
\r
88 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
89 pdTASK_HOOK_CODE pxTaskTag;
\r
95 * Some kernel aware debuggers require data to be viewed to be global, rather
\r
98 #ifdef portREMOVE_STATIC_QUALIFIER
\r
104 tskTCB * volatile pxCurrentTCB = NULL;
\r
106 /* Lists for ready and blocked tasks. --------------------*/
\r
108 static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */
\r
109 static xList xDelayedTaskList1; /*< Delayed tasks. */
\r
110 static xList xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
\r
111 static xList * volatile pxDelayedTaskList; /*< Points to the delayed task list currently being used. */
\r
112 static xList * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
\r
113 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
115 #if ( INCLUDE_vTaskDelete == 1 )
\r
117 static volatile xList xTasksWaitingTermination; /*< Tasks that have been deleted - but the their memory not yet freed. */
\r
118 static volatile unsigned portBASE_TYPE uxTasksDeleted = ( unsigned portBASE_TYPE ) 0;
\r
122 #if ( INCLUDE_vTaskSuspend == 1 )
\r
124 static xList xSuspendedTaskList; /*< Tasks that are currently suspended. */
\r
128 /* File private variables. --------------------------------*/
\r
129 static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks = ( unsigned portBASE_TYPE ) 0;
\r
130 static volatile portTickType xTickCount = ( portTickType ) 0;
\r
131 static unsigned portBASE_TYPE uxTopUsedPriority = tskIDLE_PRIORITY;
\r
132 static volatile unsigned portBASE_TYPE uxTopReadyPriority = tskIDLE_PRIORITY;
\r
133 static volatile signed portBASE_TYPE xSchedulerRunning = pdFALSE;
\r
134 static volatile unsigned portBASE_TYPE uxSchedulerSuspended = ( unsigned portBASE_TYPE ) pdFALSE;
\r
135 static volatile unsigned portBASE_TYPE uxMissedTicks = ( unsigned portBASE_TYPE ) 0;
\r
136 static volatile portBASE_TYPE xMissedYield = ( portBASE_TYPE ) pdFALSE;
\r
137 static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0;
\r
138 #if ( configUSE_TRACE_FACILITY == 1 )
\r
139 static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberate - this is guarded before use. */
\r
142 /* Debugging and trace facilities private variables and macros. ------------*/
\r
145 * The value used to fill the stack of a task when the task is created. This
\r
146 * is used purely for checking the high water mark for tasks.
\r
148 #define tskSTACK_FILL_BYTE ( 0xa5 )
\r
151 * Macros used by vListTask to indicate which state a task is in.
\r
153 #define tskBLOCKED_CHAR ( ( signed portCHAR ) 'B' )
\r
154 #define tskREADY_CHAR ( ( signed portCHAR ) 'R' )
\r
155 #define tskDELETED_CHAR ( ( signed portCHAR ) 'D' )
\r
156 #define tskSUSPENDED_CHAR ( ( signed portCHAR ) 'S' )
\r
159 * Macros and private variables used by the trace facility.
\r
161 #if ( configUSE_TRACE_FACILITY == 1 )
\r
163 #define tskSIZE_OF_EACH_TRACE_LINE ( ( unsigned portLONG ) ( sizeof( unsigned portLONG ) + sizeof( unsigned portLONG ) ) )
\r
164 static volatile signed portCHAR * volatile pcTraceBuffer;
\r
165 static signed portCHAR *pcTraceBufferStart;
\r
166 static signed portCHAR *pcTraceBufferEnd;
\r
167 static signed portBASE_TYPE xTracing = pdFALSE;
\r
168 static unsigned portBASE_TYPE uxPreviousTask = 255;
\r
169 static portCHAR pcStatusString[ 50 ];
\r
172 /*-----------------------------------------------------------*/
\r
175 * Macro that writes a trace of scheduler activity to a buffer. This trace
\r
176 * shows which task is running when and is very useful as a debugging tool.
\r
177 * As this macro is called each context switch it is a good idea to undefine
\r
178 * it if not using the facility.
\r
180 #if ( configUSE_TRACE_FACILITY == 1 )
\r
182 #define vWriteTraceToBuffer() \
\r
186 if( uxPreviousTask != pxCurrentTCB->uxTCBNumber ) \
\r
188 if( ( pcTraceBuffer + tskSIZE_OF_EACH_TRACE_LINE ) < pcTraceBufferEnd ) \
\r
190 uxPreviousTask = pxCurrentTCB->uxTCBNumber; \
\r
191 *( unsigned portLONG * ) pcTraceBuffer = ( unsigned portLONG ) xTickCount; \
\r
192 pcTraceBuffer += sizeof( unsigned portLONG ); \
\r
193 *( unsigned portLONG * ) pcTraceBuffer = ( unsigned portLONG ) uxPreviousTask; \
\r
194 pcTraceBuffer += sizeof( unsigned portLONG ); \
\r
198 xTracing = pdFALSE; \
\r
206 #define vWriteTraceToBuffer()
\r
209 /*-----------------------------------------------------------*/
\r
212 * Place the task represented by pxTCB into the appropriate ready queue for
\r
213 * the task. It is inserted at the end of the list. One quirk of this is
\r
214 * that if the task being inserted is at the same priority as the currently
\r
215 * executing task, then it will only be rescheduled after the currently
\r
216 * executing task has been rescheduled.
\r
218 #define prvAddTaskToReadyQueue( pxTCB ) \
\r
220 if( pxTCB->uxPriority > uxTopReadyPriority ) \
\r
222 uxTopReadyPriority = pxTCB->uxPriority; \
\r
224 vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ); \
\r
226 /*-----------------------------------------------------------*/
\r
229 * Macro that looks at the list of tasks that are currently delayed to see if
\r
230 * any require waking.
\r
232 * Tasks are stored in the queue in the order of their wake time - meaning
\r
233 * once one tasks has been found whose timer has not expired we need not look
\r
234 * any further down the list.
\r
236 #define prvCheckDelayedTasks() \
\r
238 register tskTCB *pxTCB; \
\r
240 while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ) ) != NULL ) \
\r
242 if( xTickCount < listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ) ) \
\r
246 vListRemove( &( pxTCB->xGenericListItem ) ); \
\r
247 /* Is the task waiting on an event also? */ \
\r
248 if( pxTCB->xEventListItem.pvContainer ) \
\r
250 vListRemove( &( pxTCB->xEventListItem ) ); \
\r
252 prvAddTaskToReadyQueue( pxTCB ); \
\r
255 /*-----------------------------------------------------------*/
\r
258 * Call the stack overflow hook function if the stack of the task being swapped
\r
259 * out is currently overflowed, or looks like it might have overflowed in the
\r
262 * Setting configCHECK_FOR_STACK_OVERFLOW to 1 will cause the macro to check
\r
263 * the current stack state only - comparing the current top of stack value to
\r
264 * the stack limit. Setting configCHECK_FOR_STACK_OVERFLOW to greater than 1
\r
265 * will also cause the last few stack bytes to be checked to ensure the value
\r
266 * to which the bytes were set when the task was created have not been
\r
267 * overwritten. Note this second test does not guarantee that an overflowed
\r
268 * stack will always be recognised.
\r
271 #if( configCHECK_FOR_STACK_OVERFLOW == 0 )
\r
273 /* FreeRTOSConfig.h is not set to check for stack overflows. */
\r
274 #define taskCHECK_FOR_STACK_OVERFLOW()
\r
276 #endif /* configCHECK_FOR_STACK_OVERFLOW == 0 */
\r
278 #if( ( configCHECK_FOR_STACK_OVERFLOW > 0 ) && ( portSTACK_GROWTH >= 0 ) )
\r
280 /* This is an invalid setting. */
\r
281 #error configCHECK_FOR_STACK_OVERFLOW can only be set to a non zero value on architectures where the stack grows down from high memory.
\r
283 #endif /* ( configCHECK_FOR_STACK_OVERFLOW > 0 ) && ( portSTACK_GROWTH >= 0 ) */
\r
285 #if( configCHECK_FOR_STACK_OVERFLOW == 1 )
\r
287 /* Only the current stack state is to be checked. */
\r
288 #define taskCHECK_FOR_STACK_OVERFLOW() \
\r
290 extern void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed portCHAR *pcTaskName ); \
\r
292 /* Is the currently saved stack pointer within the stack limit? */ \
\r
293 if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack ) \
\r
295 vApplicationStackOverflowHook( ( xTaskHandle ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
\r
299 #endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */
\r
301 #if( configCHECK_FOR_STACK_OVERFLOW > 1 )
\r
303 /* Both the current statck state and the stack fill bytes are to be checked. */
\r
304 #define taskCHECK_FOR_STACK_OVERFLOW() \
\r
306 extern void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed portCHAR *pcTaskName ); \
\r
307 static const unsigned portCHAR ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
\r
308 tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
\r
309 tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
\r
310 tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
\r
311 tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \
\r
313 /* Is the currently saved stack pointer within the stack limit? */ \
\r
314 if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack ) \
\r
316 vApplicationStackOverflowHook( ( xTaskHandle ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
\r
319 /* Has the extremity of the task stack ever been written over? */ \
\r
320 if( memcmp( ( void * ) pxCurrentTCB->pxStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \
\r
322 vApplicationStackOverflowHook( ( xTaskHandle ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
\r
326 #endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */
\r
328 /*-----------------------------------------------------------*/
\r
331 * Several functions take an xTaskHandle parameter that can optionally be NULL,
\r
332 * where NULL is used to indicate that the handle of the currently executing
\r
333 * task should be used in place of the parameter. This macro simply checks to
\r
334 * see if the parameter is NULL and returns a pointer to the appropriate TCB.
\r
336 #define prvGetTCBFromHandle( pxHandle ) ( ( pxHandle == NULL ) ? ( tskTCB * ) pxCurrentTCB : ( tskTCB * ) pxHandle )
\r
339 /* File private functions. --------------------------------*/
\r
342 * Utility to ready a TCB for a given task. Mainly just copies the parameters
\r
343 * into the TCB structure.
\r
345 static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed portCHAR * const pcName, unsigned portBASE_TYPE uxPriority );
\r
348 * Utility to ready all the lists used by the scheduler. This is called
\r
349 * automatically upon the creation of the first task.
\r
351 static void prvInitialiseTaskLists( void );
\r
354 * The idle task, which as all tasks is implemented as a never ending loop.
\r
355 * The idle task is automatically created and added to the ready lists upon
\r
356 * creation of the first user task.
\r
358 * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific
\r
359 * language extensions. The equivalent prototype for this function is:
\r
361 * void prvIdleTask( void *pvParameters );
\r
364 static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters );
\r
367 * Utility to free all memory allocated by the scheduler to hold a TCB,
\r
368 * including the stack pointed to by the TCB.
\r
370 * This does not free memory allocated by the task itself (i.e. memory
\r
371 * allocated by calls to pvPortMalloc from within the tasks application code).
\r
373 #if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
\r
374 static void prvDeleteTCB( tskTCB *pxTCB );
\r
378 * Used only by the idle task. This checks to see if anything has been placed
\r
379 * in the list of tasks waiting to be deleted. If so the task is cleaned up
\r
380 * and its TCB deleted.
\r
382 static void prvCheckTasksWaitingTermination( void );
\r
385 * Allocates memory from the heap for a TCB and associated stack. Checks the
\r
386 * allocation was successful.
\r
388 static tskTCB *prvAllocateTCBAndStack( unsigned portSHORT usStackDepth );
\r
391 * Called from vTaskList. vListTasks details all the tasks currently under
\r
392 * control of the scheduler. The tasks may be in one of a number of lists.
\r
393 * prvListTaskWithinSingleList accepts a list and details the tasks from
\r
394 * within just that list.
\r
396 * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM
\r
397 * NORMAL APPLICATION CODE.
\r
399 #if ( configUSE_TRACE_FACILITY == 1 )
\r
401 static void prvListTaskWithinSingleList( const signed portCHAR *pcWriteBuffer, xList *pxList, signed portCHAR cStatus );
\r
406 * When a task is created, the stack of the task is filled with a known value.
\r
407 * This function determines the 'high water mark' of the task stack by
\r
408 * determining how much of the stack remains at the original preset value.
\r
410 #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
\r
412 unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR * pucStackByte );
\r
421 /*-----------------------------------------------------------
\r
422 * TASK CREATION API documented in task.h
\r
423 *----------------------------------------------------------*/
\r
425 signed portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode, const signed portCHAR * const pcName, unsigned portSHORT usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask )
\r
427 signed portBASE_TYPE xReturn;
\r
430 /* Allocate the memory required by the TCB and stack for the new task.
\r
431 checking that the allocation was successful. */
\r
432 pxNewTCB = prvAllocateTCBAndStack( usStackDepth );
\r
434 if( pxNewTCB != NULL )
\r
436 portSTACK_TYPE *pxTopOfStack;
\r
438 /* Setup the newly allocated TCB with the initial state of the task. */
\r
439 prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority );
\r
441 /* Calculate the top of stack address. This depends on whether the
\r
442 stack grows from high memory to low (as per the 80x86) or visa versa.
\r
443 portSTACK_GROWTH is used to make the result positive or negative as
\r
444 required by the port. */
\r
445 #if portSTACK_GROWTH < 0
\r
447 pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
\r
451 pxTopOfStack = pxNewTCB->pxStack;
\r
455 /* Initialize the TCB stack to look as if the task was already running,
\r
456 but had been interrupted by the scheduler. The return address is set
\r
457 to the start of the task function. Once the stack has been initialised
\r
458 the top of stack variable is updated. */
\r
459 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pvTaskCode, pvParameters );
\r
461 /* We are going to manipulate the task queues to add this task to a
\r
462 ready list, so must make sure no interrupts occur. */
\r
463 portENTER_CRITICAL();
\r
465 uxCurrentNumberOfTasks++;
\r
466 if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )
\r
468 /* As this is the first task it must also be the current task. */
\r
469 pxCurrentTCB = pxNewTCB;
\r
471 /* This is the first task to be created so do the preliminary
\r
472 initialisation required. We will not recover if this call
\r
473 fails, but we will report the failure. */
\r
474 prvInitialiseTaskLists();
\r
478 /* If the scheduler is not already running, make this task the
\r
479 current task if it is the highest priority task to be created
\r
481 if( xSchedulerRunning == pdFALSE )
\r
483 if( pxCurrentTCB->uxPriority <= uxPriority )
\r
485 pxCurrentTCB = pxNewTCB;
\r
490 /* Remember the top priority to make context switching faster. Use
\r
491 the priority in pxNewTCB as this has been capped to a valid value. */
\r
492 if( pxNewTCB->uxPriority > uxTopUsedPriority )
\r
494 uxTopUsedPriority = pxNewTCB->uxPriority;
\r
497 #if ( configUSE_TRACE_FACILITY == 1 )
\r
499 /* Add a counter into the TCB for tracing only. */
\r
500 pxNewTCB->uxTCBNumber = uxTaskNumber;
\r
505 prvAddTaskToReadyQueue( pxNewTCB );
\r
508 traceTASK_CREATE( pxNewTCB );
\r
510 portEXIT_CRITICAL();
\r
514 xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
\r
515 traceTASK_CREATE_FAILED( pxNewTCB );
\r
518 if( xReturn == pdPASS )
\r
520 if( ( void * ) pxCreatedTask != NULL )
\r
522 /* Pass the TCB out - in an anonymous way. The calling function/
\r
523 task can use this as a handle to delete the task later if
\r
525 *pxCreatedTask = ( xTaskHandle ) pxNewTCB;
\r
528 if( xSchedulerRunning != pdFALSE )
\r
530 /* If the created task is of a higher priority than the current task
\r
531 then it should run now. */
\r
532 if( pxCurrentTCB->uxPriority < uxPriority )
\r
541 /*-----------------------------------------------------------*/
\r
543 #if ( INCLUDE_vTaskDelete == 1 )
\r
545 void vTaskDelete( xTaskHandle pxTaskToDelete )
\r
549 taskENTER_CRITICAL();
\r
551 /* Ensure a yield is performed if the current task is being
\r
553 if( pxTaskToDelete == pxCurrentTCB )
\r
555 pxTaskToDelete = NULL;
\r
558 /* If null is passed in here then we are deleting ourselves. */
\r
559 pxTCB = prvGetTCBFromHandle( pxTaskToDelete );
\r
561 traceTASK_DELETE( pxTCB );
\r
563 /* Remove task from the ready list and place in the termination list.
\r
564 This will stop the task from be scheduled. The idle task will check
\r
565 the termination list and free up any memory allocated by the
\r
566 scheduler for the TCB and stack. */
\r
567 vListRemove( &( pxTCB->xGenericListItem ) );
\r
569 /* Is the task waiting on an event also? */
\r
570 if( pxTCB->xEventListItem.pvContainer )
\r
572 vListRemove( &( pxTCB->xEventListItem ) );
\r
575 vListInsertEnd( ( xList * ) &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );
\r
577 /* Increment the ucTasksDeleted variable so the idle task knows
\r
578 there is a task that has been deleted and that it should therefore
\r
579 check the xTasksWaitingTermination list. */
\r
582 taskEXIT_CRITICAL();
\r
584 /* Force a reschedule if we have just deleted the current task. */
\r
585 if( xSchedulerRunning != pdFALSE )
\r
587 if( ( void * ) pxTaskToDelete == NULL )
\r
601 /*-----------------------------------------------------------
\r
602 * TASK CONTROL API documented in task.h
\r
603 *----------------------------------------------------------*/
\r
605 #if ( INCLUDE_vTaskDelayUntil == 1 )
\r
607 void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement )
\r
609 portTickType xTimeToWake;
\r
610 portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE;
\r
614 /* Generate the tick time at which the task wants to wake. */
\r
615 xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
\r
617 if( xTickCount < *pxPreviousWakeTime )
\r
619 /* The tick count has overflowed since this function was
\r
620 lasted called. In this case the only time we should ever
\r
621 actually delay is if the wake time has also overflowed,
\r
622 and the wake time is greater than the tick time. When this
\r
623 is the case it is as if neither time had overflowed. */
\r
624 if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xTickCount ) )
\r
626 xShouldDelay = pdTRUE;
\r
631 /* The tick time has not overflowed. In this case we will
\r
632 delay if either the wake time has overflowed, and/or the
\r
633 tick time is less than the wake time. */
\r
634 if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xTickCount ) )
\r
636 xShouldDelay = pdTRUE;
\r
640 /* Update the wake time ready for the next call. */
\r
641 *pxPreviousWakeTime = xTimeToWake;
\r
645 traceTASK_DELAY_UNTIL();
\r
647 /* We must remove ourselves from the ready list before adding
\r
648 ourselves to the blocked list as the same list item is used for
\r
650 vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
652 /* The list item will be inserted in wake time order. */
\r
653 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
\r
655 if( xTimeToWake < xTickCount )
\r
657 /* Wake time has overflowed. Place this item in the
\r
659 vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
663 /* The wake time has not overflowed, so we can use the
\r
664 current block list. */
\r
665 vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
669 xAlreadyYielded = xTaskResumeAll();
\r
671 /* Force a reschedule if xTaskResumeAll has not already done so, we may
\r
672 have put ourselves to sleep. */
\r
673 if( !xAlreadyYielded )
\r
680 /*-----------------------------------------------------------*/
\r
682 #if ( INCLUDE_vTaskDelay == 1 )
\r
684 void vTaskDelay( portTickType xTicksToDelay )
\r
686 portTickType xTimeToWake;
\r
687 signed portBASE_TYPE xAlreadyYielded = pdFALSE;
\r
689 /* A delay time of zero just forces a reschedule. */
\r
690 if( xTicksToDelay > ( portTickType ) 0 )
\r
696 /* A task that is removed from the event list while the
\r
697 scheduler is suspended will not get placed in the ready
\r
698 list or removed from the blocked list until the scheduler
\r
701 This task cannot be in an event list as it is the currently
\r
704 /* Calculate the time to wake - this may overflow but this is
\r
706 xTimeToWake = xTickCount + xTicksToDelay;
\r
708 /* We must remove ourselves from the ready list before adding
\r
709 ourselves to the blocked list as the same list item is used for
\r
711 vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
713 /* The list item will be inserted in wake time order. */
\r
714 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
\r
716 if( xTimeToWake < xTickCount )
\r
718 /* Wake time has overflowed. Place this item in the
\r
720 vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
724 /* The wake time has not overflowed, so we can use the
\r
725 current block list. */
\r
726 vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
729 xAlreadyYielded = xTaskResumeAll();
\r
732 /* Force a reschedule if xTaskResumeAll has not already done so, we may
\r
733 have put ourselves to sleep. */
\r
734 if( !xAlreadyYielded )
\r
741 /*-----------------------------------------------------------*/
\r
743 #if ( INCLUDE_uxTaskPriorityGet == 1 )
\r
745 unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask )
\r
748 unsigned portBASE_TYPE uxReturn;
\r
750 taskENTER_CRITICAL();
\r
752 /* If null is passed in here then we are changing the
\r
753 priority of the calling function. */
\r
754 pxTCB = prvGetTCBFromHandle( pxTask );
\r
755 uxReturn = pxTCB->uxPriority;
\r
757 taskEXIT_CRITICAL();
\r
763 /*-----------------------------------------------------------*/
\r
765 #if ( INCLUDE_vTaskPrioritySet == 1 )
\r
767 void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority )
\r
770 unsigned portBASE_TYPE uxCurrentPriority, xYieldRequired = pdFALSE;
\r
772 /* Ensure the new priority is valid. */
\r
773 if( uxNewPriority >= configMAX_PRIORITIES )
\r
775 uxNewPriority = configMAX_PRIORITIES - 1;
\r
778 taskENTER_CRITICAL();
\r
780 if( pxTask == pxCurrentTCB )
\r
785 /* If null is passed in here then we are changing the
\r
786 priority of the calling function. */
\r
787 pxTCB = prvGetTCBFromHandle( pxTask );
\r
789 traceTASK_PRIORITY_SET( pxTask, uxNewPriority );
\r
791 #if ( configUSE_MUTEXES == 1 )
\r
793 uxCurrentPriority = pxTCB->uxBasePriority;
\r
797 uxCurrentPriority = pxTCB->uxPriority;
\r
801 if( uxCurrentPriority != uxNewPriority )
\r
803 /* The priority change may have readied a task of higher
\r
804 priority than the calling task. */
\r
805 if( uxNewPriority > uxCurrentPriority )
\r
807 if( pxTask != NULL )
\r
809 /* The priority of another task is being raised. If we
\r
810 were raising the priority of the currently running task
\r
811 there would be no need to switch as it must have already
\r
812 been the highest priority task. */
\r
813 xYieldRequired = pdTRUE;
\r
816 else if( pxTask == NULL )
\r
818 /* Setting our own priority down means there may now be another
\r
819 task of higher priority that is ready to execute. */
\r
820 xYieldRequired = pdTRUE;
\r
825 #if ( configUSE_MUTEXES == 1 )
\r
827 /* Only change the priority being used if the task is not
\r
828 currently using an inherited priority. */
\r
829 if( pxTCB->uxBasePriority == pxTCB->uxPriority )
\r
831 pxTCB->uxPriority = uxNewPriority;
\r
834 /* The base priority gets set whatever. */
\r
835 pxTCB->uxBasePriority = uxNewPriority;
\r
839 pxTCB->uxPriority = uxNewPriority;
\r
843 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( configMAX_PRIORITIES - ( portTickType ) uxNewPriority ) );
\r
845 /* If the task is in the blocked or suspended list we need do
\r
846 nothing more than change it's priority variable. However, if
\r
847 the task is in a ready list it needs to be removed and placed
\r
848 in the queue appropriate to its new priority. */
\r
849 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxCurrentPriority ] ), &( pxTCB->xGenericListItem ) ) )
\r
851 /* The task is currently in its ready list - remove before adding
\r
852 it to it's new ready list. As we are in a critical section we
\r
853 can do this even if the scheduler is suspended. */
\r
854 vListRemove( &( pxTCB->xGenericListItem ) );
\r
855 prvAddTaskToReadyQueue( pxTCB );
\r
858 if( xYieldRequired == pdTRUE )
\r
864 taskEXIT_CRITICAL();
\r
868 /*-----------------------------------------------------------*/
\r
870 #if ( INCLUDE_vTaskSuspend == 1 )
\r
872 void vTaskSuspend( xTaskHandle pxTaskToSuspend )
\r
876 taskENTER_CRITICAL();
\r
878 /* Ensure a yield is performed if the current task is being
\r
880 if( pxTaskToSuspend == pxCurrentTCB )
\r
882 pxTaskToSuspend = NULL;
\r
885 /* If null is passed in here then we are suspending ourselves. */
\r
886 pxTCB = prvGetTCBFromHandle( pxTaskToSuspend );
\r
888 traceTASK_SUSPEND( pxTaskToSuspend );
\r
890 /* Remove task from the ready/delayed list and place in the suspended list. */
\r
891 vListRemove( &( pxTCB->xGenericListItem ) );
\r
893 /* Is the task waiting on an event also? */
\r
894 if( pxTCB->xEventListItem.pvContainer )
\r
896 vListRemove( &( pxTCB->xEventListItem ) );
\r
899 vListInsertEnd( ( xList * ) &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );
\r
901 taskEXIT_CRITICAL();
\r
903 /* We may have just suspended the current task. */
\r
904 if( ( void * ) pxTaskToSuspend == NULL )
\r
911 /*-----------------------------------------------------------*/
\r
913 #if ( INCLUDE_vTaskSuspend == 1 )
\r
915 signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask )
\r
917 portBASE_TYPE xReturn = pdFALSE;
\r
918 const tskTCB * const pxTCB = ( tskTCB * ) xTask;
\r
920 /* Is the task we are attempting to resume actually in the
\r
922 if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE )
\r
924 /* Has the task already been resumed from within an ISR? */
\r
925 if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) != pdTRUE )
\r
927 /* Is it in the suspended list because it is in the
\r
928 Suspended state? It is possible to be in the suspended
\r
929 list because it is blocked on a task with no timeout
\r
931 if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) == pdTRUE )
\r
942 /*-----------------------------------------------------------*/
\r
944 #if ( INCLUDE_vTaskSuspend == 1 )
\r
946 void vTaskResume( xTaskHandle pxTaskToResume )
\r
950 /* Remove the task from whichever list it is currently in, and place
\r
951 it in the ready list. */
\r
952 pxTCB = ( tskTCB * ) pxTaskToResume;
\r
954 /* The parameter cannot be NULL as it is impossible to resume the
\r
955 currently executing task. */
\r
956 if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
\r
958 taskENTER_CRITICAL();
\r
960 if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
\r
962 traceTASK_RESUME( pxTCB );
\r
964 /* As we are in a critical section we can access the ready
\r
965 lists even if the scheduler is suspended. */
\r
966 vListRemove( &( pxTCB->xGenericListItem ) );
\r
967 prvAddTaskToReadyQueue( pxTCB );
\r
969 /* We may have just resumed a higher priority task. */
\r
970 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
\r
972 /* This yield may not cause the task just resumed to run, but
\r
973 will leave the lists in the correct state for the next yield. */
\r
978 taskEXIT_CRITICAL();
\r
984 /*-----------------------------------------------------------*/
\r
986 #if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
\r
988 portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume )
\r
990 portBASE_TYPE xYieldRequired = pdFALSE;
\r
993 pxTCB = ( tskTCB * ) pxTaskToResume;
\r
995 if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
\r
997 traceTASK_RESUME_FROM_ISR( pxTCB );
\r
999 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
1001 xYieldRequired = ( pxTCB->uxPriority >= pxCurrentTCB->uxPriority );
\r
1002 vListRemove( &( pxTCB->xGenericListItem ) );
\r
1003 prvAddTaskToReadyQueue( pxTCB );
\r
1007 /* We cannot access the delayed or ready lists, so will hold this
\r
1008 task pending until the scheduler is resumed, at which point a
\r
1009 yield will be performed if necessary. */
\r
1010 vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
\r
1014 return xYieldRequired;
\r
1022 /*-----------------------------------------------------------
\r
1023 * PUBLIC SCHEDULER CONTROL documented in task.h
\r
1024 *----------------------------------------------------------*/
\r
1027 void vTaskStartScheduler( void )
\r
1029 portBASE_TYPE xReturn;
\r
1031 /* Add the idle task at the lowest priority. */
\r
1032 xReturn = xTaskCreate( prvIdleTask, ( signed portCHAR * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );
\r
1034 if( xReturn == pdPASS )
\r
1036 /* Interrupts are turned off here, to ensure a tick does not occur
\r
1037 before or during the call to xPortStartScheduler(). The stacks of
\r
1038 the created tasks contain a status word with interrupts switched on
\r
1039 so interrupts will automatically get re-enabled when the first task
\r
1042 STEPPING THROUGH HERE USING A DEBUGGER CAN CAUSE BIG PROBLEMS IF THE
\r
1043 DEBUGGER ALLOWS INTERRUPTS TO BE PROCESSED. */
\r
1044 portDISABLE_INTERRUPTS();
\r
1046 xSchedulerRunning = pdTRUE;
\r
1047 xTickCount = ( portTickType ) 0;
\r
1049 /* Setting up the timer tick is hardware specific and thus in the
\r
1050 portable interface. */
\r
1051 if( xPortStartScheduler() )
\r
1053 /* Should not reach here as if the scheduler is running the
\r
1054 function will not return. */
\r
1058 /* Should only reach here if a task calls xTaskEndScheduler(). */
\r
1062 /*-----------------------------------------------------------*/
\r
1064 void vTaskEndScheduler( void )
\r
1066 /* Stop the scheduler interrupts and call the portable scheduler end
\r
1067 routine so the original ISRs can be restored if necessary. The port
\r
1068 layer must ensure interrupts enable bit is left in the correct state. */
\r
1069 portDISABLE_INTERRUPTS();
\r
1070 xSchedulerRunning = pdFALSE;
\r
1071 vPortEndScheduler();
\r
1073 /*----------------------------------------------------------*/
\r
1075 void vTaskSuspendAll( void )
\r
1077 portENTER_CRITICAL();
\r
1078 ++uxSchedulerSuspended;
\r
1079 portEXIT_CRITICAL();
\r
1081 /*----------------------------------------------------------*/
\r
1083 signed portBASE_TYPE xTaskResumeAll( void )
\r
1085 register tskTCB *pxTCB;
\r
1086 signed portBASE_TYPE xAlreadyYielded = pdFALSE;
\r
1088 /* It is possible that an ISR caused a task to be removed from an event
\r
1089 list while the scheduler was suspended. If this was the case then the
\r
1090 removed task will have been added to the xPendingReadyList. Once the
\r
1091 scheduler has been resumed it is safe to move all the pending ready
\r
1092 tasks from this list into their appropriate ready list. */
\r
1093 portENTER_CRITICAL();
\r
1095 --uxSchedulerSuspended;
\r
1097 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
1099 if( uxCurrentNumberOfTasks > ( unsigned portBASE_TYPE ) 0 )
\r
1101 portBASE_TYPE xYieldRequired = pdFALSE;
\r
1103 /* Move any readied tasks from the pending list into the
\r
1104 appropriate ready list. */
\r
1105 while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xPendingReadyList ) ) ) != NULL )
\r
1107 vListRemove( &( pxTCB->xEventListItem ) );
\r
1108 vListRemove( &( pxTCB->xGenericListItem ) );
\r
1109 prvAddTaskToReadyQueue( pxTCB );
\r
1111 /* If we have moved a task that has a priority higher than
\r
1112 the current task then we should yield. */
\r
1113 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
\r
1115 xYieldRequired = pdTRUE;
\r
1119 /* If any ticks occurred while the scheduler was suspended then
\r
1120 they should be processed now. This ensures the tick count does not
\r
1121 slip, and that any delayed tasks are resumed at the correct time. */
\r
1122 if( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
\r
1124 while( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
\r
1126 vTaskIncrementTick();
\r
1130 /* As we have processed some ticks it is appropriate to yield
\r
1131 to ensure the highest priority task that is ready to run is
\r
1132 the task actually running. */
\r
1133 #if configUSE_PREEMPTION == 1
\r
1135 xYieldRequired = pdTRUE;
\r
1140 if( ( xYieldRequired == pdTRUE ) || ( xMissedYield == pdTRUE ) )
\r
1142 xAlreadyYielded = pdTRUE;
\r
1143 xMissedYield = pdFALSE;
\r
1149 portEXIT_CRITICAL();
\r
1151 return xAlreadyYielded;
\r
1159 /*-----------------------------------------------------------
\r
1160 * PUBLIC TASK UTILITIES documented in task.h
\r
1161 *----------------------------------------------------------*/
\r
1165 portTickType xTaskGetTickCount( void )
\r
1167 portTickType xTicks;
\r
1169 /* Critical section required if running on a 16 bit processor. */
\r
1170 taskENTER_CRITICAL();
\r
1172 xTicks = xTickCount;
\r
1174 taskEXIT_CRITICAL();
\r
1178 /*-----------------------------------------------------------*/
\r
1180 unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void )
\r
1182 unsigned portBASE_TYPE uxNumberOfTasks;
\r
1184 taskENTER_CRITICAL();
\r
1185 uxNumberOfTasks = uxCurrentNumberOfTasks;
\r
1186 taskEXIT_CRITICAL();
\r
1188 return uxNumberOfTasks;
\r
1190 /*-----------------------------------------------------------*/
\r
1192 #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_vTaskDelete == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
\r
1194 void vTaskList( signed portCHAR *pcWriteBuffer )
\r
1196 unsigned portBASE_TYPE uxQueue;
\r
1198 /* This is a VERY costly function that should be used for debug only.
\r
1199 It leaves interrupts disabled for a LONG time. */
\r
1201 vTaskSuspendAll();
\r
1203 /* Run through all the lists that could potentially contain a TCB and
\r
1204 report the task name, state and stack high water mark. */
\r
1206 pcWriteBuffer[ 0 ] = ( signed portCHAR ) 0x00;
\r
1207 strcat( ( portCHAR * ) pcWriteBuffer, ( const portCHAR * ) "\r\n" );
\r
1209 uxQueue = uxTopUsedPriority + 1;
\r
1215 if( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) )
\r
1217 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), tskREADY_CHAR );
\r
1219 }while( uxQueue > ( unsigned portSHORT ) tskIDLE_PRIORITY );
\r
1221 if( !listLIST_IS_EMPTY( pxDelayedTaskList ) )
\r
1223 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, tskBLOCKED_CHAR );
\r
1226 if( !listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) )
\r
1228 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, tskBLOCKED_CHAR );
\r
1231 if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) )
\r
1233 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, tskDELETED_CHAR );
\r
1236 if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
\r
1238 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, tskSUSPENDED_CHAR );
\r
1245 /*----------------------------------------------------------*/
\r
1247 #if ( configUSE_TRACE_FACILITY == 1 )
\r
1249 void vTaskStartTrace( signed portCHAR * pcBuffer, unsigned portLONG ulBufferSize )
\r
1251 portENTER_CRITICAL();
\r
1253 pcTraceBuffer = ( signed portCHAR * )pcBuffer;
\r
1254 pcTraceBufferStart = pcBuffer;
\r
1255 pcTraceBufferEnd = pcBuffer + ( ulBufferSize - tskSIZE_OF_EACH_TRACE_LINE );
\r
1256 xTracing = pdTRUE;
\r
1258 portEXIT_CRITICAL();
\r
1262 /*----------------------------------------------------------*/
\r
1264 #if ( configUSE_TRACE_FACILITY == 1 )
\r
1266 unsigned portLONG ulTaskEndTrace( void )
\r
1268 unsigned portLONG ulBufferLength;
\r
1270 portENTER_CRITICAL();
\r
1271 xTracing = pdFALSE;
\r
1272 portEXIT_CRITICAL();
\r
1274 ulBufferLength = ( unsigned portLONG ) ( pcTraceBuffer - pcTraceBufferStart );
\r
1276 return ulBufferLength;
\r
1283 /*-----------------------------------------------------------
\r
1284 * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES
\r
1285 * documented in task.h
\r
1286 *----------------------------------------------------------*/
\r
1289 void vTaskIncrementTick( void )
\r
1291 /* Called by the portable layer each time a tick interrupt occurs.
\r
1292 Increments the tick then checks to see if the new tick value will cause any
\r
1293 tasks to be unblocked. */
\r
1294 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
1297 if( xTickCount == ( portTickType ) 0 )
\r
1301 /* Tick count has overflowed so we need to swap the delay lists.
\r
1302 If there are any items in pxDelayedTaskList here then there is
\r
1304 pxTemp = pxDelayedTaskList;
\r
1305 pxDelayedTaskList = pxOverflowDelayedTaskList;
\r
1306 pxOverflowDelayedTaskList = pxTemp;
\r
1307 xNumOfOverflows++;
\r
1310 /* See if this tick has made a timeout expire. */
\r
1311 prvCheckDelayedTasks();
\r
1317 /* The tick hook gets called at regular intervals, even if the
\r
1318 scheduler is locked. */
\r
1319 #if ( configUSE_TICK_HOOK == 1 )
\r
1321 extern void vApplicationTickHook( void );
\r
1323 vApplicationTickHook();
\r
1328 #if ( configUSE_TICK_HOOK == 1 )
\r
1330 extern void vApplicationTickHook( void );
\r
1332 /* Guard against the tick hook being called when the missed tick
\r
1333 count is being unwound (when the scheduler is being unlocked. */
\r
1334 if( uxMissedTicks == 0 )
\r
1336 vApplicationTickHook();
\r
1341 traceTASK_INCREMENT_TICK( xTickCount );
\r
1343 /*-----------------------------------------------------------*/
\r
1345 #if ( ( INCLUDE_vTaskCleanUpResources == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
\r
1347 void vTaskCleanUpResources( void )
\r
1349 unsigned portSHORT usQueue;
\r
1350 volatile tskTCB *pxTCB;
\r
1352 usQueue = ( unsigned portSHORT ) uxTopUsedPriority + ( unsigned portSHORT ) 1;
\r
1354 /* Remove any TCB's from the ready queues. */
\r
1359 while( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ usQueue ] ) ) )
\r
1361 listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &( pxReadyTasksLists[ usQueue ] ) );
\r
1362 vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
\r
1364 prvDeleteTCB( ( tskTCB * ) pxTCB );
\r
1366 }while( usQueue > ( unsigned portSHORT ) tskIDLE_PRIORITY );
\r
1368 /* Remove any TCB's from the delayed queue. */
\r
1369 while( !listLIST_IS_EMPTY( &xDelayedTaskList1 ) )
\r
1371 listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList1 );
\r
1372 vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
\r
1374 prvDeleteTCB( ( tskTCB * ) pxTCB );
\r
1377 /* Remove any TCB's from the overflow delayed queue. */
\r
1378 while( !listLIST_IS_EMPTY( &xDelayedTaskList2 ) )
\r
1380 listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList2 );
\r
1381 vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
\r
1383 prvDeleteTCB( ( tskTCB * ) pxTCB );
\r
1386 while( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
\r
1388 listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xSuspendedTaskList );
\r
1389 vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
\r
1391 prvDeleteTCB( ( tskTCB * ) pxTCB );
\r
1396 /*-----------------------------------------------------------*/
\r
1398 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
1400 void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxTagValue )
\r
1404 /* If xTask is NULL then we are setting our own task hook. */
\r
1405 if( xTask == NULL )
\r
1407 xTCB = ( tskTCB * ) pxCurrentTCB;
\r
1411 xTCB = ( tskTCB * ) xTask;
\r
1414 /* Save the hook function in the TCB. */
\r
1415 portENTER_CRITICAL();
\r
1416 xTCB->pxTaskTag = pxTagValue;
\r
1417 portEXIT_CRITICAL();
\r
1421 /*-----------------------------------------------------------*/
\r
1423 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
1425 portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParameter )
\r
1428 portBASE_TYPE xReturn;
\r
1430 /* If xTask is NULL then we are calling our own task hook. */
\r
1431 if( xTask == NULL )
\r
1433 xTCB = ( tskTCB * ) pxCurrentTCB;
\r
1437 xTCB = ( tskTCB * ) xTask;
\r
1440 if( xTCB->pxTaskTag != NULL )
\r
1442 xReturn = xTCB->pxTaskTag( pvParameter );
\r
1453 /*-----------------------------------------------------------*/
\r
1455 void vTaskSwitchContext( void )
\r
1457 traceTASK_SWITCHED_OUT();
\r
1459 if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )
\r
1461 /* The scheduler is currently suspended - do not allow a context
\r
1463 xMissedYield = pdTRUE;
\r
1467 taskCHECK_FOR_STACK_OVERFLOW();
\r
1469 /* Find the highest priority queue that contains ready tasks. */
\r
1470 while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) )
\r
1472 --uxTopReadyPriority;
\r
1475 /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the tasks of the
\r
1476 same priority get an equal share of the processor time. */
\r
1477 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) );
\r
1479 traceTASK_SWITCHED_IN();
\r
1480 vWriteTraceToBuffer();
\r
1482 /*-----------------------------------------------------------*/
\r
1484 void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait )
\r
1486 portTickType xTimeToWake;
\r
1488 /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
\r
1489 SCHEDULER SUSPENDED. */
\r
1491 /* Place the event list item of the TCB in the appropriate event list.
\r
1492 This is placed in the list in priority order so the highest priority task
\r
1493 is the first to be woken by the event. */
\r
1494 vListInsert( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );
\r
1496 /* We must remove ourselves from the ready list before adding ourselves
\r
1497 to the blocked list as the same list item is used for both lists. We have
\r
1498 exclusive access to the ready lists as the scheduler is locked. */
\r
1499 vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
1502 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1504 if( xTicksToWait == portMAX_DELAY )
\r
1506 /* Add ourselves to the suspended task list instead of a delayed task
\r
1507 list to ensure we are not woken by a timing event. We will block
\r
1509 vListInsertEnd( ( xList * ) &xSuspendedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
1513 /* Calculate the time at which the task should be woken if the event does
\r
1514 not occur. This may overflow but this doesn't matter. */
\r
1515 xTimeToWake = xTickCount + xTicksToWait;
\r
1517 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
\r
1519 if( xTimeToWake < xTickCount )
\r
1521 /* Wake time has overflowed. Place this item in the overflow list. */
\r
1522 vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
1526 /* The wake time has not overflowed, so we can use the current block list. */
\r
1527 vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
1533 /* Calculate the time at which the task should be woken if the event does
\r
1534 not occur. This may overflow but this doesn't matter. */
\r
1535 xTimeToWake = xTickCount + xTicksToWait;
\r
1537 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
\r
1539 if( xTimeToWake < xTickCount )
\r
1541 /* Wake time has overflowed. Place this item in the overflow list. */
\r
1542 vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
1546 /* The wake time has not overflowed, so we can use the current block list. */
\r
1547 vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
1552 /*-----------------------------------------------------------*/
\r
1554 signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList )
\r
1556 tskTCB *pxUnblockedTCB;
\r
1557 portBASE_TYPE xReturn;
\r
1559 /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
\r
1560 SCHEDULER SUSPENDED. It can also be called from within an ISR. */
\r
1562 /* The event list is sorted in priority order, so we can remove the
\r
1563 first in the list, remove the TCB from the delayed list, and add
\r
1564 it to the ready list.
\r
1566 If an event is for a queue that is locked then this function will never
\r
1567 get called - the lock count on the queue will get modified instead. This
\r
1568 means we can always expect exclusive access to the event list here. */
\r
1569 pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
\r
1570 vListRemove( &( pxUnblockedTCB->xEventListItem ) );
\r
1572 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
1574 vListRemove( &( pxUnblockedTCB->xGenericListItem ) );
\r
1575 prvAddTaskToReadyQueue( pxUnblockedTCB );
\r
1579 /* We cannot access the delayed or ready lists, so will hold this
\r
1580 task pending until the scheduler is resumed. */
\r
1581 vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );
\r
1584 if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority )
\r
1586 /* Return true if the task removed from the event list has
\r
1587 a higher priority than the calling task. This allows
\r
1588 the calling task to know if it should force a context
\r
1594 xReturn = pdFALSE;
\r
1599 /*-----------------------------------------------------------*/
\r
1601 void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut )
\r
1603 pxTimeOut->xOverflowCount = xNumOfOverflows;
\r
1604 pxTimeOut->xTimeOnEntering = xTickCount;
\r
1606 /*-----------------------------------------------------------*/
\r
1608 portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait )
\r
1610 portBASE_TYPE xReturn;
\r
1612 portENTER_CRITICAL();
\r
1614 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1615 /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is
\r
1616 the maximum block time then the task should block indefinitely, and
\r
1617 therefore never time out. */
\r
1618 if( *pxTicksToWait == portMAX_DELAY )
\r
1620 xReturn = pdFALSE;
\r
1622 else /* We are not blocking indefinitely, perform the checks below. */
\r
1625 if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( xTickCount >= pxTimeOut->xTimeOnEntering ) )
\r
1627 /* The tick count is greater than the time at which vTaskSetTimeout()
\r
1628 was called, but has also overflowed since vTaskSetTimeOut() was called.
\r
1629 It must have wrapped all the way around and gone past us again. This
\r
1630 passed since vTaskSetTimeout() was called. */
\r
1633 else if( ( xTickCount - pxTimeOut->xTimeOnEntering ) < *pxTicksToWait )
\r
1635 /* Not a genuine timeout. Adjust parameters for time remaining. */
\r
1636 *pxTicksToWait -= ( xTickCount - pxTimeOut->xTimeOnEntering );
\r
1637 vTaskSetTimeOutState( pxTimeOut );
\r
1638 xReturn = pdFALSE;
\r
1645 portEXIT_CRITICAL();
\r
1649 /*-----------------------------------------------------------*/
\r
1651 void vTaskMissedYield( void )
\r
1653 xMissedYield = pdTRUE;
\r
1657 * -----------------------------------------------------------
\r
1659 * ----------------------------------------------------------
\r
1661 * The portTASK_FUNCTION() macro is used to allow port/compiler specific
\r
1662 * language extensions. The equivalent prototype for this function is:
\r
1664 * void prvIdleTask( void *pvParameters );
\r
1667 static portTASK_FUNCTION( prvIdleTask, pvParameters )
\r
1669 /* Stop warnings. */
\r
1670 ( void ) pvParameters;
\r
1674 /* See if any tasks have been deleted. */
\r
1675 prvCheckTasksWaitingTermination();
\r
1677 #if ( configUSE_PREEMPTION == 0 )
\r
1679 /* If we are not using preemption we keep forcing a task switch to
\r
1680 see if any other task has become available. If we are using
\r
1681 preemption we don't need to do this as any task becoming available
\r
1682 will automatically get the processor anyway. */
\r
1687 #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
\r
1689 /* When using preemption tasks of equal priority will be
\r
1690 timesliced. If a task that is sharing the idle priority is ready
\r
1691 to run then the idle task should yield before the end of the
\r
1694 A critical region is not required here as we are just reading from
\r
1695 the list, and an occasional incorrect value will not matter. If
\r
1696 the ready list at the idle priority contains more than one task
\r
1697 then a task other than the idle task is ready to execute. */
\r
1698 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( unsigned portBASE_TYPE ) 1 )
\r
1705 #if ( configUSE_IDLE_HOOK == 1 )
\r
1707 extern void vApplicationIdleHook( void );
\r
1709 /* Call the user defined function from within the idle task. This
\r
1710 allows the application designer to add background functionality
\r
1711 without the overhead of a separate task.
\r
1712 NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
\r
1713 CALL A FUNCTION THAT MIGHT BLOCK. */
\r
1714 vApplicationIdleHook();
\r
1718 } /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */
\r
1726 /*-----------------------------------------------------------
\r
1727 * File private functions documented at the top of the file.
\r
1728 *----------------------------------------------------------*/
\r
1732 static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed portCHAR * const pcName, unsigned portBASE_TYPE uxPriority )
\r
1734 /* Store the function name in the TCB. */
\r
1735 strncpy( ( char * ) pxTCB->pcTaskName, ( const char * ) pcName, ( unsigned portSHORT ) configMAX_TASK_NAME_LEN );
\r
1736 pxTCB->pcTaskName[ ( unsigned portSHORT ) configMAX_TASK_NAME_LEN - ( unsigned portSHORT ) 1 ] = '\0';
\r
1738 /* This is used as an array index so must ensure it's not too large. */
\r
1739 if( uxPriority >= configMAX_PRIORITIES )
\r
1741 uxPriority = configMAX_PRIORITIES - 1;
\r
1744 pxTCB->uxPriority = uxPriority;
\r
1745 #if ( configUSE_MUTEXES == 1 )
\r
1747 pxTCB->uxBasePriority = uxPriority;
\r
1751 vListInitialiseItem( &( pxTCB->xGenericListItem ) );
\r
1752 vListInitialiseItem( &( pxTCB->xEventListItem ) );
\r
1754 /* Set the pxTCB as a link back from the xListItem. This is so we can get
\r
1755 back to the containing TCB from a generic item in a list. */
\r
1756 listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB );
\r
1758 /* Event lists are always in priority order. */
\r
1759 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );
\r
1760 listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB );
\r
1762 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
\r
1764 pxTCB->uxCriticalNesting = ( unsigned portBASE_TYPE ) 0;
\r
1768 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
1770 pxTCB->pxTaskTag = NULL;
\r
1774 /*-----------------------------------------------------------*/
\r
1776 static void prvInitialiseTaskLists( void )
\r
1778 unsigned portBASE_TYPE uxPriority;
\r
1780 for( uxPriority = 0; uxPriority < configMAX_PRIORITIES; uxPriority++ )
\r
1782 vListInitialise( ( xList * ) &( pxReadyTasksLists[ uxPriority ] ) );
\r
1785 vListInitialise( ( xList * ) &xDelayedTaskList1 );
\r
1786 vListInitialise( ( xList * ) &xDelayedTaskList2 );
\r
1787 vListInitialise( ( xList * ) &xPendingReadyList );
\r
1789 #if ( INCLUDE_vTaskDelete == 1 )
\r
1791 vListInitialise( ( xList * ) &xTasksWaitingTermination );
\r
1795 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1797 vListInitialise( ( xList * ) &xSuspendedTaskList );
\r
1801 /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
\r
1803 pxDelayedTaskList = &xDelayedTaskList1;
\r
1804 pxOverflowDelayedTaskList = &xDelayedTaskList2;
\r
1806 /*-----------------------------------------------------------*/
\r
1808 static void prvCheckTasksWaitingTermination( void )
\r
1810 #if ( INCLUDE_vTaskDelete == 1 )
\r
1812 portBASE_TYPE xListIsEmpty;
\r
1814 /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
\r
1815 too often in the idle task. */
\r
1816 if( uxTasksDeleted > ( unsigned portBASE_TYPE ) 0 )
\r
1818 vTaskSuspendAll();
\r
1819 xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
\r
1822 if( !xListIsEmpty )
\r
1826 portENTER_CRITICAL();
\r
1828 pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xTasksWaitingTermination ) );
\r
1829 vListRemove( &( pxTCB->xGenericListItem ) );
\r
1830 --uxCurrentNumberOfTasks;
\r
1833 portEXIT_CRITICAL();
\r
1835 prvDeleteTCB( pxTCB );
\r
1841 /*-----------------------------------------------------------*/
\r
1843 static tskTCB *prvAllocateTCBAndStack( unsigned portSHORT usStackDepth )
\r
1847 /* Allocate space for the TCB. Where the memory comes from depends on
\r
1848 the implementation of the port malloc function. */
\r
1849 pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) );
\r
1851 if( pxNewTCB != NULL )
\r
1853 /* Allocate space for the stack used by the task being created.
\r
1854 The base of the stack memory stored in the TCB so the task can
\r
1855 be deleted later if required. */
\r
1856 pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMalloc( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) );
\r
1858 if( pxNewTCB->pxStack == NULL )
\r
1860 /* Could not allocate the stack. Delete the allocated TCB. */
\r
1861 vPortFree( pxNewTCB );
\r
1866 /* Just to help debugging. */
\r
1867 memset( pxNewTCB->pxStack, tskSTACK_FILL_BYTE, usStackDepth * sizeof( portSTACK_TYPE ) );
\r
1873 /*-----------------------------------------------------------*/
\r
1875 #if ( configUSE_TRACE_FACILITY == 1 )
\r
1877 static void prvListTaskWithinSingleList( const signed portCHAR *pcWriteBuffer, xList *pxList, signed portCHAR cStatus )
\r
1879 volatile tskTCB *pxNextTCB, *pxFirstTCB;
\r
1880 unsigned portSHORT usStackRemaining;
\r
1882 /* Write the details of all the TCB's in pxList into the buffer. */
\r
1883 listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
\r
1886 listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
\r
1887 usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned portCHAR * ) pxNextTCB->pxStack );
\r
1888 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
1889 strcat( ( portCHAR * ) pcWriteBuffer, ( portCHAR * ) pcStatusString );
\r
1891 } while( pxNextTCB != pxFirstTCB );
\r
1895 /*-----------------------------------------------------------*/
\r
1897 #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
\r
1899 unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR * pucStackByte )
\r
1901 register unsigned portSHORT usCount = 0;
\r
1903 while( *pucStackByte == tskSTACK_FILL_BYTE )
\r
1905 pucStackByte -= portSTACK_GROWTH;
\r
1909 usCount /= sizeof( portSTACK_TYPE );
\r
1915 /*-----------------------------------------------------------*/
\r
1917 #if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )
\r
1919 unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask )
\r
1923 pxTCB = prvGetTCBFromHandle( xTask );
\r
1924 return usTaskCheckFreeStackSpace( ( unsigned portCHAR * ) pxTCB->pxStack );
\r
1928 /*-----------------------------------------------------------*/
\r
1930 #if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
\r
1932 static void prvDeleteTCB( tskTCB *pxTCB )
\r
1934 /* Free up the memory allocated by the scheduler for the task. It is up to
\r
1935 the task to free any memory allocated at the application level. */
\r
1936 vPortFree( pxTCB->pxStack );
\r
1937 vPortFree( pxTCB );
\r
1943 /*-----------------------------------------------------------*/
\r
1945 #if ( INCLUDE_xTaskGetCurrentTaskHandle == 1 )
\r
1947 xTaskHandle xTaskGetCurrentTaskHandle( void )
\r
1949 xTaskHandle xReturn;
\r
1951 portENTER_CRITICAL();
\r
1953 xReturn = ( xTaskHandle ) pxCurrentTCB;
\r
1955 portEXIT_CRITICAL();
\r
1962 /*-----------------------------------------------------------*/
\r
1964 #if ( INCLUDE_xTaskGetSchedulerState == 1 )
\r
1966 portBASE_TYPE xTaskGetSchedulerState( void )
\r
1968 portBASE_TYPE xReturn;
\r
1970 if( xSchedulerRunning == pdFALSE )
\r
1972 xReturn = taskSCHEDULER_NOT_STARTED;
\r
1976 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
1978 xReturn = taskSCHEDULER_RUNNING;
\r
1982 xReturn = taskSCHEDULER_SUSPENDED;
\r
1990 /*-----------------------------------------------------------*/
\r
1992 #if ( configUSE_MUTEXES == 1 )
\r
1994 void vTaskPriorityInherit( xTaskHandle * const pxMutexHolder )
\r
1996 tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
\r
1998 if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )
\r
2000 /* Adjust the mutex holder state to account for its new priority. */
\r
2001 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxCurrentTCB->uxPriority );
\r
2003 /* If the task being modified is in the ready state it will need to
\r
2004 be moved in to a new list. */
\r
2005 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) )
\r
2007 vListRemove( &( pxTCB->xGenericListItem ) );
\r
2009 /* Inherit the priority before being moved into the new list. */
\r
2010 pxTCB->uxPriority = pxCurrentTCB->uxPriority;
\r
2011 prvAddTaskToReadyQueue( pxTCB );
\r
2015 /* Just inherit the priority. */
\r
2016 pxTCB->uxPriority = pxCurrentTCB->uxPriority;
\r
2022 /*-----------------------------------------------------------*/
\r
2024 #if ( configUSE_MUTEXES == 1 )
\r
2026 void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder )
\r
2028 tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
\r
2030 if( pxMutexHolder != NULL )
\r
2032 if( pxTCB->uxPriority != pxTCB->uxBasePriority )
\r
2034 /* We must be the running task to be able to give the mutex back.
\r
2035 Remove ourselves from the ready list we currently appear in. */
\r
2036 vListRemove( &( pxTCB->xGenericListItem ) );
\r
2038 /* Disinherit the priority before adding ourselves into the new
\r
2040 pxTCB->uxPriority = pxTCB->uxBasePriority;
\r
2041 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxTCB->uxPriority );
\r
2042 prvAddTaskToReadyQueue( pxTCB );
\r
2048 /*-----------------------------------------------------------*/
\r
2050 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
\r
2052 void vTaskEnterCritical( void )
\r
2054 portDISABLE_INTERRUPTS();
\r
2056 if( xSchedulerRunning != pdFALSE )
\r
2058 pxCurrentTCB->uxCriticalNesting++;
\r
2063 /*-----------------------------------------------------------*/
\r
2065 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
\r
2067 void vTaskExitCritical( void )
\r
2069 if( xSchedulerRunning != pdFALSE )
\r
2071 if( pxCurrentTCB->uxCriticalNesting > 0 )
\r
2073 pxCurrentTCB->uxCriticalNesting--;
\r
2075 if( pxCurrentTCB->uxCriticalNesting == 0 )
\r
2077 portENABLE_INTERRUPTS();
\r
2084 /*-----------------------------------------------------------*/
\r