From 99cceb5283888b1f6d9f60ed8a95a76c53aac23f Mon Sep 17 00:00:00 2001 From: rtel Date: Thu, 12 Dec 2013 10:19:07 +0000 Subject: [PATCH] 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. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2128 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- FreeRTOS/Source/event_groups.c | 27 ++++++++++ FreeRTOS/Source/include/FreeRTOS.h | 50 +++++++++++++++++-- FreeRTOS/Source/include/task.h | 4 +- FreeRTOS/Source/portable/MSVC-MingW/port.c | 45 +++++++++++++++-- .../Source/portable/MSVC-MingW/portmacro.h | 8 +-- FreeRTOS/Source/tasks.c | 11 +++- 6 files changed, 129 insertions(+), 16 deletions(-) diff --git a/FreeRTOS/Source/event_groups.c b/FreeRTOS/Source/event_groups.c index 70011c388..644539965 100644 --- a/FreeRTOS/Source/event_groups.c +++ b/FreeRTOS/Source/event_groups.c @@ -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 diff --git a/FreeRTOS/Source/include/FreeRTOS.h b/FreeRTOS/Source/include/FreeRTOS.h index 7832f5547..e4a1edd31 100644 --- a/FreeRTOS/Source/include/FreeRTOS.h +++ b/FreeRTOS/Source/include/FreeRTOS.h @@ -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 diff --git a/FreeRTOS/Source/include/task.h b/FreeRTOS/Source/include/task.h index 956556e67..288c783fe 100644 --- a/FreeRTOS/Source/include/task.h +++ b/FreeRTOS/Source/include/task.h @@ -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 diff --git a/FreeRTOS/Source/portable/MSVC-MingW/port.c b/FreeRTOS/Source/portable/MSVC-MingW/port.c index 35e40cb61..8e8e82d5f 100644 --- a/FreeRTOS/Source/portable/MSVC-MingW/port.c +++ b/FreeRTOS/Source/portable/MSVC-MingW/port.c @@ -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; + + /* 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; - ReleaseMutex( pvInterruptEventMutex ); + /* Close the thread. */ + CloseHandle( pvThread ); + ExitThread( 0 ); } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Source/portable/MSVC-MingW/portmacro.h b/FreeRTOS/Source/portable/MSVC-MingW/portmacro.h index 518223622..03a9bc981 100644 --- a/FreeRTOS/Source/portable/MSVC-MingW/portmacro.h +++ b/FreeRTOS/Source/portable/MSVC-MingW/portmacro.h @@ -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 ) ); diff --git a/FreeRTOS/Source/tasks.c b/FreeRTOS/Source/tasks.c index bf7475ab1..c3284ca3e 100644 --- a/FreeRTOS/Source/tasks.c +++ b/FreeRTOS/Source/tasks.c @@ -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; -- 2.39.5