Add trace macros into the event groups implementation.

Add a task pre-delete hook to allow the insertion of any port specific clean up when a task is deleted.
Increase use of 'const' qualifiers.
Add vPortCloseRunningThread() into the Win32 port layer to attempt to allow Windows threads to be closed more gracefully when a task deletes itself.
This commit is contained in:
Richard Barry 2013-12-12 10:19:07 +00:00
parent 0416289066
commit 6b3393b4b6
6 changed files with 129 additions and 16 deletions

View File

@ -128,6 +128,11 @@ xEVENT_BITS *pxEventBits;
{
pxEventBits->uxEventBits = 0;
vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );
traceEVENT_GROUP_CREATE( pxEventBits );
}
else
{
traceEVENT_GROUP_CREATE_FAILED();
}
return ( xEventGroupHandle ) pxEventBits;
@ -148,6 +153,8 @@ portBASE_TYPE xYieldedAlready;
vTaskSuspendAll();
{
traceEVENT_GROUP_SYNC_START( xEventGroup, uxBitsToSet );
uxOriginalBitValue = pxEventBits->uxEventBits;
( void ) xEventGroupSetBits( xEventGroup, uxBitsToSet );
@ -172,6 +179,11 @@ portBASE_TYPE xYieldedAlready;
task's event list item so the kernel knows when a match is
found. Then enter the blocked state. */
vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | taskCLEAR_EVENTS_ON_EXIT_BIT | taskWAIT_FOR_ALL_BITS ), xTicksToWait );
/* This is obsolete as it will get set after the task unblocks,
but some compilers mistakenly generate a warning about the
variable being returned without being set if it is not done. */
uxReturn = 0;
}
else
{
@ -209,6 +221,7 @@ portBASE_TYPE xYieldedAlready;
}
}
traceEVENT_GROUP_SYNC_END( xEventGroup, uxReturn );
return uxReturn;
}
/*-----------------------------------------------------------*/
@ -232,6 +245,8 @@ xEventBitsType uxReturn, uxControlBits = 0;
{
const xEventBitsType uxCurrentEventBits = pxEventBits->uxEventBits;
traceEVENT_GROUP_WAIT_BITS_START( xEventGroup, uxBitsToWaitFor );
if( xWaitForAllBits == pdFALSE )
{
/* Task only has to wait for one bit within uxBitsToWaitFor to be set. Is
@ -288,6 +303,11 @@ xEventBitsType uxReturn, uxControlBits = 0;
found. Then enter the blocked state. */
vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | uxControlBits ), xTicksToWait );
portYIELD_WITHIN_API();
/* This is obsolete as it will get set after the task unblocks, but
some compilers mistakenly generate a warning about the variable
being returned without being set if it is not done. */
uxReturn = 0;
}
}
taskEXIT_CRITICAL();
@ -313,6 +333,7 @@ xEventBitsType uxReturn, uxControlBits = 0;
}
}
traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxReturn );
return uxReturn;
}
/*-----------------------------------------------------------*/
@ -329,6 +350,8 @@ xEventBitsType uxReturn;
uxBitsToClear = ~uxBitsToClear;
taskENTER_CRITICAL();
{
traceEVENT_GROUP_CLEAR_BITS( xEventGroup, ~uxBitsToClear );
/* The value returned is the event group value prior to the bits being
cleared. */
uxReturn = pxEventBits->uxEventBits;
@ -359,6 +382,8 @@ portBASE_TYPE xMatchFound = pdFALSE;
pxListEnd = listGET_END_MARKER( pxList ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */
vTaskSuspendAll();
{
traceEVENT_GROUP_SET_BITS( xEventGroup, uxBitsToSet );
pxListItem = listGET_HEAD_ENTRY( pxList );
/* Set the bits. */
@ -432,6 +457,8 @@ const xList *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits );
vTaskSuspendAll();
{
traceEVENT_GROUP_DELETE( xEventGroup );
while( listCURRENT_LIST_LENGTH( pxTasksWaitingForBits ) > ( unsigned portBASE_TYPE ) 0 )
{
/* Unblock the task, returning 0 as the event list is being deleted

View File

@ -136,11 +136,11 @@ typedef portTickType xEventBitsType;
#endif
#ifndef INCLUDE_vTaskDelete
#error Missing definition: INCLUDE_vTaskDelete must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
#error Missing definition: INCLUDE_vTaskDelete must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
#endif
#ifndef INCLUDE_vTaskSuspend
#error Missing definition: INCLUDE_vTaskSuspend must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
#error Missing definition: INCLUDE_vTaskSuspend must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
#endif
#ifndef INCLUDE_vTaskDelayUntil
@ -156,13 +156,13 @@ typedef portTickType xEventBitsType;
#endif
#if configUSE_CO_ROUTINES != 0
#if configMAX_CO_ROUTINE_PRIORITIES < 1
#ifndef configMAX_CO_ROUTINE_PRIORITIES
#error configMAX_CO_ROUTINE_PRIORITIES must be greater than or equal to 1.
#endif
#endif
#if configMAX_PRIORITIES < 1
#error configMAX_PRIORITIES must be greater than or equal to 1.
#ifndef configMAX_PRIORITIES
#error configMAX_PRIORITIES must be defined to be greater than or equal to 1.
#endif
#ifndef INCLUDE_xTaskGetIdleTaskHandle
@ -294,6 +294,10 @@ typedef portTickType xEventBitsType;
#define portCLEAN_UP_TCB( pxTCB ) ( void ) pxTCB
#endif
#ifndef portPRE_DELETE_HOOK
#define portPRE_DELETE_HOOK( pvTaskToDelete, pxYieldPending )
#endif
#ifndef portSETUP_TCB
#define portSETUP_TCB( pxTCB ) ( void ) pxTCB
#endif
@ -551,6 +555,42 @@ typedef portTickType xEventBitsType;
#define traceFREE( pvAddress, uiSize )
#endif
#ifndef traceEVENT_GROUP_CREATE
#define traceEVENT_GROUP_CREATE( xEventGroup )
#endif
#ifndef traceEVENT_GROUP_CREATE_FAILED
#define traceEVENT_GROUP_CREATE_FAILED()
#endif
#ifndef traceEVENT_GROUP_SYNC_START
#define traceEVENT_GROUP_SYNC_START( xEventGroup, uxBitsToSet )
#endif
#ifndef traceEVENT_GROUP_SYNC_END
#define traceEVENT_GROUP_SYNC_END( xEventGroup, uxReturn )
#endif
#ifndef traceEVENT_GROUP_WAIT_BITS_START
#define traceEVENT_GROUP_WAIT_BITS_START( xEventGroup, uxBitsToWaitFor )
#endif
#ifndef traceEVENT_GROUP_WAIT_BITS_END
#define traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxReturn )
#endif
#ifndef traceEVENT_GROUP_CLEAR_BITS
#define traceEVENT_GROUP_CLEAR_BITS( xEventGroup, uxBitsToClear )
#endif
#ifndef traceEVENT_GROUP_SET_BITS
#define traceEVENT_GROUP_SET_BITS( xEventGroup, uxBitsToSet )
#endif
#ifndef traceEVENT_GROUP_DELETE
#define traceEVENT_GROUP_DELETE( xEventGroup )
#endif
#ifndef configGENERATE_RUN_TIME_STATS
#define configGENERATE_RUN_TIME_STATS 0
#endif

View File

@ -1412,8 +1412,8 @@ portBASE_TYPE xTaskIncrementTick( void ) PRIVILEGED_FUNCTION;
* portTICK_RATE_MS can be used to convert kernel ticks into a real time
* period.
*/
void vTaskPlaceOnEventList( xList * const pxEventList, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;
void vTaskPlaceOnUnorderedEventList( xList * pxEventList, portTickType xItemValue, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;
void vTaskPlaceOnEventList( xList * const pxEventList, const portTickType xTicksToWait ) PRIVILEGED_FUNCTION;
void vTaskPlaceOnUnorderedEventList( xList * pxEventList, portTickType xItemValue, const portTickType xTicksToWait ) PRIVILEGED_FUNCTION;
/*
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN

View File

@ -244,6 +244,7 @@ char *pcTopOfStack = ( char * ) pxTopOfStack;
/* Create the thread itself. */
pxThreadState->pvThread = CreateThread( NULL, 0, ( LPTHREAD_START_ROUTINE ) pxCode, pvParameters, CREATE_SUSPENDED, NULL );
configASSERT( pxThreadState->pvThread );
SetThreadAffinityMask( pxThreadState->pvThread, 0x01 );
SetThreadPriorityBoost( pxThreadState->pvThread, TRUE );
SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_IDLE );
@ -418,13 +419,51 @@ void vPortDeleteThread( void *pvTaskToDelete )
{
xThreadState *pxThreadState;
WaitForSingleObject( pvInterruptEventMutex, INFINITE );
/* Find the handle of the thread being deleted. */
pxThreadState = ( xThreadState * ) ( *( unsigned long *) pvTaskToDelete );
/* Check that the thread is still valid, it might have been closed by
vPortCloseRunningThread() - which will be the case if the task associated
with the thread originally deleted itself rather than being deleted by a
different task. */
if( pxThreadState->pvThread != NULL )
{
WaitForSingleObject( pvInterruptEventMutex, INFINITE );
CloseHandle( pxThreadState->pvThread );
TerminateThread( pxThreadState->pvThread, 0 );
ReleaseMutex( pvInterruptEventMutex );
}
}
/*-----------------------------------------------------------*/
void vPortCloseRunningThread( void *pvTaskToDelete, volatile portBASE_TYPE *pxPendYield )
{
xThreadState *pxThreadState;
void *pvThread;
/* Find the handle of the thread being deleted. */
pxThreadState = ( xThreadState * ) ( *( unsigned long *) pvTaskToDelete );
TerminateThread( pxThreadState->pvThread, 0 );
pvThread = pxThreadState->pvThread;
ReleaseMutex( pvInterruptEventMutex );
/* Raise the Windows priority of the thread to ensure the FreeRTOS scheduler
does not run and swap it out before it is closed. If that were to happen
the thread would never run again and effectively be a thread handle and
memory leak. */
SetThreadPriority( pvThread, THREAD_PRIORITY_ABOVE_NORMAL );
/* This function will not return, therefore a yield is set as pending to
ensure a context switch occurs away from this thread on the next tick. */
*pxPendYield = pdTRUE;
/* Mark the thread associated with this task as invalid so
vPortDeleteThread() does not try to terminate it. */
pxThreadState->pvThread = NULL;
/* Close the thread. */
CloseHandle( pvThread );
ExitThread( 0 );
}
/*-----------------------------------------------------------*/

View File

@ -139,7 +139,7 @@ void vPortExitCritical( void );
#define portINTERRUPT_YIELD ( 0UL )
#define portINTERRUPT_TICK ( 1UL )
/*
/*
* Raise a simulated interrupt represented by the bit mask in ulInterruptMask.
* Each bit can be used to represent an individual interrupt - with the first
* two bits being used for the Yield and Tick interrupts respectively.
@ -147,13 +147,13 @@ void vPortExitCritical( void );
void vPortGenerateSimulatedInterrupt( unsigned long ulInterruptNumber );
/*
* Install an interrupt handler to be called by the simulated interrupt handler
* Install an interrupt handler to be called by the simulated interrupt handler
* thread. The interrupt number must be above any used by the kernel itself
* (at the time of writing the kernel was using interrupt numbers 0, 1, and 2
* as defined above). The number must also be lower than 32.
* as defined above). The number must also be lower than 32.
*
* Interrupt handler functions must return a non-zero value if executing the
* handler resulted in a task switch being required.
* handler resulted in a task switch being required.
*/
void vPortSetInterruptHandler( unsigned long ulInterruptNumber, unsigned long (*pvHandler)( void ) );

View File

@ -685,6 +685,13 @@ tskTCB * pxNewTCB;
if( pxTCB == pxCurrentTCB )
{
configASSERT( uxSchedulerSuspended == 0 );
/* The pre-delete hook is primarily for the Windows simulator,
in which Windows specific clean up operations are performed,
after which it is not possible to yield away from this task -
hence xYieldPending is used to latch that a context switch is
required. */
portPRE_DELETE_HOOK( pxTCB, &xYieldPending );
portYIELD_WITHIN_API();
}
}
@ -1896,7 +1903,7 @@ void vTaskSwitchContext( void )
}
/*-----------------------------------------------------------*/
void vTaskPlaceOnEventList( xList * const pxEventList, portTickType xTicksToWait )
void vTaskPlaceOnEventList( xList * const pxEventList, const portTickType xTicksToWait )
{
portTickType xTimeToWake;
@ -1948,7 +1955,7 @@ portTickType xTimeToWake;
}
/*-----------------------------------------------------------*/
void vTaskPlaceOnUnorderedEventList( xList * pxEventList, portTickType xItemValue, portTickType xTicksToWait )
void vTaskPlaceOnUnorderedEventList( xList * pxEventList, portTickType xItemValue, const portTickType xTicksToWait )
{
portTickType xTimeToWake;