From f391529f3850e080072606e3324a5deb8410e77f Mon Sep 17 00:00:00 2001 From: richardbarry Date: Mon, 3 Mar 2008 20:56:55 +0000 Subject: [PATCH] Add stack check macros. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@224 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- Source/include/FreeRTOS.h | 7 +- Source/include/task.h | 6 +- Source/tasks.c | 294 +++++++++++++------------------------- 3 files changed, 108 insertions(+), 199 deletions(-) diff --git a/Source/include/FreeRTOS.h b/Source/include/FreeRTOS.h index 585aebf8e..5fcd9e7a2 100644 --- a/Source/include/FreeRTOS.h +++ b/Source/include/FreeRTOS.h @@ -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. #endif -#ifndef INCLUDE_uxGetStackHighWaterMark - #define INCLUDE_uxGetStackHighWaterMark 0 +#ifndef INCLUDE_uxTaskGetStackHighWaterMark + #define INCLUDE_uxTaskGetStackHighWaterMark 0 #endif #ifndef configUSE_RECURSIVE_MUTEXES @@ -189,6 +189,9 @@ #define traceBLOCKING_ON_QUEUE_SEND( pxQueue ) #endif +#ifndef configCHECK_FOR_STACK_OVERFLOW + #define configCHECK_FOR_STACK_OVERFLOW 0 +#endif /* The following event macros are embedded in the kernel API calls. */ diff --git a/Source/include/task.h b/Source/include/task.h index be136e740..98f1cb78f 100644 --- a/Source/include/task.h +++ b/Source/include/task.h @@ -868,9 +868,9 @@ unsigned portLONG ulTaskEndTrace( void ); /** * task.h - *
unsigned portBASE_TYPE uxGetStackHighWaterMark( void );
+ *
unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( void );
* - * 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. * * 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 * to overflowing its stack. */ -unsigned portBASE_TYPE uxGetStackHighWaterMark( void ); +unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( void ); /*----------------------------------------------------------- * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES diff --git a/Source/tasks.c b/Source/tasks.c index 15e61cf1b..ad65c144e 100644 --- a/Source/tasks.c +++ b/Source/tasks.c @@ -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. +++ http://www.FreeRTOS.org +++ - Documentation, latest information, license and contact details. + Documentation, latest information, license and contact details. +++ http://www.SafeRTOS.com +++ 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 #include @@ -345,6 +171,8 @@ static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0; #endif +/*-----------------------------------------------------------*/ + /* * 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. @@ -382,7 +210,7 @@ static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0; #define vWriteTraceToBuffer() #endif - +/*-----------------------------------------------------------*/ /* * 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; \ } \ vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ); \ -} +} +/*-----------------------------------------------------------*/ /* * 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 ) ); \ } \ - 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, @@ -508,7 +410,7 @@ static tskTCB *prvAllocateTCBAndStack( unsigned portSHORT usStackDepth ); * This function determines the 'high water mark' of the task stack by * 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 ); @@ -528,8 +430,6 @@ static tskTCB *prvAllocateTCBAndStack( unsigned portSHORT usStackDepth ); - - /*----------------------------------------------------------- * TASK CREATION API documented in task.h *----------------------------------------------------------*/ @@ -663,7 +563,7 @@ tskTCB * pxNewTCB; 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. */ if( pxTaskToDelete == pxCurrentTCB ) { @@ -697,7 +597,7 @@ tskTCB * pxNewTCB; taskEXIT_CRITICAL(); /* Force a reschedule if we have just deleted the current task. */ - if( xSchedulerRunning != pdFALSE ) + if( xSchedulerRunning != pdFALSE ) { if( ( void * ) pxTaskToDelete == NULL ) { @@ -912,7 +812,7 @@ tskTCB * pxNewTCB; { /* The priority change may have readied a task of higher priority than the calling task. */ - if( uxNewPriority > uxCurrentPriority ) + if( uxNewPriority > uxCurrentPriority ) { if( pxTask != NULL ) { @@ -985,7 +885,7 @@ tskTCB * pxNewTCB; 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. */ if( pxTaskToSuspend == pxCurrentTCB ) { @@ -1407,8 +1307,8 @@ inline void vTaskIncrementTick( void ) { xList *pxTemp; - /* Tick count has overflowed so we need to swap the delay lists. - If there are any items in pxDelayedTaskList here then there is + /* Tick count has overflowed so we need to swap the delay lists. + If there are any items in pxDelayedTaskList here then there is an error! */ pxTemp = pxDelayedTaskList; pxDelayedTaskList = pxOverflowDelayedTaskList; @@ -1423,7 +1323,7 @@ inline void vTaskIncrementTick( void ) { ++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. */ #if ( configUSE_TICK_HOOK == 1 ) { @@ -1514,6 +1414,8 @@ void vTaskSwitchContext( void ) return; } + taskCHECK_FOR_STACK_OVERFLOW(); + /* Find the highest priority queue that contains ready tasks. */ while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) ) { @@ -1548,7 +1450,7 @@ portTickType xTimeToWake; #if ( INCLUDE_vTaskSuspend == 1 ) - { + { if( xTicksToWait == portMAX_DELAY ) { /* Add ourselves to the suspended task list instead of a delayed task @@ -1933,7 +1835,8 @@ tskTCB *pxNewTCB; #endif /*-----------------------------------------------------------*/ -#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxGetStackHighWaterMark == 1 ) ) +#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) + unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR * pucStackByte ) { register unsigned portSHORT usCount = 0; @@ -1948,14 +1851,17 @@ tskTCB *pxNewTCB; return usCount; } + #endif /*-----------------------------------------------------------*/ -#if ( INCLUDE_uxGetStackHighWaterMark == 1 ) - unsigned portBASE_TYPE uxGetStackHighWaterMark( void ) +#if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) + + unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( void ) { return usTaskCheckFreeStackSpace( pxCurrentTCB->pxStack ); } + #endif /*-----------------------------------------------------------*/ -- 2.39.5