Add stack check macros.

This commit is contained in:
Richard Barry 2008-03-03 20:56:55 +00:00
parent 71ef3153ea
commit 39f6b0b5de
3 changed files with 108 additions and 199 deletions

View file

@ -118,8 +118,8 @@
#error Missing definition: configUSE_16_BIT_TICKS should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. #error Missing definition: configUSE_16_BIT_TICKS should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
#endif #endif
#ifndef INCLUDE_uxGetStackHighWaterMark #ifndef INCLUDE_uxTaskGetStackHighWaterMark
#define INCLUDE_uxGetStackHighWaterMark 0 #define INCLUDE_uxTaskGetStackHighWaterMark 0
#endif #endif
#ifndef configUSE_RECURSIVE_MUTEXES #ifndef configUSE_RECURSIVE_MUTEXES
@ -189,6 +189,9 @@
#define traceBLOCKING_ON_QUEUE_SEND( pxQueue ) #define traceBLOCKING_ON_QUEUE_SEND( pxQueue )
#endif #endif
#ifndef configCHECK_FOR_STACK_OVERFLOW
#define configCHECK_FOR_STACK_OVERFLOW 0
#endif
/* The following event macros are embedded in the kernel API calls. */ /* The following event macros are embedded in the kernel API calls. */

View file

