blob: 37beb15cfc59eaeb457cd67c3da5ea2ee9ea58af [file] [log] [blame]
Richard Barryb6df57c2006-05-02 09:39:15 +00001/*
Richard Barry7818ed52009-06-21 19:07:47 +00002 FreeRTOS.org V5.3.1 - Copyright (C) 2003-2009 Richard Barry.
Richard Barryb6df57c2006-05-02 09:39:15 +00003
Richard Barry946da762006-05-28 08:17:56 +00004 This file is part of the FreeRTOS.org distribution.
Richard Barryb6df57c2006-05-02 09:39:15 +00005
Richard Barry8b4ef532009-05-19 10:38:26 +00006 FreeRTOS.org is free software; you can redistribute it and/or modify it
Richard Barry2f40ad72009-03-14 19:20:12 +00007 under the terms of the GNU General Public License (version 2) as published
8 by the Free Software Foundation and modified by the FreeRTOS exception.
Richard Barry4bf55212009-05-30 15:51:41 +00009 **NOTE** The exception to the GPL is included to allow you to distribute a
10 combined work that includes FreeRTOS.org without being obliged to provide
11 the source code for any proprietary components. Alternative commercial
12 license and support terms are also available upon request. See the
13 licensing section of http://www.FreeRTOS.org for full details.
Richard Barryb6df57c2006-05-02 09:39:15 +000014
Richard Barry2f40ad72009-03-14 19:20:12 +000015 FreeRTOS.org is distributed in the hope that it will be useful, but WITHOUT
Richard Barry8b4ef532009-05-19 10:38:26 +000016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
Richard Barry2f40ad72009-03-14 19:20:12 +000018 more details.
Richard Barryb6df57c2006-05-02 09:39:15 +000019
Richard Barry8b4ef532009-05-19 10:38:26 +000020 You should have received a copy of the GNU General Public License along
21 with FreeRTOS.org; if not, write to the Free Software Foundation, Inc., 59
Richard Barry2f40ad72009-03-14 19:20:12 +000022 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
Richard Barryb6df57c2006-05-02 09:39:15 +000023
Richard Barry2f40ad72009-03-14 19:20:12 +000024
25 ***************************************************************************
26 * *
27 * Get the FreeRTOS eBook! See http://www.FreeRTOS.org/Documentation *
Richard Barry52ba0e62009-02-09 20:21:35 +000028 * *
29 * This is a concise, step by step, 'hands on' guide that describes both *
30 * general multitasking concepts and FreeRTOS specifics. It presents and *
31 * explains numerous examples that are written using the FreeRTOS API. *
32 * Full source code for all the examples is provided in an accompanying *
33 * .zip file. *
Richard Barry2f40ad72009-03-14 19:20:12 +000034 * *
35 ***************************************************************************
36
37 1 tab == 4 spaces!
Richard Barry0a6d59a2007-04-01 20:47:49 +000038
Richard Barry39f6b0b2008-03-03 20:56:55 +000039 Please ensure to read the configuration and relevant port sections of the
Richard Barryc86dcf72008-02-03 19:45:58 +000040 online documentation.
41
Richard Barry2f40ad72009-03-14 19:20:12 +000042 http://www.FreeRTOS.org - Documentation, latest information, license and
Richard Barry527fb6a2008-03-25 21:22:13 +000043 contact details.
Richard Barryc86dcf72008-02-03 19:45:58 +000044
Richard Barry2f40ad72009-03-14 19:20:12 +000045 http://www.SafeRTOS.com - A version that is certified for use in safety
Richard Barry527fb6a2008-03-25 21:22:13 +000046 critical systems.
Richard Barryc86dcf72008-02-03 19:45:58 +000047
Richard Barry2f40ad72009-03-14 19:20:12 +000048 http://www.OpenRTOS.com - Commercial support, development, porting,
Richard Barry527fb6a2008-03-25 21:22:13 +000049 licensing and training services.
Richard Barryb6df57c2006-05-02 09:39:15 +000050*/
51
Richard Barryb6df57c2006-05-02 09:39:15 +000052
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56
57#include "FreeRTOS.h"
58#include "task.h"
Richard Barry4f631de2008-10-09 00:53:02 +000059#include "StackMacros.h"
Richard Barryb6df57c2006-05-02 09:39:15 +000060
61/*
62 * Macro to define the amount of stack available to the idle task.
63 */
64#define tskIDLE_STACK_SIZE configMINIMAL_STACK_SIZE
65
Richard Barryb6df57c2006-05-02 09:39:15 +000066/*
Richard Barryb6df57c2006-05-02 09:39:15 +000067 * Task control block. A task control block (TCB) is allocated to each task,
68 * and stores the context of the task.
69 */
70typedef struct tskTaskControlBlock
71{
72 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. */
73 xListItem xGenericListItem; /*< List item used to place the TCB in ready and blocked queues. */
74 xListItem xEventListItem; /*< List item used to place the TCB in event lists. */
75 unsigned portBASE_TYPE uxPriority; /*< The priority of the task where 0 is the lowest priority. */
76 portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */
Richard Barryb6df57c2006-05-02 09:39:15 +000077 signed portCHAR pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */
Richard Barry60338bd2007-08-21 16:54:48 +000078
Richard Barry4f631de2008-10-09 00:53:02 +000079 #if ( portSTACK_GROWTH > 0 )
80 portSTACK_TYPE *pxEndOfStack; /*< Used for stack overflow checking on architectures where the stack grows up from low memory. */
81 #endif
82
Richard Barry2b174e52008-02-25 18:54:28 +000083 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
84 unsigned portBASE_TYPE uxCriticalNesting;
85 #endif
86
Richard Barry60338bd2007-08-21 16:54:48 +000087 #if ( configUSE_TRACE_FACILITY == 1 )
Richard Barry8b4ef532009-05-19 10:38:26 +000088 unsigned portBASE_TYPE uxTCBNumber; /*< This is used for tracing the scheduler and making debugging easier only. */
Richard Barryc66301a2009-05-21 12:23:24 +000089 #endif
90
Richard Barry60338bd2007-08-21 16:54:48 +000091 #if ( configUSE_MUTEXES == 1 )
Richard Barry8b4ef532009-05-19 10:38:26 +000092 unsigned portBASE_TYPE uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
Richard Barry60338bd2007-08-21 16:54:48 +000093 #endif
Richard Barryda6d27b2008-04-12 09:46:19 +000094
Richard Barrye9395422008-04-16 07:47:02 +000095 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
96 pdTASK_HOOK_CODE pxTaskTag;
Richard Barryda6d27b2008-04-12 09:46:19 +000097 #endif
Richard Barry8b4ef532009-05-19 10:38:26 +000098
99 #if ( configGENERATE_RUN_TIME_STATS == 1 )
100 unsigned portLONG ulRunTimeCounter; /*< Used for calculating how much CPU time each task is utilising. */
101 #endif
Richard Barryc66301a2009-05-21 12:23:24 +0000102
Richard Barryb6df57c2006-05-02 09:39:15 +0000103} tskTCB;
104
Richard Barry8ce7a792008-05-24 18:52:12 +0000105/*
106 * Some kernel aware debuggers require data to be viewed to be global, rather
107 * than file scope.
108 */
109#ifdef portREMOVE_STATIC_QUALIFIER
110 #define static
111#endif
112
Richard Barryb6df57c2006-05-02 09:39:15 +0000113/*lint -e956 */
114
Richard Barryc66301a2009-05-21 12:23:24 +0000115tskTCB * volatile pxCurrentTCB = NULL;
Richard Barryb6df57c2006-05-02 09:39:15 +0000116
117/* Lists for ready and blocked tasks. --------------------*/
118
119static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */
120static xList xDelayedTaskList1; /*< Delayed tasks. */
121static xList xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
122static xList * volatile pxDelayedTaskList; /*< Points to the delayed task list currently being used. */
123static xList * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
124static 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. */
125
126#if ( INCLUDE_vTaskDelete == 1 )
127
128 static volatile xList xTasksWaitingTermination; /*< Tasks that have been deleted - but the their memory not yet freed. */
129 static volatile unsigned portBASE_TYPE uxTasksDeleted = ( unsigned portBASE_TYPE ) 0;
130
131#endif
132
133#if ( INCLUDE_vTaskSuspend == 1 )
134
135 static xList xSuspendedTaskList; /*< Tasks that are currently suspended. */
136
137#endif
138
139/* File private variables. --------------------------------*/
140static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks = ( unsigned portBASE_TYPE ) 0;
141static volatile portTickType xTickCount = ( portTickType ) 0;
Richard Barryb18929e2006-08-27 14:09:54 +0000142static unsigned portBASE_TYPE uxTopUsedPriority = tskIDLE_PRIORITY;
Richard Barryb6df57c2006-05-02 09:39:15 +0000143static volatile unsigned portBASE_TYPE uxTopReadyPriority = tskIDLE_PRIORITY;
144static volatile signed portBASE_TYPE xSchedulerRunning = pdFALSE;
145static volatile unsigned portBASE_TYPE uxSchedulerSuspended = ( unsigned portBASE_TYPE ) pdFALSE;
146static volatile unsigned portBASE_TYPE uxMissedTicks = ( unsigned portBASE_TYPE ) 0;
147static volatile portBASE_TYPE xMissedYield = ( portBASE_TYPE ) pdFALSE;
Richard Barryb18929e2006-08-27 14:09:54 +0000148static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0;
Richard Barrya7f13492009-05-03 08:28:14 +0000149static unsigned portBASE_TYPE uxTaskNumber = ( unsigned portBASE_TYPE ) 0;
Richard Barry6eed6692008-07-30 09:34:03 +0000150
Richard Barry8b4ef532009-05-19 10:38:26 +0000151#if ( configGENERATE_RUN_TIME_STATS == 1 )
152
153 static portCHAR pcStatsString[ 50 ];
154 static unsigned portLONG ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */
155 static void prvGenerateRunTimeStatsForTasksInList( const signed portCHAR *pcWriteBuffer, xList *pxList, unsigned portLONG ulTotalRunTime );
156
157#endif
158
Richard Barryb6df57c2006-05-02 09:39:15 +0000159/* Debugging and trace facilities private variables and macros. ------------*/
160
161/*
162 * The value used to fill the stack of a task when the task is created. This
163 * is used purely for checking the high water mark for tasks.
164 */
165#define tskSTACK_FILL_BYTE ( 0xa5 )
166
167/*
168 * Macros used by vListTask to indicate which state a task is in.
169 */
170#define tskBLOCKED_CHAR ( ( signed portCHAR ) 'B' )
171#define tskREADY_CHAR ( ( signed portCHAR ) 'R' )
172#define tskDELETED_CHAR ( ( signed portCHAR ) 'D' )
173#define tskSUSPENDED_CHAR ( ( signed portCHAR ) 'S' )
174
175/*
176 * Macros and private variables used by the trace facility.
177 */
178#if ( configUSE_TRACE_FACILITY == 1 )
179
180 #define tskSIZE_OF_EACH_TRACE_LINE ( ( unsigned portLONG ) ( sizeof( unsigned portLONG ) + sizeof( unsigned portLONG ) ) )
181 static volatile signed portCHAR * volatile pcTraceBuffer;
182 static signed portCHAR *pcTraceBufferStart;
183 static signed portCHAR *pcTraceBufferEnd;
184 static signed portBASE_TYPE xTracing = pdFALSE;
Richard Barry6eed6692008-07-30 09:34:03 +0000185 static unsigned portBASE_TYPE uxPreviousTask = 255;
186 static portCHAR pcStatusString[ 50 ];
Richard Barry8b4ef532009-05-19 10:38:26 +0000187
Richard Barryb6df57c2006-05-02 09:39:15 +0000188#endif
189
Richard Barry39f6b0b2008-03-03 20:56:55 +0000190/*-----------------------------------------------------------*/
191
Richard Barryb6df57c2006-05-02 09:39:15 +0000192/*
193 * Macro that writes a trace of scheduler activity to a buffer. This trace
194 * shows which task is running when and is very useful as a debugging tool.
195 * As this macro is called each context switch it is a good idea to undefine
196 * it if not using the facility.
197 */
198#if ( configUSE_TRACE_FACILITY == 1 )
199
Richard Barryd481cff2006-07-03 19:34:28 +0000200 #define vWriteTraceToBuffer() \
201 { \
202 if( xTracing ) \
203 { \
Richard Barryd481cff2006-07-03 19:34:28 +0000204 if( uxPreviousTask != pxCurrentTCB->uxTCBNumber ) \
205 { \
206 if( ( pcTraceBuffer + tskSIZE_OF_EACH_TRACE_LINE ) < pcTraceBufferEnd ) \
207 { \
208 uxPreviousTask = pxCurrentTCB->uxTCBNumber; \
Richard Barryb6df57c2006-05-02 09:39:15 +0000209 *( unsigned portLONG * ) pcTraceBuffer = ( unsigned portLONG ) xTickCount; \
Richard Barryd481cff2006-07-03 19:34:28 +0000210 pcTraceBuffer += sizeof( unsigned portLONG ); \
Richard Barryb6df57c2006-05-02 09:39:15 +0000211 *( unsigned portLONG * ) pcTraceBuffer = ( unsigned portLONG ) uxPreviousTask; \
Richard Barryd481cff2006-07-03 19:34:28 +0000212 pcTraceBuffer += sizeof( unsigned portLONG ); \
213 } \
214 else \
215 { \
216 xTracing = pdFALSE; \
217 } \
218 } \
219 } \
Richard Barryb6df57c2006-05-02 09:39:15 +0000220 }
221
222#else
223
224 #define vWriteTraceToBuffer()
225
226#endif
Richard Barry39f6b0b2008-03-03 20:56:55 +0000227/*-----------------------------------------------------------*/
Richard Barryb6df57c2006-05-02 09:39:15 +0000228
229/*
230 * Place the task represented by pxTCB into the appropriate ready queue for
231 * the task. It is inserted at the end of the list. One quirk of this is
232 * that if the task being inserted is at the same priority as the currently
233 * executing task, then it will only be rescheduled after the currently
234 * executing task has been rescheduled.
235 */
236#define prvAddTaskToReadyQueue( pxTCB ) \
237{ \
238 if( pxTCB->uxPriority > uxTopReadyPriority ) \
239 { \
240 uxTopReadyPriority = pxTCB->uxPriority; \
241 } \
242 vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ); \
Richard Barry39f6b0b2008-03-03 20:56:55 +0000243}
Richard Barryc66301a2009-05-21 12:23:24 +0000244/*-----------------------------------------------------------*/
Richard Barryb6df57c2006-05-02 09:39:15 +0000245
246/*
247 * Macro that looks at the list of tasks that are currently delayed to see if
248 * any require waking.
249 *
250 * Tasks are stored in the queue in the order of their wake time - meaning
251 * once one tasks has been found whose timer has not expired we need not look
252 * any further down the list.
253 */
Richard Barryd481cff2006-07-03 19:34:28 +0000254#define prvCheckDelayedTasks() \
255{ \
256register tskTCB *pxTCB; \
257 \
258 while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ) ) != NULL ) \
259 { \
260 if( xTickCount < listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ) ) \
261 { \
262 break; \
263 } \
264 vListRemove( &( pxTCB->xGenericListItem ) ); \
265 /* Is the task waiting on an event also? */ \
266 if( pxTCB->xEventListItem.pvContainer ) \
267 { \
268 vListRemove( &( pxTCB->xEventListItem ) ); \
269 } \
Richard Barry39f6b0b2008-03-03 20:56:55 +0000270 prvAddTaskToReadyQueue( pxTCB ); \
Richard Barryd481cff2006-07-03 19:34:28 +0000271 } \
Richard Barry39f6b0b2008-03-03 20:56:55 +0000272}
273/*-----------------------------------------------------------*/
274
275/*
Richard Barryb6df57c2006-05-02 09:39:15 +0000276 * Several functions take an xTaskHandle parameter that can optionally be NULL,
277 * where NULL is used to indicate that the handle of the currently executing
278 * task should be used in place of the parameter. This macro simply checks to
279 * see if the parameter is NULL and returns a pointer to the appropriate TCB.
280 */
281#define prvGetTCBFromHandle( pxHandle ) ( ( pxHandle == NULL ) ? ( tskTCB * ) pxCurrentTCB : ( tskTCB * ) pxHandle )
282
283
284/* File private functions. --------------------------------*/
285
286/*
287 * Utility to ready a TCB for a given task. Mainly just copies the parameters
288 * into the TCB structure.
289 */
Richard Barry60338bd2007-08-21 16:54:48 +0000290static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed portCHAR * const pcName, unsigned portBASE_TYPE uxPriority );
Richard Barryb6df57c2006-05-02 09:39:15 +0000291
292/*
293 * Utility to ready all the lists used by the scheduler. This is called
294 * automatically upon the creation of the first task.
295 */
296static void prvInitialiseTaskLists( void );
297
298/*
299 * The idle task, which as all tasks is implemented as a never ending loop.
300 * The idle task is automatically created and added to the ready lists upon
301 * creation of the first user task.
302 *
303 * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific
304 * language extensions. The equivalent prototype for this function is:
305 *
306 * void prvIdleTask( void *pvParameters );
307 *
308 */
309static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters );
310
311/*
312 * Utility to free all memory allocated by the scheduler to hold a TCB,
313 * including the stack pointed to by the TCB.
314 *
315 * This does not free memory allocated by the task itself (i.e. memory
316 * allocated by calls to pvPortMalloc from within the tasks application code).
317 */
318#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
Richard Barry8b4ef532009-05-19 10:38:26 +0000319
Richard Barryb6df57c2006-05-02 09:39:15 +0000320 static void prvDeleteTCB( tskTCB *pxTCB );
Richard Barry8b4ef532009-05-19 10:38:26 +0000321
Richard Barryb6df57c2006-05-02 09:39:15 +0000322#endif
323
324/*
325 * Used only by the idle task. This checks to see if anything has been placed
326 * in the list of tasks waiting to be deleted. If so the task is cleaned up
327 * and its TCB deleted.
328 */
329static void prvCheckTasksWaitingTermination( void );
330
331/*
332 * Allocates memory from the heap for a TCB and associated stack. Checks the
333 * allocation was successful.
334 */
335static tskTCB *prvAllocateTCBAndStack( unsigned portSHORT usStackDepth );
336
337/*
338 * Called from vTaskList. vListTasks details all the tasks currently under
339 * control of the scheduler. The tasks may be in one of a number of lists.
340 * prvListTaskWithinSingleList accepts a list and details the tasks from
341 * within just that list.
342 *
343 * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM
344 * NORMAL APPLICATION CODE.
345 */
346#if ( configUSE_TRACE_FACILITY == 1 )
347
Richard Barry60338bd2007-08-21 16:54:48 +0000348 static void prvListTaskWithinSingleList( const signed portCHAR *pcWriteBuffer, xList *pxList, signed portCHAR cStatus );
Richard Barryb6df57c2006-05-02 09:39:15 +0000349
350#endif
351
352/*
353 * When a task is created, the stack of the task is filled with a known value.
354 * This function determines the 'high water mark' of the task stack by
355 * determining how much of the stack remains at the original preset value.
356 */
Richard Barry39f6b0b2008-03-03 20:56:55 +0000357#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
Richard Barryb6df57c2006-05-02 09:39:15 +0000358
Richard Barry60338bd2007-08-21 16:54:48 +0000359 unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR * pucStackByte );
Richard Barryb6df57c2006-05-02 09:39:15 +0000360
361#endif
362
Richard Barry7a8eb502007-07-28 16:33:07 +0000363
Richard Barryb6df57c2006-05-02 09:39:15 +0000364/*lint +e956 */
365
366
367
Richard Barryb6df57c2006-05-02 09:39:15 +0000368/*-----------------------------------------------------------
369 * TASK CREATION API documented in task.h
370 *----------------------------------------------------------*/
371
372signed portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode, const signed portCHAR * const pcName, unsigned portSHORT usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask )
373{
374signed portBASE_TYPE xReturn;
375tskTCB * pxNewTCB;
Richard Barryb6df57c2006-05-02 09:39:15 +0000376
377 /* Allocate the memory required by the TCB and stack for the new task.
378 checking that the allocation was successful. */
379 pxNewTCB = prvAllocateTCBAndStack( usStackDepth );
380
381 if( pxNewTCB != NULL )
Richard Barryc66301a2009-05-21 12:23:24 +0000382 {
Richard Barryb6df57c2006-05-02 09:39:15 +0000383 portSTACK_TYPE *pxTopOfStack;
384
385 /* Setup the newly allocated TCB with the initial state of the task. */
Richard Barry60338bd2007-08-21 16:54:48 +0000386 prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority );
Richard Barryb6df57c2006-05-02 09:39:15 +0000387
388 /* Calculate the top of stack address. This depends on whether the
389 stack grows from high memory to low (as per the 80x86) or visa versa.
390 portSTACK_GROWTH is used to make the result positive or negative as
391 required by the port. */
392 #if portSTACK_GROWTH < 0
393 {
Richard Barry0a9fddb2009-06-30 16:32:36 +0000394 pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 ) - ( ( usStackDepth - 1 ) % portBYTE_ALIGNMENT );
Richard Barryb6df57c2006-05-02 09:39:15 +0000395 }
396 #else
397 {
Richard Barryc66301a2009-05-21 12:23:24 +0000398 pxTopOfStack = pxNewTCB->pxStack;
Richard Barry4f631de2008-10-09 00:53:02 +0000399
400 /* If we want to use stack checking on architectures that use
401 a positive stack growth direction then we also need to store the
402 other extreme of the stack space. */
403 pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
Richard Barryb6df57c2006-05-02 09:39:15 +0000404 }
405 #endif
406
407 /* Initialize the TCB stack to look as if the task was already running,
408 but had been interrupted by the scheduler. The return address is set
409 to the start of the task function. Once the stack has been initialised
410 the top of stack variable is updated. */
411 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pvTaskCode, pvParameters );
412
413 /* We are going to manipulate the task queues to add this task to a
414 ready list, so must make sure no interrupts occur. */
415 portENTER_CRITICAL();
416 {
417 uxCurrentNumberOfTasks++;
418 if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )
419 {
420 /* As this is the first task it must also be the current task. */
421 pxCurrentTCB = pxNewTCB;
422
423 /* This is the first task to be created so do the preliminary
424 initialisation required. We will not recover if this call
425 fails, but we will report the failure. */
426 prvInitialiseTaskLists();
427 }
428 else
Richard Barryc66301a2009-05-21 12:23:24 +0000429 {
Richard Barryb6df57c2006-05-02 09:39:15 +0000430 /* If the scheduler is not already running, make this task the
431 current task if it is the highest priority task to be created
432 so far. */
433 if( xSchedulerRunning == pdFALSE )
434 {
435 if( pxCurrentTCB->uxPriority <= uxPriority )
436 {
Richard Barryc66301a2009-05-21 12:23:24 +0000437 pxCurrentTCB = pxNewTCB;
Richard Barryb6df57c2006-05-02 09:39:15 +0000438 }
439 }
Richard Barryc66301a2009-05-21 12:23:24 +0000440 }
Richard Barryb6df57c2006-05-02 09:39:15 +0000441
442 /* Remember the top priority to make context switching faster. Use
443 the priority in pxNewTCB as this has been capped to a valid value. */
444 if( pxNewTCB->uxPriority > uxTopUsedPriority )
445 {
446 uxTopUsedPriority = pxNewTCB->uxPriority;
447 }
448
Richard Barry60338bd2007-08-21 16:54:48 +0000449 #if ( configUSE_TRACE_FACILITY == 1 )
450 {
451 /* Add a counter into the TCB for tracing only. */
452 pxNewTCB->uxTCBNumber = uxTaskNumber;
Richard Barry60338bd2007-08-21 16:54:48 +0000453 }
454 #endif
Richard Barry42b60ed2009-03-14 15:04:44 +0000455 uxTaskNumber++;
Richard Barryb6df57c2006-05-02 09:39:15 +0000456
457 prvAddTaskToReadyQueue( pxNewTCB );
458
459 xReturn = pdPASS;
Richard Barryb8b70522008-03-03 16:32:05 +0000460 traceTASK_CREATE( pxNewTCB );
Richard Barryb6df57c2006-05-02 09:39:15 +0000461 }
462 portEXIT_CRITICAL();
463 }
464 else
465 {
466 xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
Richard Barryb8b70522008-03-03 16:32:05 +0000467 traceTASK_CREATE_FAILED( pxNewTCB );
Richard Barryb6df57c2006-05-02 09:39:15 +0000468 }
469
470 if( xReturn == pdPASS )
471 {
472 if( ( void * ) pxCreatedTask != NULL )
473 {
474 /* Pass the TCB out - in an anonymous way. The calling function/
475 task can use this as a handle to delete the task later if
476 required.*/
477 *pxCreatedTask = ( xTaskHandle ) pxNewTCB;
478 }
479
480 if( xSchedulerRunning != pdFALSE )
481 {
482 /* If the created task is of a higher priority than the current task
483 then it should run now. */
484 if( pxCurrentTCB->uxPriority < uxPriority )
485 {
486 taskYIELD();
487 }
488 }
489 }
490
491 return xReturn;
492}
493/*-----------------------------------------------------------*/
494
495#if ( INCLUDE_vTaskDelete == 1 )
496
497 void vTaskDelete( xTaskHandle pxTaskToDelete )
498 {
499 tskTCB *pxTCB;
500
501 taskENTER_CRITICAL();
502 {
Richard Barry39f6b0b2008-03-03 20:56:55 +0000503 /* Ensure a yield is performed if the current task is being
Richard Barry946da762006-05-28 08:17:56 +0000504 deleted. */
505 if( pxTaskToDelete == pxCurrentTCB )
506 {
507 pxTaskToDelete = NULL;
508 }
509
Richard Barryb6df57c2006-05-02 09:39:15 +0000510 /* If null is passed in here then we are deleting ourselves. */
511 pxTCB = prvGetTCBFromHandle( pxTaskToDelete );
512
Richard Barryb6df57c2006-05-02 09:39:15 +0000513 /* Remove task from the ready list and place in the termination list.
514 This will stop the task from be scheduled. The idle task will check
515 the termination list and free up any memory allocated by the
516 scheduler for the TCB and stack. */
517 vListRemove( &( pxTCB->xGenericListItem ) );
518
Richard Barryc66301a2009-05-21 12:23:24 +0000519 /* Is the task waiting on an event also? */
Richard Barryb6df57c2006-05-02 09:39:15 +0000520 if( pxTCB->xEventListItem.pvContainer )
521 {
522 vListRemove( &( pxTCB->xEventListItem ) );
523 }
524
525 vListInsertEnd( ( xList * ) &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );
526
527 /* Increment the ucTasksDeleted variable so the idle task knows
528 there is a task that has been deleted and that it should therefore
529 check the xTasksWaitingTermination list. */
530 ++uxTasksDeleted;
Richard Barry42b60ed2009-03-14 15:04:44 +0000531
532 /* Increment the uxTaskNumberVariable also so kernel aware debuggers
Richard Barryc66301a2009-05-21 12:23:24 +0000533 can detect that the task lists need re-generating. */
Richard Barry42b60ed2009-03-14 15:04:44 +0000534 uxTaskNumber++;
Richard Barry245bb812009-05-22 15:35:40 +0000535
536 traceTASK_DELETE( pxTCB );
Richard Barryb6df57c2006-05-02 09:39:15 +0000537 }
538 taskEXIT_CRITICAL();
539
540 /* Force a reschedule if we have just deleted the current task. */
Richard Barry39f6b0b2008-03-03 20:56:55 +0000541 if( xSchedulerRunning != pdFALSE )
Richard Barryb6df57c2006-05-02 09:39:15 +0000542 {
Richard Barryd481cff2006-07-03 19:34:28 +0000543 if( ( void * ) pxTaskToDelete == NULL )
544 {
545 taskYIELD();
546 }
Richard Barryb6df57c2006-05-02 09:39:15 +0000547 }
548 }
549
550#endif
551
552
553
554
555
556
557/*-----------------------------------------------------------
558 * TASK CONTROL API documented in task.h
559 *----------------------------------------------------------*/
560
561#if ( INCLUDE_vTaskDelayUntil == 1 )
562
Richard Barry60338bd2007-08-21 16:54:48 +0000563 void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement )
Richard Barryb6df57c2006-05-02 09:39:15 +0000564 {
565 portTickType xTimeToWake;
566 portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE;
567
568 vTaskSuspendAll();
569 {
570 /* Generate the tick time at which the task wants to wake. */
571 xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
572
573 if( xTickCount < *pxPreviousWakeTime )
574 {
575 /* The tick count has overflowed since this function was
576 lasted called. In this case the only time we should ever
577 actually delay is if the wake time has also overflowed,
578 and the wake time is greater than the tick time. When this
579 is the case it is as if neither time had overflowed. */
580 if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xTickCount ) )
581 {
582 xShouldDelay = pdTRUE;
583 }
584 }
585 else
586 {
587 /* The tick time has not overflowed. In this case we will
588 delay if either the wake time has overflowed, and/or the
589 tick time is less than the wake time. */
590 if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xTickCount ) )
591 {
592 xShouldDelay = pdTRUE;
593 }
594 }
595
596 /* Update the wake time ready for the next call. */
597 *pxPreviousWakeTime = xTimeToWake;
598
599 if( xShouldDelay )
600 {
Richard Barryb8b70522008-03-03 16:32:05 +0000601 traceTASK_DELAY_UNTIL();
602
Richard Barryb6df57c2006-05-02 09:39:15 +0000603 /* We must remove ourselves from the ready list before adding
604 ourselves to the blocked list as the same list item is used for
605 both lists. */
606 vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
607
608 /* The list item will be inserted in wake time order. */
609 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
610
611 if( xTimeToWake < xTickCount )
612 {
613 /* Wake time has overflowed. Place this item in the
614 overflow list. */
615 vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
616 }
617 else
618 {
619 /* The wake time has not overflowed, so we can use the
620 current block list. */
621 vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
622 }
623 }
624 }
625 xAlreadyYielded = xTaskResumeAll();
626
627 /* Force a reschedule if xTaskResumeAll has not already done so, we may
628 have put ourselves to sleep. */
629 if( !xAlreadyYielded )
630 {
631 taskYIELD();
632 }
Richard Barryc66301a2009-05-21 12:23:24 +0000633 }
634
Richard Barryb6df57c2006-05-02 09:39:15 +0000635#endif
636/*-----------------------------------------------------------*/
637
638#if ( INCLUDE_vTaskDelay == 1 )
639
640 void vTaskDelay( portTickType xTicksToDelay )
641 {
642 portTickType xTimeToWake;
643 signed portBASE_TYPE xAlreadyYielded = pdFALSE;
644
645 /* A delay time of zero just forces a reschedule. */
646 if( xTicksToDelay > ( portTickType ) 0 )
647 {
648 vTaskSuspendAll();
649 {
Richard Barryb8b70522008-03-03 16:32:05 +0000650 traceTASK_DELAY();
651
Richard Barryb6df57c2006-05-02 09:39:15 +0000652 /* A task that is removed from the event list while the
653 scheduler is suspended will not get placed in the ready
654 list or removed from the blocked list until the scheduler
655 is resumed.
Richard Barryc66301a2009-05-21 12:23:24 +0000656
Richard Barryb6df57c2006-05-02 09:39:15 +0000657 This task cannot be in an event list as it is the currently
658 executing task. */
659
660 /* Calculate the time to wake - this may overflow but this is
661 not a problem. */
662 xTimeToWake = xTickCount + xTicksToDelay;
663
664 /* We must remove ourselves from the ready list before adding
665 ourselves to the blocked list as the same list item is used for
666 both lists. */
667 vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
668
669 /* The list item will be inserted in wake time order. */
670 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
671
672 if( xTimeToWake < xTickCount )
673 {
674 /* Wake time has overflowed. Place this item in the
675 overflow list. */
676 vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
677 }
678 else
679 {
680 /* The wake time has not overflowed, so we can use the
681 current block list. */
682 vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
683 }
684 }
685 xAlreadyYielded = xTaskResumeAll();
686 }
Richard Barryc66301a2009-05-21 12:23:24 +0000687
Richard Barryb6df57c2006-05-02 09:39:15 +0000688 /* Force a reschedule if xTaskResumeAll has not already done so, we may
689 have put ourselves to sleep. */
690 if( !xAlreadyYielded )
691 {
692 taskYIELD();
693 }
694 }
Richard Barryc66301a2009-05-21 12:23:24 +0000695
Richard Barryb6df57c2006-05-02 09:39:15 +0000696#endif
697/*-----------------------------------------------------------*/
698
699#if ( INCLUDE_uxTaskPriorityGet == 1 )
700
701 unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask )
702 {
703 tskTCB *pxTCB;
704 unsigned portBASE_TYPE uxReturn;
705
706 taskENTER_CRITICAL();
707 {
708 /* If null is passed in here then we are changing the
709 priority of the calling function. */
710 pxTCB = prvGetTCBFromHandle( pxTask );
711 uxReturn = pxTCB->uxPriority;
712 }
713 taskEXIT_CRITICAL();
714
715 return uxReturn;
716 }
717
718#endif
719/*-----------------------------------------------------------*/
720
721#if ( INCLUDE_vTaskPrioritySet == 1 )
722
723 void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority )
724 {
725 tskTCB *pxTCB;
Richard Barry3dcbed52006-06-22 17:18:31 +0000726 unsigned portBASE_TYPE uxCurrentPriority, xYieldRequired = pdFALSE;
Richard Barryb6df57c2006-05-02 09:39:15 +0000727
728 /* Ensure the new priority is valid. */
729 if( uxNewPriority >= configMAX_PRIORITIES )
730 {
731 uxNewPriority = configMAX_PRIORITIES - 1;
732 }
733
734 taskENTER_CRITICAL();
735 {
Richard Barry3f620022008-05-01 17:15:36 +0000736 if( pxTask == pxCurrentTCB )
737 {
738 pxTask = NULL;
739 }
740
Richard Barryb6df57c2006-05-02 09:39:15 +0000741 /* If null is passed in here then we are changing the
742 priority of the calling function. */
743 pxTCB = prvGetTCBFromHandle( pxTask );
Richard Barryc66301a2009-05-21 12:23:24 +0000744
Richard Barryb8b70522008-03-03 16:32:05 +0000745 traceTASK_PRIORITY_SET( pxTask, uxNewPriority );
746
Richard Barry60338bd2007-08-21 16:54:48 +0000747 #if ( configUSE_MUTEXES == 1 )
748 {
749 uxCurrentPriority = pxTCB->uxBasePriority;
750 }
751 #else
752 {
753 uxCurrentPriority = pxTCB->uxPriority;
754 }
755 #endif
Richard Barryb6df57c2006-05-02 09:39:15 +0000756
757 if( uxCurrentPriority != uxNewPriority )
758 {
Richard Barry3dcbed52006-06-22 17:18:31 +0000759 /* The priority change may have readied a task of higher
760 priority than the calling task. */
Richard Barry39f6b0b2008-03-03 20:56:55 +0000761 if( uxNewPriority > uxCurrentPriority )
Richard Barry3dcbed52006-06-22 17:18:31 +0000762 {
763 if( pxTask != NULL )
764 {
765 /* The priority of another task is being raised. If we
766 were raising the priority of the currently running task
767 there would be no need to switch as it must have already
768 been the highest priority task. */
769 xYieldRequired = pdTRUE;
770 }
771 }
772 else if( pxTask == NULL )
773 {
774 /* Setting our own priority down means there may now be another
775 task of higher priority that is ready to execute. */
776 xYieldRequired = pdTRUE;
777 }
Richard Barryc66301a2009-05-21 12:23:24 +0000778
779
Richard Barry60338bd2007-08-21 16:54:48 +0000780
781 #if ( configUSE_MUTEXES == 1 )
782 {
783 /* Only change the priority being used if the task is not
784 currently using an inherited priority. */
785 if( pxTCB->uxBasePriority == pxTCB->uxPriority )
786 {
787 pxTCB->uxPriority = uxNewPriority;
788 }
Richard Barryc66301a2009-05-21 12:23:24 +0000789
Richard Barry60338bd2007-08-21 16:54:48 +0000790 /* The base priority gets set whatever. */
Richard Barryc66301a2009-05-21 12:23:24 +0000791 pxTCB->uxBasePriority = uxNewPriority;
Richard Barry60338bd2007-08-21 16:54:48 +0000792 }
793 #else
794 {
795 pxTCB->uxPriority = uxNewPriority;
796 }
797 #endif
798
Richard Barry98a99592007-09-17 10:07:48 +0000799 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( configMAX_PRIORITIES - ( portTickType ) uxNewPriority ) );
Richard Barryb6df57c2006-05-02 09:39:15 +0000800
801 /* If the task is in the blocked or suspended list we need do
802 nothing more than change it's priority variable. However, if
803 the task is in a ready list it needs to be removed and placed
804 in the queue appropriate to its new priority. */
805 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxCurrentPriority ] ), &( pxTCB->xGenericListItem ) ) )
806 {
Richard Barryd481cff2006-07-03 19:34:28 +0000807 /* The task is currently in its ready list - remove before adding
808 it to it's new ready list. As we are in a critical section we
809 can do this even if the scheduler is suspended. */
810 vListRemove( &( pxTCB->xGenericListItem ) );
811 prvAddTaskToReadyQueue( pxTCB );
Richard Barryc66301a2009-05-21 12:23:24 +0000812 }
813
Richard Barry3dcbed52006-06-22 17:18:31 +0000814 if( xYieldRequired == pdTRUE )
815 {
816 taskYIELD();
Richard Barryc66301a2009-05-21 12:23:24 +0000817 }
Richard Barryb6df57c2006-05-02 09:39:15 +0000818 }
819 }
820 taskEXIT_CRITICAL();
Richard Barryb6df57c2006-05-02 09:39:15 +0000821 }
822
823#endif
824/*-----------------------------------------------------------*/
825
826#if ( INCLUDE_vTaskSuspend == 1 )
827
828 void vTaskSuspend( xTaskHandle pxTaskToSuspend )
829 {
830 tskTCB *pxTCB;
831
832 taskENTER_CRITICAL();
833 {
Richard Barry39f6b0b2008-03-03 20:56:55 +0000834 /* Ensure a yield is performed if the current task is being
Richard Barry946da762006-05-28 08:17:56 +0000835 suspended. */
836 if( pxTaskToSuspend == pxCurrentTCB )
837 {
838 pxTaskToSuspend = NULL;
839 }
840
Richard Barryb6df57c2006-05-02 09:39:15 +0000841 /* If null is passed in here then we are suspending ourselves. */
842 pxTCB = prvGetTCBFromHandle( pxTaskToSuspend );
843
Richard Barry8b4ef532009-05-19 10:38:26 +0000844 traceTASK_SUSPEND( pxTCB );
Richard Barryb8b70522008-03-03 16:32:05 +0000845
Richard Barryb6df57c2006-05-02 09:39:15 +0000846 /* Remove task from the ready/delayed list and place in the suspended list. */
847 vListRemove( &( pxTCB->xGenericListItem ) );
848
Richard Barryc66301a2009-05-21 12:23:24 +0000849 /* Is the task waiting on an event also? */
Richard Barryb6df57c2006-05-02 09:39:15 +0000850 if( pxTCB->xEventListItem.pvContainer )
851 {
852 vListRemove( &( pxTCB->xEventListItem ) );
853 }
854
855 vListInsertEnd( ( xList * ) &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );
856 }
857 taskEXIT_CRITICAL();
858
859 /* We may have just suspended the current task. */
860 if( ( void * ) pxTaskToSuspend == NULL )
861 {
862 taskYIELD();
863 }
864 }
865
866#endif
867/*-----------------------------------------------------------*/
868
869#if ( INCLUDE_vTaskSuspend == 1 )
870
Richard Barry2888b152008-05-19 19:17:56 +0000871 signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask )
Richard Barry7a8eb502007-07-28 16:33:07 +0000872 {
873 portBASE_TYPE xReturn = pdFALSE;
Richard Barry2888b152008-05-19 19:17:56 +0000874 const tskTCB * const pxTCB = ( tskTCB * ) xTask;
Richard Barry7a8eb502007-07-28 16:33:07 +0000875
876 /* Is the task we are attempting to resume actually in the
877 suspended list? */
878 if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE )
879 {
880 /* Has the task already been resumed from within an ISR? */
881 if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) != pdTRUE )
Richard Barryc66301a2009-05-21 12:23:24 +0000882 {
Richard Barry7a8eb502007-07-28 16:33:07 +0000883 /* Is it in the suspended list because it is in the
884 Suspended state? It is possible to be in the suspended
885 list because it is blocked on a task with no timeout
886 specified. */
Richard Barrya06a2e42007-07-28 18:41:53 +0000887 if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) == pdTRUE )
Richard Barry7a8eb502007-07-28 16:33:07 +0000888 {
889 xReturn = pdTRUE;
890 }
891 }
892 }
893
894 return xReturn;
895 }
896
897#endif
898/*-----------------------------------------------------------*/
899
900#if ( INCLUDE_vTaskSuspend == 1 )
901
Richard Barryb6df57c2006-05-02 09:39:15 +0000902 void vTaskResume( xTaskHandle pxTaskToResume )
903 {
Richard Barryde1094e2007-07-28 18:35:03 +0000904 tskTCB *pxTCB;
Richard Barryb6df57c2006-05-02 09:39:15 +0000905
906 /* Remove the task from whichever list it is currently in, and place
907 it in the ready list. */
908 pxTCB = ( tskTCB * ) pxTaskToResume;
909
910 /* The parameter cannot be NULL as it is impossible to resume the
911 currently executing task. */
Richard Barry3f620022008-05-01 17:15:36 +0000912 if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
Richard Barryb6df57c2006-05-02 09:39:15 +0000913 {
914 taskENTER_CRITICAL();
915 {
Richard Barry2888b152008-05-19 19:17:56 +0000916 if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
Richard Barryb6df57c2006-05-02 09:39:15 +0000917 {
Richard Barryb8b70522008-03-03 16:32:05 +0000918 traceTASK_RESUME( pxTCB );
919
Richard Barry7a8eb502007-07-28 16:33:07 +0000920 /* As we are in a critical section we can access the ready
921 lists even if the scheduler is suspended. */
922 vListRemove( &( pxTCB->xGenericListItem ) );
923 prvAddTaskToReadyQueue( pxTCB );
Richard Barryd481cff2006-07-03 19:34:28 +0000924
Richard Barry7a8eb502007-07-28 16:33:07 +0000925 /* We may have just resumed a higher priority task. */
926 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
927 {
928 /* This yield may not cause the task just resumed to run, but
929 will leave the lists in the correct state for the next yield. */
930 taskYIELD();
Richard Barryd481cff2006-07-03 19:34:28 +0000931 }
Richard Barryb6df57c2006-05-02 09:39:15 +0000932 }
933 }
934 taskEXIT_CRITICAL();
Richard Barryb6df57c2006-05-02 09:39:15 +0000935 }
936 }
937
938#endif
939
Richard Barryd481cff2006-07-03 19:34:28 +0000940/*-----------------------------------------------------------*/
941
Richard Barry6cc711d2006-08-11 10:56:12 +0000942#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
Richard Barryd481cff2006-07-03 19:34:28 +0000943
944 portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume )
945 {
Richard Barry58a357e2006-08-11 10:02:38 +0000946 portBASE_TYPE xYieldRequired = pdFALSE;
Richard Barryde1094e2007-07-28 18:35:03 +0000947 tskTCB *pxTCB;
Richard Barry58a357e2006-08-11 10:02:38 +0000948
949 pxTCB = ( tskTCB * ) pxTaskToResume;
Richard Barryd481cff2006-07-03 19:34:28 +0000950
Richard Barry2888b152008-05-19 19:17:56 +0000951 if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
Richard Barryd481cff2006-07-03 19:34:28 +0000952 {
Richard Barryb8b70522008-03-03 16:32:05 +0000953 traceTASK_RESUME_FROM_ISR( pxTCB );
954
Richard Barry7a8eb502007-07-28 16:33:07 +0000955 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
Richard Barryd481cff2006-07-03 19:34:28 +0000956 {
Richard Barry7a8eb502007-07-28 16:33:07 +0000957 xYieldRequired = ( pxTCB->uxPriority >= pxCurrentTCB->uxPriority );
Richard Barryc66301a2009-05-21 12:23:24 +0000958 vListRemove( &( pxTCB->xGenericListItem ) );
Richard Barry7a8eb502007-07-28 16:33:07 +0000959 prvAddTaskToReadyQueue( pxTCB );
960 }
961 else
962 {
963 /* We cannot access the delayed or ready lists, so will hold this
964 task pending until the scheduler is resumed, at which point a
Richard Barry60338bd2007-08-21 16:54:48 +0000965 yield will be performed if necessary. */
Richard Barry7a8eb502007-07-28 16:33:07 +0000966 vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
Richard Barryd481cff2006-07-03 19:34:28 +0000967 }
Richard Barry17617c52006-07-03 19:39:42 +0000968 }
Richard Barryd481cff2006-07-03 19:34:28 +0000969
970 return xYieldRequired;
971 }
972
973#endif
Richard Barryb6df57c2006-05-02 09:39:15 +0000974
975
976
977
978/*-----------------------------------------------------------
979 * PUBLIC SCHEDULER CONTROL documented in task.h
980 *----------------------------------------------------------*/
981
982
983void vTaskStartScheduler( void )
984{
985portBASE_TYPE xReturn;
986
987 /* Add the idle task at the lowest priority. */
988 xReturn = xTaskCreate( prvIdleTask, ( signed portCHAR * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );
989
990 if( xReturn == pdPASS )
991 {
992 /* Interrupts are turned off here, to ensure a tick does not occur
993 before or during the call to xPortStartScheduler(). The stacks of
994 the created tasks contain a status word with interrupts switched on
995 so interrupts will automatically get re-enabled when the first task
996 starts to run.
Richard Barryc66301a2009-05-21 12:23:24 +0000997
Richard Barryb6df57c2006-05-02 09:39:15 +0000998 STEPPING THROUGH HERE USING A DEBUGGER CAN CAUSE BIG PROBLEMS IF THE
999 DEBUGGER ALLOWS INTERRUPTS TO BE PROCESSED. */
1000 portDISABLE_INTERRUPTS();
1001
1002 xSchedulerRunning = pdTRUE;
1003 xTickCount = ( portTickType ) 0;
1004
Richard Barry8b4ef532009-05-19 10:38:26 +00001005 /* If configGENERATE_RUN_TIME_STATS is defined then the following
1006 macro must be defined to configure the timer/counter used to generate
1007 the run time counter time base. */
1008 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();
1009
Richard Barryb6df57c2006-05-02 09:39:15 +00001010 /* Setting up the timer tick is hardware specific and thus in the
1011 portable interface. */
1012 if( xPortStartScheduler() )
1013 {
1014 /* Should not reach here as if the scheduler is running the
1015 function will not return. */
1016 }
1017 else
1018 {
1019 /* Should only reach here if a task calls xTaskEndScheduler(). */
1020 }
1021 }
1022}
1023/*-----------------------------------------------------------*/
1024
1025void vTaskEndScheduler( void )
1026{
1027 /* Stop the scheduler interrupts and call the portable scheduler end
1028 routine so the original ISRs can be restored if necessary. The port
1029 layer must ensure interrupts enable bit is left in the correct state. */
1030 portDISABLE_INTERRUPTS();
1031 xSchedulerRunning = pdFALSE;
1032 vPortEndScheduler();
1033}
1034/*----------------------------------------------------------*/
1035
1036void vTaskSuspendAll( void )
1037{
Richard Barry55c96042009-03-11 10:55:41 +00001038 /* A critical section is not required as the variable is of type
1039 portBASE_TYPE. */
1040 ++uxSchedulerSuspended;
Richard Barryb6df57c2006-05-02 09:39:15 +00001041}
1042/*----------------------------------------------------------*/
1043
1044signed portBASE_TYPE xTaskResumeAll( void )
1045{
1046register tskTCB *pxTCB;
1047signed portBASE_TYPE xAlreadyYielded = pdFALSE;
1048
1049 /* It is possible that an ISR caused a task to be removed from an event
1050 list while the scheduler was suspended. If this was the case then the
1051 removed task will have been added to the xPendingReadyList. Once the
1052 scheduler has been resumed it is safe to move all the pending ready
1053 tasks from this list into their appropriate ready list. */
1054 portENTER_CRITICAL();
1055 {
1056 --uxSchedulerSuspended;
1057
1058 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
Richard Barryc66301a2009-05-21 12:23:24 +00001059 {
Richard Barryb6df57c2006-05-02 09:39:15 +00001060 if( uxCurrentNumberOfTasks > ( unsigned portBASE_TYPE ) 0 )
1061 {
1062 portBASE_TYPE xYieldRequired = pdFALSE;
Richard Barryc66301a2009-05-21 12:23:24 +00001063
Richard Barryb6df57c2006-05-02 09:39:15 +00001064 /* Move any readied tasks from the pending list into the
1065 appropriate ready list. */
1066 while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xPendingReadyList ) ) ) != NULL )
1067 {
1068 vListRemove( &( pxTCB->xEventListItem ) );
1069 vListRemove( &( pxTCB->xGenericListItem ) );
1070 prvAddTaskToReadyQueue( pxTCB );
Richard Barryc66301a2009-05-21 12:23:24 +00001071
Richard Barryb6df57c2006-05-02 09:39:15 +00001072 /* If we have moved a task that has a priority higher than
1073 the current task then we should yield. */
1074 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
1075 {
1076 xYieldRequired = pdTRUE;
1077 }
1078 }
1079
1080 /* If any ticks occurred while the scheduler was suspended then
1081 they should be processed now. This ensures the tick count does not
1082 slip, and that any delayed tasks are resumed at the correct time. */
1083 if( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
1084 {
1085 while( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
1086 {
1087 vTaskIncrementTick();
1088 --uxMissedTicks;
1089 }
1090
1091 /* As we have processed some ticks it is appropriate to yield
1092 to ensure the highest priority task that is ready to run is
1093 the task actually running. */
Richard Barrydfb8e702008-01-22 18:43:03 +00001094 #if configUSE_PREEMPTION == 1
1095 {
1096 xYieldRequired = pdTRUE;
1097 }
1098 #endif
Richard Barryb6df57c2006-05-02 09:39:15 +00001099 }
Richard Barryc66301a2009-05-21 12:23:24 +00001100
Richard Barryb6df57c2006-05-02 09:39:15 +00001101 if( ( xYieldRequired == pdTRUE ) || ( xMissedYield == pdTRUE ) )
1102 {
1103 xAlreadyYielded = pdTRUE;
1104 xMissedYield = pdFALSE;
1105 taskYIELD();
1106 }
1107 }
1108 }
1109 }
1110 portEXIT_CRITICAL();
1111
1112 return xAlreadyYielded;
1113}
1114
1115
1116
1117
1118
1119
1120/*-----------------------------------------------------------
1121 * PUBLIC TASK UTILITIES documented in task.h
1122 *----------------------------------------------------------*/
1123
1124
1125
1126portTickType xTaskGetTickCount( void )
1127{
1128portTickType xTicks;
1129
1130 /* Critical section required if running on a 16 bit processor. */
1131 taskENTER_CRITICAL();
1132 {
1133 xTicks = xTickCount;
1134 }
1135 taskEXIT_CRITICAL();
1136
1137 return xTicks;
1138}
1139/*-----------------------------------------------------------*/
1140
1141unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void )
1142{
Richard Barry55c96042009-03-11 10:55:41 +00001143 /* A critical section is not required because the variables are of type
1144 portBASE_TYPE. */
1145 return uxCurrentNumberOfTasks;
Richard Barryb6df57c2006-05-02 09:39:15 +00001146}
1147/*-----------------------------------------------------------*/
1148
Richard Barry8b4ef532009-05-19 10:38:26 +00001149#if ( configUSE_TRACE_FACILITY == 1 )
Richard Barryb6df57c2006-05-02 09:39:15 +00001150
1151 void vTaskList( signed portCHAR *pcWriteBuffer )
1152 {
1153 unsigned portBASE_TYPE uxQueue;
1154
1155 /* This is a VERY costly function that should be used for debug only.
1156 It leaves interrupts disabled for a LONG time. */
1157
Richard Barry946da762006-05-28 08:17:56 +00001158 vTaskSuspendAll();
Richard Barryb6df57c2006-05-02 09:39:15 +00001159 {
1160 /* Run through all the lists that could potentially contain a TCB and
1161 report the task name, state and stack high water mark. */
1162
1163 pcWriteBuffer[ 0 ] = ( signed portCHAR ) 0x00;
1164 strcat( ( portCHAR * ) pcWriteBuffer, ( const portCHAR * ) "\r\n" );
1165
1166 uxQueue = uxTopUsedPriority + 1;
1167
1168 do
1169 {
1170 uxQueue--;
1171
1172 if( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) )
1173 {
Richard Barryc66301a2009-05-21 12:23:24 +00001174 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), tskREADY_CHAR );
Richard Barryb6df57c2006-05-02 09:39:15 +00001175 }
1176 }while( uxQueue > ( unsigned portSHORT ) tskIDLE_PRIORITY );
1177
1178 if( !listLIST_IS_EMPTY( pxDelayedTaskList ) )
1179 {
1180 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, tskBLOCKED_CHAR );
1181 }
1182
1183 if( !listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) )
1184 {
1185 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, tskBLOCKED_CHAR );
1186 }
1187
Richard Barry8b4ef532009-05-19 10:38:26 +00001188 #if( INCLUDE_vTaskDelete == 1 )
Richard Barryb6df57c2006-05-02 09:39:15 +00001189 {
Richard Barry8b4ef532009-05-19 10:38:26 +00001190 if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) )
1191 {
1192 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, tskDELETED_CHAR );
1193 }
1194 }
1195 #endif
1196
1197 #if ( INCLUDE_vTaskSuspend == 1 )
1198 {
1199 if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
1200 {
1201 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, tskSUSPENDED_CHAR );
1202 }
1203 }
1204 #endif
1205 }
1206 xTaskResumeAll();
1207 }
1208
1209#endif
1210/*----------------------------------------------------------*/
1211
1212#if ( configGENERATE_RUN_TIME_STATS == 1 )
1213
1214 void vTaskGetRunTimeStats( signed portCHAR *pcWriteBuffer )
1215 {
1216 unsigned portBASE_TYPE uxQueue;
1217 unsigned portLONG ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
1218
1219 /* This is a VERY costly function that should be used for debug only.
1220 It leaves interrupts disabled for a LONG time. */
1221
1222 vTaskSuspendAll();
1223 {
1224 /* Run through all the lists that could potentially contain a TCB,
Richard Barryc66301a2009-05-21 12:23:24 +00001225 generating a table of run timer percentages in the provided
Richard Barry8b4ef532009-05-19 10:38:26 +00001226 buffer. */
1227
1228 pcWriteBuffer[ 0 ] = ( signed portCHAR ) 0x00;
1229 strcat( ( portCHAR * ) pcWriteBuffer, ( const portCHAR * ) "\r\n" );
1230
1231 uxQueue = uxTopUsedPriority + 1;
1232
1233 do
1234 {
1235 uxQueue--;
1236
1237 if( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) )
1238 {
1239 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), ulTotalRunTime );
1240 }
1241 }while( uxQueue > ( unsigned portSHORT ) tskIDLE_PRIORITY );
1242
1243 if( !listLIST_IS_EMPTY( pxDelayedTaskList ) )
1244 {
1245 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, ulTotalRunTime );
Richard Barryb6df57c2006-05-02 09:39:15 +00001246 }
1247
Richard Barry8b4ef532009-05-19 10:38:26 +00001248 if( !listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) )
Richard Barryb6df57c2006-05-02 09:39:15 +00001249 {
Richard Barry8b4ef532009-05-19 10:38:26 +00001250 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, ulTotalRunTime );
Richard Barryb6df57c2006-05-02 09:39:15 +00001251 }
Richard Barry8b4ef532009-05-19 10:38:26 +00001252
1253 #if ( INCLUDE_vTaskDelete == 1 )
1254 {
1255 if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) )
1256 {
1257 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, ulTotalRunTime );
1258 }
1259 }
1260 #endif
1261
1262 #if ( INCLUDE_vTaskSuspend == 1 )
1263 {
1264 if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
1265 {
1266 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, ulTotalRunTime );
1267 }
1268 }
1269 #endif
Richard Barryb6df57c2006-05-02 09:39:15 +00001270 }
Richard Barry946da762006-05-28 08:17:56 +00001271 xTaskResumeAll();
Richard Barryb6df57c2006-05-02 09:39:15 +00001272 }
1273
1274#endif
1275/*----------------------------------------------------------*/
1276
1277#if ( configUSE_TRACE_FACILITY == 1 )
1278
1279 void vTaskStartTrace( signed portCHAR * pcBuffer, unsigned portLONG ulBufferSize )
1280 {
1281 portENTER_CRITICAL();
1282 {
Richard Barry79dd9812008-02-15 13:44:06 +00001283 pcTraceBuffer = ( signed portCHAR * )pcBuffer;
Richard Barryb6df57c2006-05-02 09:39:15 +00001284 pcTraceBufferStart = pcBuffer;
1285 pcTraceBufferEnd = pcBuffer + ( ulBufferSize - tskSIZE_OF_EACH_TRACE_LINE );
1286 xTracing = pdTRUE;
1287 }
1288 portEXIT_CRITICAL();
1289 }
1290
1291#endif
1292/*----------------------------------------------------------*/
1293
1294#if ( configUSE_TRACE_FACILITY == 1 )
1295
1296 unsigned portLONG ulTaskEndTrace( void )
1297 {
1298 unsigned portLONG ulBufferLength;
1299
1300 portENTER_CRITICAL();
1301 xTracing = pdFALSE;
1302 portEXIT_CRITICAL();
1303
1304 ulBufferLength = ( unsigned portLONG ) ( pcTraceBuffer - pcTraceBufferStart );
1305
1306 return ulBufferLength;
1307 }
1308
1309#endif
1310
1311
1312
1313/*-----------------------------------------------------------
1314 * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES
1315 * documented in task.h
1316 *----------------------------------------------------------*/
1317
1318
Richard Barry0d298072008-05-01 08:57:45 +00001319void vTaskIncrementTick( void )
Richard Barryb6df57c2006-05-02 09:39:15 +00001320{
1321 /* Called by the portable layer each time a tick interrupt occurs.
1322 Increments the tick then checks to see if the new tick value will cause any
1323 tasks to be unblocked. */
1324 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
1325 {
1326 ++xTickCount;
1327 if( xTickCount == ( portTickType ) 0 )
1328 {
1329 xList *pxTemp;
1330
Richard Barry39f6b0b2008-03-03 20:56:55 +00001331 /* Tick count has overflowed so we need to swap the delay lists.
1332 If there are any items in pxDelayedTaskList here then there is
Richard Barry946da762006-05-28 08:17:56 +00001333 an error! */
Richard Barryb6df57c2006-05-02 09:39:15 +00001334 pxTemp = pxDelayedTaskList;
1335 pxDelayedTaskList = pxOverflowDelayedTaskList;
1336 pxOverflowDelayedTaskList = pxTemp;
Richard Barryb18929e2006-08-27 14:09:54 +00001337 xNumOfOverflows++;
Richard Barryb6df57c2006-05-02 09:39:15 +00001338 }
1339
1340 /* See if this tick has made a timeout expire. */
1341 prvCheckDelayedTasks();
1342 }
1343 else
1344 {
1345 ++uxMissedTicks;
Richard Barry946da762006-05-28 08:17:56 +00001346
Richard Barry39f6b0b2008-03-03 20:56:55 +00001347 /* The tick hook gets called at regular intervals, even if the
Richard Barry946da762006-05-28 08:17:56 +00001348 scheduler is locked. */
1349 #if ( configUSE_TICK_HOOK == 1 )
1350 {
1351 extern void vApplicationTickHook( void );
1352
1353 vApplicationTickHook();
1354 }
1355 #endif
Richard Barryb6df57c2006-05-02 09:39:15 +00001356 }
1357
1358 #if ( configUSE_TICK_HOOK == 1 )
1359 {
1360 extern void vApplicationTickHook( void );
1361
Richard Barry946da762006-05-28 08:17:56 +00001362 /* Guard against the tick hook being called when the missed tick
1363 count is being unwound (when the scheduler is being unlocked. */
1364 if( uxMissedTicks == 0 )
1365 {
1366 vApplicationTickHook();
1367 }
Richard Barryb6df57c2006-05-02 09:39:15 +00001368 }
1369 #endif
Richard Barryb8b70522008-03-03 16:32:05 +00001370
1371 traceTASK_INCREMENT_TICK( xTickCount );
Richard Barryb6df57c2006-05-02 09:39:15 +00001372}
1373/*-----------------------------------------------------------*/
1374
1375#if ( ( INCLUDE_vTaskCleanUpResources == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
1376
1377 void vTaskCleanUpResources( void )
1378 {
1379 unsigned portSHORT usQueue;
1380 volatile tskTCB *pxTCB;
1381
1382 usQueue = ( unsigned portSHORT ) uxTopUsedPriority + ( unsigned portSHORT ) 1;
1383
1384 /* Remove any TCB's from the ready queues. */
1385 do
1386 {
1387 usQueue--;
1388
1389 while( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ usQueue ] ) ) )
1390 {
1391 listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &( pxReadyTasksLists[ usQueue ] ) );
1392 vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
1393
1394 prvDeleteTCB( ( tskTCB * ) pxTCB );
1395 }
1396 }while( usQueue > ( unsigned portSHORT ) tskIDLE_PRIORITY );
1397
1398 /* Remove any TCB's from the delayed queue. */
1399 while( !listLIST_IS_EMPTY( &xDelayedTaskList1 ) )
1400 {
1401 listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList1 );
1402 vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
1403
1404 prvDeleteTCB( ( tskTCB * ) pxTCB );
1405 }
1406
1407 /* Remove any TCB's from the overflow delayed queue. */
1408 while( !listLIST_IS_EMPTY( &xDelayedTaskList2 ) )
1409 {
1410 listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList2 );
1411 vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
1412
1413 prvDeleteTCB( ( tskTCB * ) pxTCB );
1414 }
1415
1416 while( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
1417 {
1418 listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xSuspendedTaskList );
1419 vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
1420
1421 prvDeleteTCB( ( tskTCB * ) pxTCB );
Richard Barryc66301a2009-05-21 12:23:24 +00001422 }
Richard Barryb6df57c2006-05-02 09:39:15 +00001423 }
1424
1425#endif
1426/*-----------------------------------------------------------*/
1427
Richard Barrye9395422008-04-16 07:47:02 +00001428#if ( configUSE_APPLICATION_TASK_TAG == 1 )
Richard Barryda6d27b2008-04-12 09:46:19 +00001429
Richard Barrye9395422008-04-16 07:47:02 +00001430 void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxTagValue )
Richard Barryda6d27b2008-04-12 09:46:19 +00001431 {
1432 tskTCB *xTCB;
1433
1434 /* If xTask is NULL then we are setting our own task hook. */
1435 if( xTask == NULL )
1436 {
1437 xTCB = ( tskTCB * ) pxCurrentTCB;
1438 }
1439 else
1440 {
1441 xTCB = ( tskTCB * ) xTask;
1442 }
Richard Barryc66301a2009-05-21 12:23:24 +00001443
Richard Barry55c96042009-03-11 10:55:41 +00001444 /* Save the hook function in the TCB. A critical section is required as
1445 the value can be accessed from an interrupt. */
Richard Barrye9395422008-04-16 07:47:02 +00001446 portENTER_CRITICAL();
1447 xTCB->pxTaskTag = pxTagValue;
1448 portEXIT_CRITICAL();
Richard Barryda6d27b2008-04-12 09:46:19 +00001449 }
Richard Barryc66301a2009-05-21 12:23:24 +00001450
Richard Barryda6d27b2008-04-12 09:46:19 +00001451#endif
1452/*-----------------------------------------------------------*/
1453
Richard Barrye9395422008-04-16 07:47:02 +00001454#if ( configUSE_APPLICATION_TASK_TAG == 1 )
Richard Barryda6d27b2008-04-12 09:46:19 +00001455
Richard Barryf24533b2009-05-30 13:30:40 +00001456 pdTASK_HOOK_CODE xTaskGetApplicationTaskTag( xTaskHandle xTask )
1457 {
1458 tskTCB *xTCB;
1459 pdTASK_HOOK_CODE xReturn;
1460
1461 /* If xTask is NULL then we are setting our own task hook. */
1462 if( xTask == NULL )
1463 {
1464 xTCB = ( tskTCB * ) pxCurrentTCB;
1465 }
1466 else
1467 {
1468 xTCB = ( tskTCB * ) xTask;
1469 }
1470
1471 /* Save the hook function in the TCB. A critical section is required as
1472 the value can be accessed from an interrupt. */
1473 portENTER_CRITICAL();
1474 xReturn = xTCB->pxTaskTag;
1475 portEXIT_CRITICAL();
1476
1477 return xReturn;
1478 }
1479
1480#endif
1481/*-----------------------------------------------------------*/
1482
1483#if ( configUSE_APPLICATION_TASK_TAG == 1 )
1484
Richard Barryda6d27b2008-04-12 09:46:19 +00001485 portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParameter )
1486 {
1487 tskTCB *xTCB;
1488 portBASE_TYPE xReturn;
1489
1490 /* If xTask is NULL then we are calling our own task hook. */
1491 if( xTask == NULL )
1492 {
1493 xTCB = ( tskTCB * ) pxCurrentTCB;
1494 }
1495 else
1496 {
1497 xTCB = ( tskTCB * ) xTask;
1498 }
1499
Richard Barrye9395422008-04-16 07:47:02 +00001500 if( xTCB->pxTaskTag != NULL )
Richard Barryda6d27b2008-04-12 09:46:19 +00001501 {
Richard Barrye9395422008-04-16 07:47:02 +00001502 xReturn = xTCB->pxTaskTag( pvParameter );
Richard Barryda6d27b2008-04-12 09:46:19 +00001503 }
1504 else
1505 {
1506 xReturn = pdFAIL;
1507 }
1508
1509 return xReturn;
1510 }
Richard Barryc66301a2009-05-21 12:23:24 +00001511
Richard Barryda6d27b2008-04-12 09:46:19 +00001512#endif
1513/*-----------------------------------------------------------*/
1514
Richard Barryb6df57c2006-05-02 09:39:15 +00001515void vTaskSwitchContext( void )
1516{
Richard Barryb6df57c2006-05-02 09:39:15 +00001517 if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )
1518 {
1519 /* The scheduler is currently suspended - do not allow a context
1520 switch. */
1521 xMissedYield = pdTRUE;
1522 return;
1523 }
1524
Richard Barryc66301a2009-05-21 12:23:24 +00001525 traceTASK_SWITCHED_OUT();
1526
1527 #if ( configGENERATE_RUN_TIME_STATS == 1 )
1528 {
1529 unsigned portLONG ulTempCounter = portGET_RUN_TIME_COUNTER_VALUE();
1530
1531 /* Add the amount of time the task has been running to the accumulated
1532 time so far. The time the task started running was stored in
1533 ulTaskSwitchedInTime. Note that there is no overflow protection here
1534 so count values are only valid until the timer overflows. Generally
1535 this will be about 1 hour assuming a 1uS timer increment. */
1536 pxCurrentTCB->ulRunTimeCounter += ( ulTempCounter - ulTaskSwitchedInTime );
1537 ulTaskSwitchedInTime = ulTempCounter;
1538 }
1539 #endif
1540
Richard Barry4f631de2008-10-09 00:53:02 +00001541 taskFIRST_CHECK_FOR_STACK_OVERFLOW();
1542 taskSECOND_CHECK_FOR_STACK_OVERFLOW();
Richard Barry39f6b0b2008-03-03 20:56:55 +00001543
Richard Barryb6df57c2006-05-02 09:39:15 +00001544 /* Find the highest priority queue that contains ready tasks. */
1545 while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) )
1546 {
1547 --uxTopReadyPriority;
1548 }
1549
1550 /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the tasks of the
1551 same priority get an equal share of the processor time. */
1552 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) );
Richard Barryb8b70522008-03-03 16:32:05 +00001553
1554 traceTASK_SWITCHED_IN();
Richard Barryb6df57c2006-05-02 09:39:15 +00001555 vWriteTraceToBuffer();
1556}
1557/*-----------------------------------------------------------*/
1558
Richard Barry60338bd2007-08-21 16:54:48 +00001559void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait )
Richard Barryb6df57c2006-05-02 09:39:15 +00001560{
1561portTickType xTimeToWake;
1562
1563 /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
1564 SCHEDULER SUSPENDED. */
1565
1566 /* Place the event list item of the TCB in the appropriate event list.
1567 This is placed in the list in priority order so the highest priority task
1568 is the first to be woken by the event. */
1569 vListInsert( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );
1570
Richard Barryb6df57c2006-05-02 09:39:15 +00001571 /* We must remove ourselves from the ready list before adding ourselves
1572 to the blocked list as the same list item is used for both lists. We have
1573 exclusive access to the ready lists as the scheduler is locked. */
1574 vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
1575
Richard Barry6083a3a2006-10-28 09:47:41 +00001576
1577 #if ( INCLUDE_vTaskSuspend == 1 )
Richard Barryc66301a2009-05-21 12:23:24 +00001578 {
Richard Barry6083a3a2006-10-28 09:47:41 +00001579 if( xTicksToWait == portMAX_DELAY )
Richard Barry96d46842006-10-22 20:28:16 +00001580 {
Richard Barry6083a3a2006-10-28 09:47:41 +00001581 /* Add ourselves to the suspended task list instead of a delayed task
1582 list to ensure we are not woken by a timing event. We will block
1583 indefinitely. */
1584 vListInsertEnd( ( xList * ) &xSuspendedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
Richard Barry96d46842006-10-22 20:28:16 +00001585 }
1586 else
1587 {
Richard Barry6083a3a2006-10-28 09:47:41 +00001588 /* Calculate the time at which the task should be woken if the event does
1589 not occur. This may overflow but this doesn't matter. */
1590 xTimeToWake = xTickCount + xTicksToWait;
Richard Barryc66301a2009-05-21 12:23:24 +00001591
Richard Barry6083a3a2006-10-28 09:47:41 +00001592 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
Richard Barryc66301a2009-05-21 12:23:24 +00001593
Richard Barry6083a3a2006-10-28 09:47:41 +00001594 if( xTimeToWake < xTickCount )
1595 {
1596 /* Wake time has overflowed. Place this item in the overflow list. */
1597 vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
1598 }
1599 else
1600 {
1601 /* The wake time has not overflowed, so we can use the current block list. */
1602 vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
1603 }
Richard Barry96d46842006-10-22 20:28:16 +00001604 }
Richard Barryb6df57c2006-05-02 09:39:15 +00001605 }
Richard Barry6083a3a2006-10-28 09:47:41 +00001606 #else
1607 {
1608 /* Calculate the time at which the task should be woken if the event does
1609 not occur. This may overflow but this doesn't matter. */
1610 xTimeToWake = xTickCount + xTicksToWait;
Richard Barryc66301a2009-05-21 12:23:24 +00001611
Richard Barry6083a3a2006-10-28 09:47:41 +00001612 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
Richard Barryc66301a2009-05-21 12:23:24 +00001613
Richard Barry6083a3a2006-10-28 09:47:41 +00001614 if( xTimeToWake < xTickCount )
1615 {
1616 /* Wake time has overflowed. Place this item in the overflow list. */
1617 vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
1618 }
1619 else
1620 {
1621 /* The wake time has not overflowed, so we can use the current block list. */
1622 vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
1623 }
1624 }
1625 #endif
Richard Barryb6df57c2006-05-02 09:39:15 +00001626}
1627/*-----------------------------------------------------------*/
1628
Richard Barry60338bd2007-08-21 16:54:48 +00001629signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList )
Richard Barryb6df57c2006-05-02 09:39:15 +00001630{
1631tskTCB *pxUnblockedTCB;
1632portBASE_TYPE xReturn;
1633
1634 /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
1635 SCHEDULER SUSPENDED. It can also be called from within an ISR. */
1636
1637 /* The event list is sorted in priority order, so we can remove the
1638 first in the list, remove the TCB from the delayed list, and add
1639 it to the ready list.
Richard Barryc66301a2009-05-21 12:23:24 +00001640
Richard Barryb6df57c2006-05-02 09:39:15 +00001641 If an event is for a queue that is locked then this function will never
1642 get called - the lock count on the queue will get modified instead. This
1643 means we can always expect exclusive access to the event list here. */
1644 pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
1645 vListRemove( &( pxUnblockedTCB->xEventListItem ) );
1646
1647 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
1648 {
1649 vListRemove( &( pxUnblockedTCB->xGenericListItem ) );
1650 prvAddTaskToReadyQueue( pxUnblockedTCB );
1651 }
1652 else
1653 {
1654 /* We cannot access the delayed or ready lists, so will hold this
1655 task pending until the scheduler is resumed. */
1656 vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );
1657 }
1658
1659 if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority )
1660 {
1661 /* Return true if the task removed from the event list has
1662 a higher priority than the calling task. This allows
1663 the calling task to know if it should force a context
1664 switch now. */
1665 xReturn = pdTRUE;
1666 }
1667 else
1668 {
1669 xReturn = pdFALSE;
1670 }
1671
1672 return xReturn;
1673}
Richard Barryb18929e2006-08-27 14:09:54 +00001674/*-----------------------------------------------------------*/
Richard Barryb6df57c2006-05-02 09:39:15 +00001675
Richard Barry60338bd2007-08-21 16:54:48 +00001676void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut )
Richard Barryb18929e2006-08-27 14:09:54 +00001677{
1678 pxTimeOut->xOverflowCount = xNumOfOverflows;
1679 pxTimeOut->xTimeOnEntering = xTickCount;
1680}
1681/*-----------------------------------------------------------*/
Richard Barryb6df57c2006-05-02 09:39:15 +00001682
Richard Barry60338bd2007-08-21 16:54:48 +00001683portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait )
Richard Barryb18929e2006-08-27 14:09:54 +00001684{
1685portBASE_TYPE xReturn;
Richard Barryb6df57c2006-05-02 09:39:15 +00001686
Richard Barryed28aa22008-03-23 16:00:51 +00001687 portENTER_CRITICAL();
1688 {
1689 #if ( INCLUDE_vTaskSuspend == 1 )
1690 /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is
1691 the maximum block time then the task should block indefinitely, and
1692 therefore never time out. */
1693 if( *pxTicksToWait == portMAX_DELAY )
1694 {
1695 xReturn = pdFALSE;
1696 }
1697 else /* We are not blocking indefinitely, perform the checks below. */
1698 #endif
1699
1700 if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( xTickCount >= pxTimeOut->xTimeOnEntering ) )
Richard Barry7a8eb502007-07-28 16:33:07 +00001701 {
Richard Barryed28aa22008-03-23 16:00:51 +00001702 /* The tick count is greater than the time at which vTaskSetTimeout()
1703 was called, but has also overflowed since vTaskSetTimeOut() was called.
1704 It must have wrapped all the way around and gone past us again. This
1705 passed since vTaskSetTimeout() was called. */
1706 xReturn = pdTRUE;
1707 }
1708 else if( ( xTickCount - pxTimeOut->xTimeOnEntering ) < *pxTicksToWait )
1709 {
1710 /* Not a genuine timeout. Adjust parameters for time remaining. */
1711 *pxTicksToWait -= ( xTickCount - pxTimeOut->xTimeOnEntering );
1712 vTaskSetTimeOutState( pxTimeOut );
Richard Barry7a8eb502007-07-28 16:33:07 +00001713 xReturn = pdFALSE;
1714 }
Richard Barryed28aa22008-03-23 16:00:51 +00001715 else
1716 {
1717 xReturn = pdTRUE;
1718 }
1719 }
1720 portEXIT_CRITICAL();
Richard Barryb6df57c2006-05-02 09:39:15 +00001721
Richard Barryb18929e2006-08-27 14:09:54 +00001722 return xReturn;
1723}
1724/*-----------------------------------------------------------*/
1725
1726void vTaskMissedYield( void )
1727{
1728 xMissedYield = pdTRUE;
1729}
Richard Barryb6df57c2006-05-02 09:39:15 +00001730
1731/*
1732 * -----------------------------------------------------------
1733 * The Idle task.
1734 * ----------------------------------------------------------
1735 *
1736 * The portTASK_FUNCTION() macro is used to allow port/compiler specific
1737 * language extensions. The equivalent prototype for this function is:
1738 *
1739 * void prvIdleTask( void *pvParameters );
1740 *
1741 */
1742static portTASK_FUNCTION( prvIdleTask, pvParameters )
1743{
1744 /* Stop warnings. */
1745 ( void ) pvParameters;
1746
1747 for( ;; )
1748 {
1749 /* See if any tasks have been deleted. */
1750 prvCheckTasksWaitingTermination();
1751
1752 #if ( configUSE_PREEMPTION == 0 )
1753 {
1754 /* If we are not using preemption we keep forcing a task switch to
1755 see if any other task has become available. If we are using
1756 preemption we don't need to do this as any task becoming available
1757 will automatically get the processor anyway. */
Richard Barryc66301a2009-05-21 12:23:24 +00001758 taskYIELD();
Richard Barryb6df57c2006-05-02 09:39:15 +00001759 }
1760 #endif
1761
1762 #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
1763 {
1764 /* When using preemption tasks of equal priority will be
1765 timesliced. If a task that is sharing the idle priority is ready
1766 to run then the idle task should yield before the end of the
1767 timeslice.
Richard Barryc66301a2009-05-21 12:23:24 +00001768
Richard Barryb6df57c2006-05-02 09:39:15 +00001769 A critical region is not required here as we are just reading from
1770 the list, and an occasional incorrect value will not matter. If
1771 the ready list at the idle priority contains more than one task
1772 then a task other than the idle task is ready to execute. */
1773 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( unsigned portBASE_TYPE ) 1 )
1774 {
1775 taskYIELD();
1776 }
1777 }
1778 #endif
1779
1780 #if ( configUSE_IDLE_HOOK == 1 )
1781 {
1782 extern void vApplicationIdleHook( void );
1783
1784 /* Call the user defined function from within the idle task. This
1785 allows the application designer to add background functionality
1786 without the overhead of a separate task.
1787 NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
1788 CALL A FUNCTION THAT MIGHT BLOCK. */
1789 vApplicationIdleHook();
1790 }
1791 #endif
1792 }
1793} /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */
1794
1795
1796
1797
1798
1799
1800
1801/*-----------------------------------------------------------
1802 * File private functions documented at the top of the file.
1803 *----------------------------------------------------------*/
1804
1805
1806
Richard Barry60338bd2007-08-21 16:54:48 +00001807static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed portCHAR * const pcName, unsigned portBASE_TYPE uxPriority )
Richard Barryb6df57c2006-05-02 09:39:15 +00001808{
Richard Barryb6df57c2006-05-02 09:39:15 +00001809 /* Store the function name in the TCB. */
Richard Barryf24533b2009-05-30 13:30:40 +00001810 #if configMAX_TASK_NAME_LEN > 1
1811 {
1812 /* Don't bring strncpy into the build unnecessarily. */
1813 strncpy( ( char * ) pxTCB->pcTaskName, ( const char * ) pcName, ( unsigned portSHORT ) configMAX_TASK_NAME_LEN );
1814 }
1815 #endif
Richard Barryb6df57c2006-05-02 09:39:15 +00001816 pxTCB->pcTaskName[ ( unsigned portSHORT ) configMAX_TASK_NAME_LEN - ( unsigned portSHORT ) 1 ] = '\0';
1817
1818 /* This is used as an array index so must ensure it's not too large. */
1819 if( uxPriority >= configMAX_PRIORITIES )
1820 {
1821 uxPriority = configMAX_PRIORITIES - 1;
1822 }
1823
1824 pxTCB->uxPriority = uxPriority;
Richard Barry60338bd2007-08-21 16:54:48 +00001825 #if ( configUSE_MUTEXES == 1 )
1826 {
1827 pxTCB->uxBasePriority = uxPriority;
1828 }
1829 #endif
Richard Barryb6df57c2006-05-02 09:39:15 +00001830
1831 vListInitialiseItem( &( pxTCB->xGenericListItem ) );
1832 vListInitialiseItem( &( pxTCB->xEventListItem ) );
1833
1834 /* Set the pxTCB as a link back from the xListItem. This is so we can get
1835 back to the containing TCB from a generic item in a list. */
1836 listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB );
1837
1838 /* Event lists are always in priority order. */
1839 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );
1840 listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB );
Richard Barryda6d27b2008-04-12 09:46:19 +00001841
1842 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
1843 {
1844 pxTCB->uxCriticalNesting = ( unsigned portBASE_TYPE ) 0;
1845 }
1846 #endif
1847
Richard Barrye9395422008-04-16 07:47:02 +00001848 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
Richard Barryda6d27b2008-04-12 09:46:19 +00001849 {
Richard Barrye9395422008-04-16 07:47:02 +00001850 pxTCB->pxTaskTag = NULL;
Richard Barryda6d27b2008-04-12 09:46:19 +00001851 }
Richard Barryc66301a2009-05-21 12:23:24 +00001852 #endif
Richard Barry8b4ef532009-05-19 10:38:26 +00001853
1854 #if ( configGENERATE_RUN_TIME_STATS == 1 )
1855 {
1856 pxTCB->ulRunTimeCounter = 0UL;
1857 }
1858 #endif
Richard Barryb6df57c2006-05-02 09:39:15 +00001859}
1860/*-----------------------------------------------------------*/
1861
1862static void prvInitialiseTaskLists( void )
1863{
1864unsigned portBASE_TYPE uxPriority;
1865
1866 for( uxPriority = 0; uxPriority < configMAX_PRIORITIES; uxPriority++ )
1867 {
1868 vListInitialise( ( xList * ) &( pxReadyTasksLists[ uxPriority ] ) );
1869 }
1870
1871 vListInitialise( ( xList * ) &xDelayedTaskList1 );
1872 vListInitialise( ( xList * ) &xDelayedTaskList2 );
1873 vListInitialise( ( xList * ) &xPendingReadyList );
1874
1875 #if ( INCLUDE_vTaskDelete == 1 )
1876 {
1877 vListInitialise( ( xList * ) &xTasksWaitingTermination );
1878 }
1879 #endif
1880
1881 #if ( INCLUDE_vTaskSuspend == 1 )
1882 {
1883 vListInitialise( ( xList * ) &xSuspendedTaskList );
1884 }
1885 #endif
1886
1887 /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
1888 using list2. */
1889 pxDelayedTaskList = &xDelayedTaskList1;
1890 pxOverflowDelayedTaskList = &xDelayedTaskList2;
1891}
1892/*-----------------------------------------------------------*/
1893
1894static void prvCheckTasksWaitingTermination( void )
Richard Barryc66301a2009-05-21 12:23:24 +00001895{
Richard Barryb6df57c2006-05-02 09:39:15 +00001896 #if ( INCLUDE_vTaskDelete == 1 )
Richard Barryc66301a2009-05-21 12:23:24 +00001897 {
Richard Barryb6df57c2006-05-02 09:39:15 +00001898 portBASE_TYPE xListIsEmpty;
1899
1900 /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
1901 too often in the idle task. */
1902 if( uxTasksDeleted > ( unsigned portBASE_TYPE ) 0 )
1903 {
1904 vTaskSuspendAll();
Richard Barryc66301a2009-05-21 12:23:24 +00001905 xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
Richard Barryb6df57c2006-05-02 09:39:15 +00001906 xTaskResumeAll();
1907
1908 if( !xListIsEmpty )
1909 {
1910 tskTCB *pxTCB;
1911
1912 portENTER_CRITICAL();
Richard Barryc66301a2009-05-21 12:23:24 +00001913 {
Richard Barryb6df57c2006-05-02 09:39:15 +00001914 pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xTasksWaitingTermination ) );
1915 vListRemove( &( pxTCB->xGenericListItem ) );
1916 --uxCurrentNumberOfTasks;
1917 --uxTasksDeleted;
1918 }
1919 portEXIT_CRITICAL();
1920
1921 prvDeleteTCB( pxTCB );
1922 }
1923 }
1924 }
1925 #endif
1926}
1927/*-----------------------------------------------------------*/
1928
1929static tskTCB *prvAllocateTCBAndStack( unsigned portSHORT usStackDepth )
1930{
1931tskTCB *pxNewTCB;
1932
1933 /* Allocate space for the TCB. Where the memory comes from depends on
1934 the implementation of the port malloc function. */
1935 pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) );
1936
1937 if( pxNewTCB != NULL )
1938 {
1939 /* Allocate space for the stack used by the task being created.
1940 The base of the stack memory stored in the TCB so the task can
1941 be deleted later if required. */
1942 pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMalloc( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) );
1943
1944 if( pxNewTCB->pxStack == NULL )
1945 {
1946 /* Could not allocate the stack. Delete the allocated TCB. */
Richard Barryc66301a2009-05-21 12:23:24 +00001947 vPortFree( pxNewTCB );
1948 pxNewTCB = NULL;
1949 }
Richard Barryb6df57c2006-05-02 09:39:15 +00001950 else
1951 {
1952 /* Just to help debugging. */
1953 memset( pxNewTCB->pxStack, tskSTACK_FILL_BYTE, usStackDepth * sizeof( portSTACK_TYPE ) );
1954 }
1955 }
1956
1957 return pxNewTCB;
1958}
1959/*-----------------------------------------------------------*/
1960
1961#if ( configUSE_TRACE_FACILITY == 1 )
1962
Richard Barry60338bd2007-08-21 16:54:48 +00001963 static void prvListTaskWithinSingleList( const signed portCHAR *pcWriteBuffer, xList *pxList, signed portCHAR cStatus )
Richard Barryb6df57c2006-05-02 09:39:15 +00001964 {
1965 volatile tskTCB *pxNextTCB, *pxFirstTCB;
Richard Barryb6df57c2006-05-02 09:39:15 +00001966 unsigned portSHORT usStackRemaining;
1967
1968 /* Write the details of all the TCB's in pxList into the buffer. */
1969 listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
1970 do
1971 {
1972 listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
1973 usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned portCHAR * ) pxNextTCB->pxStack );
1974 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 );
1975 strcat( ( portCHAR * ) pcWriteBuffer, ( portCHAR * ) pcStatusString );
1976
1977 } while( pxNextTCB != pxFirstTCB );
1978 }
1979
1980#endif
1981/*-----------------------------------------------------------*/
1982
Richard Barry8b4ef532009-05-19 10:38:26 +00001983#if ( configGENERATE_RUN_TIME_STATS == 1 )
1984
1985 static void prvGenerateRunTimeStatsForTasksInList( const signed portCHAR *pcWriteBuffer, xList *pxList, unsigned portLONG ulTotalRunTime )
1986 {
1987 volatile tskTCB *pxNextTCB, *pxFirstTCB;
1988 unsigned portLONG ulStatsAsPercentage;
1989
1990 /* Write the run time stats of all the TCB's in pxList into the buffer. */
1991 listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
1992 do
1993 {
Richard Barryc66301a2009-05-21 12:23:24 +00001994 /* Get next TCB in from the list. */
Richard Barry8b4ef532009-05-19 10:38:26 +00001995 listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
1996
Richard Barryc66301a2009-05-21 12:23:24 +00001997 /* Divide by zero check. */
1998 if( ulTotalRunTime > 0UL )
Richard Barry8b4ef532009-05-19 10:38:26 +00001999 {
Richard Barryc66301a2009-05-21 12:23:24 +00002000 /* Has the task run at all? */
2001 if( pxNextTCB->ulRunTimeCounter == 0 )
2002 {
2003 /* The task has used no CPU time at all. */
2004 sprintf( pcStatsString, ( portCHAR * ) "%s\t\t0\t\t0%%\r\n", pxNextTCB->pcTaskName );
2005 }
2006 else
2007 {
2008 /* What percentage of the total run time as the task used?
2009 This will always be rounded down to the nearest integer. */
2010 ulStatsAsPercentage = ( 100UL * pxNextTCB->ulRunTimeCounter ) / ulTotalRunTime;
Richard Barry8b4ef532009-05-19 10:38:26 +00002011
Richard Barryc66301a2009-05-21 12:23:24 +00002012 if( ulStatsAsPercentage > 0UL )
2013 {
Richard Barrycd7fb3f2009-05-28 20:35:28 +00002014 sprintf( pcStatsString, ( portCHAR * ) "%s\t\t%u\t\t%u%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage );
Richard Barryc66301a2009-05-21 12:23:24 +00002015 }
2016 else
2017 {
2018 /* If the percentage is zero here then the task has
Richard Barrycd7fb3f2009-05-28 20:35:28 +00002019 consumed less than 1% of the total run time. */
2020 sprintf( pcStatsString, ( portCHAR * ) "%s\t\t%u\t\t<1%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter );
Richard Barryc66301a2009-05-21 12:23:24 +00002021 }
2022 }
2023
2024 strcat( ( portCHAR * ) pcWriteBuffer, ( portCHAR * ) pcStatsString );
2025 }
Richard Barry8b4ef532009-05-19 10:38:26 +00002026
2027 } while( pxNextTCB != pxFirstTCB );
2028 }
2029
2030#endif
2031/*-----------------------------------------------------------*/
2032
Richard Barry03acab12008-10-29 10:11:22 +00002033#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
Richard Barry39f6b0b2008-03-03 20:56:55 +00002034
Richard Barry60338bd2007-08-21 16:54:48 +00002035 unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR * pucStackByte )
Richard Barryb6df57c2006-05-02 09:39:15 +00002036 {
2037 register unsigned portSHORT usCount = 0;
2038
2039 while( *pucStackByte == tskSTACK_FILL_BYTE )
2040 {
2041 pucStackByte -= portSTACK_GROWTH;
2042 usCount++;
2043 }
2044
2045 usCount /= sizeof( portSTACK_TYPE );
2046
2047 return usCount;
2048 }
Richard Barry39f6b0b2008-03-03 20:56:55 +00002049
Richard Barryb6df57c2006-05-02 09:39:15 +00002050#endif
2051/*-----------------------------------------------------------*/
2052
Richard Barry39f6b0b2008-03-03 20:56:55 +00002053#if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )
2054
Richard Barry47a7f012008-03-05 10:12:35 +00002055 unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask )
Richard Barryb8b70522008-03-03 16:32:05 +00002056 {
Richard Barry47a7f012008-03-05 10:12:35 +00002057 tskTCB *pxTCB;
Richard Barry4f631de2008-10-09 00:53:02 +00002058 unsigned portCHAR *pcEndOfStack;
Richard Barry47a7f012008-03-05 10:12:35 +00002059
2060 pxTCB = prvGetTCBFromHandle( xTask );
Richard Barry4f631de2008-10-09 00:53:02 +00002061
2062 #if portSTACK_GROWTH < 0
2063 {
2064 pcEndOfStack = ( unsigned portCHAR * ) pxTCB->pxStack;
2065 }
2066 #else
2067 {
2068 pcEndOfStack = ( unsigned portCHAR * ) pxTCB->pxEndOfStack;
2069 }
2070 #endif
2071
2072 return usTaskCheckFreeStackSpace( pcEndOfStack );
Richard Barryb8b70522008-03-03 16:32:05 +00002073 }
Richard Barry39f6b0b2008-03-03 20:56:55 +00002074
Richard Barryb8b70522008-03-03 16:32:05 +00002075#endif
2076/*-----------------------------------------------------------*/
Richard Barryb6df57c2006-05-02 09:39:15 +00002077
2078#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
2079
2080 static void prvDeleteTCB( tskTCB *pxTCB )
2081 {
2082 /* Free up the memory allocated by the scheduler for the task. It is up to
2083 the task to free any memory allocated at the application level. */
2084 vPortFree( pxTCB->pxStack );
2085 vPortFree( pxTCB );
2086 }
2087
2088#endif
2089
2090
2091/*-----------------------------------------------------------*/
2092
2093#if ( INCLUDE_xTaskGetCurrentTaskHandle == 1 )
2094
2095 xTaskHandle xTaskGetCurrentTaskHandle( void )
2096 {
Richard Barry55c96042009-03-11 10:55:41 +00002097 /* A critical section is not required as this is not called from
2098 an interrupt and the current TCB will always be the same for any
2099 individual execution thread. */
2100 return pxCurrentTCB;
Richard Barryb6df57c2006-05-02 09:39:15 +00002101 }
2102
2103#endif
2104
Richard Barry7a8eb502007-07-28 16:33:07 +00002105/*-----------------------------------------------------------*/
Richard Barryb6df57c2006-05-02 09:39:15 +00002106
Richard Barry7a8eb502007-07-28 16:33:07 +00002107#if ( INCLUDE_xTaskGetSchedulerState == 1 )
Richard Barryb6df57c2006-05-02 09:39:15 +00002108
Richard Barry7a8eb502007-07-28 16:33:07 +00002109 portBASE_TYPE xTaskGetSchedulerState( void )
2110 {
2111 portBASE_TYPE xReturn;
Richard Barryc66301a2009-05-21 12:23:24 +00002112
Richard Barry7a8eb502007-07-28 16:33:07 +00002113 if( xSchedulerRunning == pdFALSE )
2114 {
2115 xReturn = taskSCHEDULER_NOT_STARTED;
2116 }
2117 else
2118 {
2119 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
2120 {
2121 xReturn = taskSCHEDULER_RUNNING;
2122 }
2123 else
2124 {
2125 xReturn = taskSCHEDULER_SUSPENDED;
2126 }
2127 }
Richard Barryc66301a2009-05-21 12:23:24 +00002128
Richard Barry7a8eb502007-07-28 16:33:07 +00002129 return xReturn;
2130 }
2131
2132#endif
Richard Barry2b174e52008-02-25 18:54:28 +00002133/*-----------------------------------------------------------*/
Richard Barryb6df57c2006-05-02 09:39:15 +00002134
Richard Barry60338bd2007-08-21 16:54:48 +00002135#if ( configUSE_MUTEXES == 1 )
Richard Barryc66301a2009-05-21 12:23:24 +00002136
Richard Barry60338bd2007-08-21 16:54:48 +00002137 void vTaskPriorityInherit( xTaskHandle * const pxMutexHolder )
2138 {
2139 tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
2140
2141 if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )
2142 {
2143 /* Adjust the mutex holder state to account for its new priority. */
2144 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxCurrentTCB->uxPriority );
2145
Richard Barrydfb8e702008-01-22 18:43:03 +00002146 /* If the task being modified is in the ready state it will need to
Richard Barry60338bd2007-08-21 16:54:48 +00002147 be moved in to a new list. */
2148 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) )
2149 {
2150 vListRemove( &( pxTCB->xGenericListItem ) );
2151
2152 /* Inherit the priority before being moved into the new list. */
2153 pxTCB->uxPriority = pxCurrentTCB->uxPriority;
2154 prvAddTaskToReadyQueue( pxTCB );
2155 }
2156 else
2157 {
2158 /* Just inherit the priority. */
2159 pxTCB->uxPriority = pxCurrentTCB->uxPriority;
2160 }
2161 }
2162 }
2163
2164#endif
Richard Barry2b174e52008-02-25 18:54:28 +00002165/*-----------------------------------------------------------*/
Richard Barry60338bd2007-08-21 16:54:48 +00002166
Richard Barryc66301a2009-05-21 12:23:24 +00002167#if ( configUSE_MUTEXES == 1 )
Richard Barry60338bd2007-08-21 16:54:48 +00002168
2169 void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder )
2170 {
2171 tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
2172
2173 if( pxMutexHolder != NULL )
2174 {
2175 if( pxTCB->uxPriority != pxTCB->uxBasePriority )
2176 {
2177 /* We must be the running task to be able to give the mutex back.
2178 Remove ourselves from the ready list we currently appear in. */
2179 vListRemove( &( pxTCB->xGenericListItem ) );
2180
2181 /* Disinherit the priority before adding ourselves into the new
2182 ready list. */
2183 pxTCB->uxPriority = pxTCB->uxBasePriority;
2184 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxTCB->uxPriority );
2185 prvAddTaskToReadyQueue( pxTCB );
2186 }
2187 }
2188 }
2189
2190#endif
Richard Barry2b174e52008-02-25 18:54:28 +00002191/*-----------------------------------------------------------*/
Richard Barry60338bd2007-08-21 16:54:48 +00002192
Richard Barry2b174e52008-02-25 18:54:28 +00002193#if ( portCRITICAL_NESTING_IN_TCB == 1 )
2194
2195 void vTaskEnterCritical( void )
2196 {
2197 portDISABLE_INTERRUPTS();
2198
2199 if( xSchedulerRunning != pdFALSE )
2200 {
2201 pxCurrentTCB->uxCriticalNesting++;
2202 }
2203 }
2204
2205#endif
2206/*-----------------------------------------------------------*/
2207
2208#if ( portCRITICAL_NESTING_IN_TCB == 1 )
2209
2210void vTaskExitCritical( void )
2211{
2212 if( xSchedulerRunning != pdFALSE )
2213 {
2214 if( pxCurrentTCB->uxCriticalNesting > 0 )
2215 {
2216 pxCurrentTCB->uxCriticalNesting--;
2217
2218 if( pxCurrentTCB->uxCriticalNesting == 0 )
2219 {
2220 portENABLE_INTERRUPTS();
2221 }
2222 }
2223 }
2224}
2225
2226#endif
2227/*-----------------------------------------------------------*/
2228
Richard Barry60338bd2007-08-21 16:54:48 +00002229
Richard Barryc66301a2009-05-21 12:23:24 +00002230
Richard Barryb6df57c2006-05-02 09:39:15 +00002231