@ -868,9 +868,9 @@ unsigned portLONG ulTaskEndTrace( void );
/** /**
* task.h * task.h
* <PRE>unsigned portBASE_TYPE uxGetStackHighWaterMark( void );</PRE> * <PRE>unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( void );</PRE>
* *
* INCLUDE_uxGetStackHighWaterMark must be set to 1 in FreeRTOSConfig.h for * INCLUDE_uxTaskGetStackHighWaterMark must be set to 1 in FreeRTOSConfig.h for
* this function to be available. * this function to be available.
* *
* Returns the high water mark for the stack of the calling task. That is, * Returns the high water mark for the stack of the calling task. That is,
@ -878,7 +878,7 @@ unsigned portLONG ulTaskEndTrace( void );
* started. The small the returned number the closer the task has come * started. The small the returned number the closer the task has come
* to overflowing its stack. * to overflowing its stack.
*/ */
unsigned portBASE_TYPE uxGetStackHighWaterMark( void ); unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( void );
/*----------------------------------------------------------- /*-----------------------------------------------------------
* SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES

View file

@ -25,11 +25,11 @@
*************************************************************************** ***************************************************************************
Please ensure to read the configuration and relevant port sections of the Please ensure to read the configuration and relevant port sections of the
online documentation. online documentation.
+++ http://www.FreeRTOS.org +++ +++ http://www.FreeRTOS.org +++
Documentation, latest information, license and contact details. Documentation, latest information, license and contact details.
+++ http://www.SafeRTOS.com +++ +++ http://www.SafeRTOS.com +++
A version that is certified for use in safety critical systems. A version that is certified for use in safety critical systems.
@ -40,180 +40,6 @@
*************************************************************************** ***************************************************************************
*/ */
/*
Changes from V1.00:
+ Call to portRESTORE_CONTEXT has been removed. The first context
switch is now performed within sPortStartScheduler().
Changes from V1.01:
+ More use of 8bit data types.
+ Function name prefixes changed where the data type returned has changed.
+ configUSE_TRACE_FACILITY is no longer defined by default.
Changes from V1.2.0
+ Introduced ucTopReadyPriority. This tracks the highest priority ready
queue that contains a valid TCB and thus makes the context switch
slightly faster.
+ prvAddTaskToReadyQueue() has been made a macro.
Changes from V1.2.6
+ Added conditional compilation directives.
+ Extended API.
+ Rearranged function order.
+ Creating a task now causes a context switch if the task being created
has a higher priority than the calling task - assuming the kernel is
running.
+ vTaskDelete() now only causes a context switch if the calling task is
the task being deleted.
Changes from V2.0.0
+ Allow the type of the tick count to be 16 or 32 bits.
+ Introduce xPendingReadyList feature to allow the time interrupts have to
be disabled to be minimised.
+ Remove the #if( INCLUDE_vTaskSuspendAll ) statements. vTaskSuspendAll()
is now always included as it is used by the scheduler itself.
Changes from V2.1.0
+ Bug fix - pxCurrentTCB is now initialised before the call to
prvInitializeTaskLists(). Previously pxCurrentTCB could be accessed
while null.
Changed from V2.1.1
+ Change to where lStackSize is declared within sTaskCreate() to prevent
compiler warnings with 8051 port.
Changes from V2.2.0
+ Explicit use of 'signed' qualifier on portCHAR types added.
+ Changed odd calculation of initial pxTopOfStack value when
portSTACK_GROWTH < 0.
+ Removed pcVersionNumber definition.
Changes from V2.5.3
+ cTaskResumeAll() modified to ensure it can be called prior to the task
lists being initialised.
Changes from V2.5.5
+ Added API function vTaskDelayUntil().
+ Added INCLUDE_vTaskDelay conditional compilation.
Changes from V2.6.0
+ Updated the vWriteTraceToBuffer macro to always be 4 byte aligned so it
can be used on ARM architectures.
+ tskMAX_TASK_NAME_LEN definition replaced with the port specific
configMAX_TASK_NAME_LEN definition.
+ Removed the call to strcpy when copying across the task name into the
TCB.
+ Added ucTasksDeleted variable to prevent vTaskSuspendAll() being called
too often in the idle task.
Changes between V3.0.0 and V2.6.1
+ When resuming the scheduler a yield is performed if either a tick has
been missed, or a task is moved from the pending ready list into a ready
list. Previously a yield was not performed on this second condition.
+ Introduced the type portBASE_TYPE. This necessitates several API
changes.
+ Removed the sUsingPreemption variable. The constant defined in
portmacro.h is now used directly.
+ The idle task can now include an optional hook function - and no longer
completes its time slice if other tasks with equal priority to it are
ready to run.
+ See the FreeRTOS.org documentation for more information on V2.x.x to
V3.x.x modifications.
Changes from V3.1.1
+ Modified vTaskPrioritySet() and vTaskResume() to allow these functions to
be called while the scheduler is suspended.
+ Corrected the task ordering within event lists.
Changes from V3.2.0
+ Added function xTaskGetCurrentTaskHandle().
Changes from V3.2.4
+ Changed the volatile declarations on some variables to reflect the
changes to the list definitions.
+ Changed the order of the TCB definition so there is commonality between
the task control block and a co-routine control block.
+ Allow the scheduler to be started even if no tasks other than the idle
task has been created. This allows co-routines to run even when no tasks
have been created.
+ The need for a context switch is now signalled if a task woken by an
event has a priority greater or equal to the currently running task.
Previously this was only greater than.
Changes from V4.0.0
+ Added the xMissedYield handling.
Changes from V4.0.1
+ The function vTaskList() now suspends the scheduler rather than disabling
interrupts during the creation of the task list.
+ Allow a task to delete itself by passing in its own handle. Previously
this could only be done by passing in NULL.
+ The tick hook function is now called only within a tick isr. Previously
it was also called when the tick function was called during the scheduler
unlocking process.
Changes from V4.0.3
+ Extra checks have been placed in vTaskPrioritySet() to avoid unnecessary
yields.
Changed from V4.0.4
+ Bug fix: The 'value' of the event list item is updated when the priority
of a task is changed. Previously only the priority of the TCB itself was
changed.
+ When resuming a task a check is first made to see if the task is actually
suspended.
+ vTaskPrioritySet() and vTaskResume() no longer use the event list item.
This has not been necessary since V4.0.1 when the xMissedYield handling
was added.
+ Implement xTaskResumeFromISR().
Changes from V4.0.5
+ Added utility functions and xOverflowCount variable to facilitate the
queue.c changes.
Changes from V4.1.2
+ Tasks that block on events with a timeout of portMAX_DELAY are now
blocked indefinitely if configINCLUDE_vTaskSuspend is defined.
Previously portMAX_DELAY was just the longest block time possible.
Changes from V4.1.3
+ Very small change made to xTaskCheckForTimeout() as a result of the
SafeRTOS testing. This corrects the case where the function can return an
invalid value - but only in an extremely unlikely scenario.
Changes since V4.3.1:
+ Added xTaskGetSchedulerState() function.
+ Added prvIsTaskSuspended() to take into account the Occurrence of
vTaskResume() or vTaskResumeFromISR() being called passing in the
handle of a task that appears in the Suspended list only because it
is blocked on an event without a timeout being specified.
+ Updated xTaskCheckForTimeout() to take into account that tasks blocked
using the Suspended list should never time out.
*/
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -345,6 +171,8 @@ static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0;
#endif #endif
/*-----------------------------------------------------------*/
/* /*
* Macro that writes a trace of scheduler activity to a buffer. This trace * Macro that writes a trace of scheduler activity to a buffer. This trace
* shows which task is running when and is very useful as a debugging tool. * shows which task is running when and is very useful as a debugging tool.
@ -382,7 +210,7 @@ static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0;
#define vWriteTraceToBuffer() #define vWriteTraceToBuffer()
#endif #endif
/*-----------------------------------------------------------*/
/* /*
* Place the task represented by pxTCB into the appropriate ready queue for * Place the task represented by pxTCB into the appropriate ready queue for
@ -398,7 +226,8 @@ static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0;
uxTopReadyPriority = pxTCB->uxPriority; \ uxTopReadyPriority = pxTCB->uxPriority; \
} \ } \
vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ); \ vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ); \
} }
/*-----------------------------------------------------------*/
/* /*
* Macro that looks at the list of tasks that are currently delayed to see if * Macro that looks at the list of tasks that are currently delayed to see if
@ -424,9 +253,82 @@ register tskTCB *pxTCB; \
{ \ { \
vListRemove( &( pxTCB->xEventListItem ) ); \ vListRemove( &( pxTCB->xEventListItem ) ); \
} \ } \
prvAddTaskToReadyQueue( pxTCB ); \ prvAddTaskToReadyQueue( pxTCB ); \
} \ } \
} }
/*-----------------------------------------------------------*/
/*
* Call the stack overflow hook function if the stack of the task being swapped
* out is currently overflowed, or looks like it might have overflowed in the
* past.
*
* Setting configCHECK_FOR_STACK_OVERFLOW to 1 will cause the macro to check
* the current stack state only - comparing the current top of stack value to
* the stack limit. Setting configCHECK_FOR_STACK_OVERFLOW to greater than 1
* will also cause the last few stack bytes to be checked to ensure the value
* to which the bytes were set when the task was created have not been
* overwritten. Note this second test does not guarantee that an overflown
* stack will always be recognised.
*/
#if( configCHECK_FOR_STACK_OVERFLOW == 0 )
/* FreeRTOSConfig.h is not set to check for stack overflows. */
#define taskCHECK_FOR_STACK_OVERFLOW()
#endif /* configCHECK_FOR_STACK_OVERFLOW == 0 */
#if( ( configCHECK_FOR_STACK_OVERFLOW > 0 ) && ( portSTACK_GROWTH >= 0 ) )
/* This is an invalid setting. */
#error configCHECK_FOR_STACK_OVERFLOW can only be set to a non zero value on architectures where the stack grows down from high memory.
#endif /* ( configCHECK_FOR_STACK_OVERFLOW > 0 ) && ( portSTACK_GROWTH >= 0 ) */
#if( configCHECK_FOR_STACK_OVERFLOW == 1 )
/* Only the current stack state is to be checked. */
#define taskCHECK_FOR_STACK_OVERFLOW() \
{ \
extern void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed portCHAR *pcTaskName ); \
\
/* Is the currently saved stack pointer within the stack limit? */ \
if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack ) \
{ \
vApplicationStackOverflowHook( pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
} \
}
#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */
#if( configCHECK_FOR_STACK_OVERFLOW > 1 )
/* Both the current statck state and the stack fill bytes are to be checked. */
#define taskCHECK_FOR_STACK_OVERFLOW() \
{ \
extern void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed portCHAR *pcTaskName ); \
static const unsigned portCHAR ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \
\
/* Is the currently saved stack pointer within the stack limit? */ \
if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack ) \
{ \
vApplicationStackOverflowHook( pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
} \
\
/* Has the extremity of the task stack ever been written over? */ \
if( memcmp( pxCurrentTCB->pxStack, ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \
{ \
vApplicationStackOverflowHook( pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
} \
}
#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */
/*-----------------------------------------------------------*/
/* /*
* Several functions take an xTaskHandle parameter that can optionally be NULL, * Several functions take an xTaskHandle parameter that can optionally be NULL,
@ -508,7 +410,7 @@ static tskTCB *prvAllocateTCBAndStack( unsigned portSHORT usStackDepth );
* This function determines the 'high water mark' of the task stack by * This function determines the 'high water mark' of the task stack by
* determining how much of the stack remains at the original preset value. * determining how much of the stack remains at the original preset value.
*/ */
#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxGetStackHighWaterMark == 1 ) ) #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR * pucStackByte ); unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR * pucStackByte );
@ -528,8 +430,6 @@ static tskTCB *prvAllocateTCBAndStack( unsigned portSHORT usStackDepth );
/*----------------------------------------------------------- /*-----------------------------------------------------------
* TASK CREATION API documented in task.h * TASK CREATION API documented in task.h
*----------------------------------------------------------*/ *----------------------------------------------------------*/
@ -663,7 +563,7 @@ tskTCB * pxNewTCB;
taskENTER_CRITICAL(); taskENTER_CRITICAL();
{ {
/* Ensure a yield is performed if the current task is being /* Ensure a yield is performed if the current task is being
deleted. */ deleted. */
if( pxTaskToDelete == pxCurrentTCB ) if( pxTaskToDelete == pxCurrentTCB )
{ {
@ -697,7 +597,7 @@ tskTCB * pxNewTCB;
taskEXIT_CRITICAL(); taskEXIT_CRITICAL();
/* Force a reschedule if we have just deleted the current task. */ /* Force a reschedule if we have just deleted the current task. */
if( xSchedulerRunning != pdFALSE ) if( xSchedulerRunning != pdFALSE )
{ {
if( ( void * ) pxTaskToDelete == NULL ) if( ( void * ) pxTaskToDelete == NULL )
{ {
@ -912,7 +812,7 @@ tskTCB * pxNewTCB;
{ {
/* The priority change may have readied a task of higher /* The priority change may have readied a task of higher
priority than the calling task. */ priority than the calling task. */
if( uxNewPriority > uxCurrentPriority ) if( uxNewPriority > uxCurrentPriority )
{ {
if( pxTask != NULL ) if( pxTask != NULL )
{ {
@ -985,7 +885,7 @@ tskTCB * pxNewTCB;
taskENTER_CRITICAL(); taskENTER_CRITICAL();
{ {
/* Ensure a yield is performed if the current task is being /* Ensure a yield is performed if the current task is being
suspended. */ suspended. */
if( pxTaskToSuspend == pxCurrentTCB ) if( pxTaskToSuspend == pxCurrentTCB )
{ {
@ -1407,8 +1307,8 @@ inline void vTaskIncrementTick( void )
{ {
xList *pxTemp; xList *pxTemp;
/* Tick count has overflowed so we need to swap the delay lists. /* Tick count has overflowed so we need to swap the delay lists.
If there are any items in pxDelayedTaskList here then there is If there are any items in pxDelayedTaskList here then there is
an error! */ an error! */
pxTemp = pxDelayedTaskList; pxTemp = pxDelayedTaskList;
pxDelayedTaskList = pxOverflowDelayedTaskList; pxDelayedTaskList = pxOverflowDelayedTaskList;
@ -1423,7 +1323,7 @@ inline void vTaskIncrementTick( void )
{ {
++uxMissedTicks; ++uxMissedTicks;
/* The tick hook gets called at regular intervals, even if the /* The tick hook gets called at regular intervals, even if the
scheduler is locked. */ scheduler is locked. */
#if ( configUSE_TICK_HOOK == 1 ) #if ( configUSE_TICK_HOOK == 1 )
{ {
@ -1514,6 +1414,8 @@ void vTaskSwitchContext( void )
return; return;
} }
taskCHECK_FOR_STACK_OVERFLOW();
/* Find the highest priority queue that contains ready tasks. */ /* Find the highest priority queue that contains ready tasks. */
while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) ) while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) )
{ {
@ -1548,7 +1450,7 @@ portTickType xTimeToWake;
#if ( INCLUDE_vTaskSuspend == 1 ) #if ( INCLUDE_vTaskSuspend == 1 )
{ {
if( xTicksToWait == portMAX_DELAY ) if( xTicksToWait == portMAX_DELAY )
{ {
/* Add ourselves to the suspended task list instead of a delayed task /* Add ourselves to the suspended task list instead of a delayed task
@ -1933,7 +1835,8 @@ tskTCB *pxNewTCB;
#endif #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxGetStackHighWaterMark == 1 ) ) #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR * pucStackByte ) unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR * pucStackByte )
{ {
register unsigned portSHORT usCount = 0; register unsigned portSHORT usCount = 0;
@ -1948,14 +1851,17 @@ tskTCB *pxNewTCB;
return usCount; return usCount;
} }
#endif #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( INCLUDE_uxGetStackHighWaterMark == 1 ) #if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )
unsigned portBASE_TYPE uxGetStackHighWaterMark( void )
unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( void )
{ {
return usTaskCheckFreeStackSpace( pxCurrentTCB->pxStack ); return usTaskCheckFreeStackSpace( pxCurrentTCB->pxStack );
} }
#endif #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/