From c7d808ad56ae07bba579e297576e246db96d0be9 Mon Sep 17 00:00:00 2001 From: rtel Date: Wed, 23 Apr 2014 15:23:54 +0000 Subject: [PATCH] Event Groups: Convert the 'clear bits from ISR' function into a pended function to fix reentrancy issue. Event Groups: Ensure the 'wait bits' and 'sync' functions don't return values that still contain some internal control bits. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2238 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- FreeRTOS/Source/event_groups.c | 60 +++++++++++++------ FreeRTOS/Source/include/event_groups.h | 58 ++++++++++++++++-- FreeRTOS/Source/include/timers.h | 6 +- FreeRTOS/Source/portable/GCC/ARM_CA9/port.c | 2 + .../Source/portable/GCC/ARM_CA9/portmacro.h | 1 + .../Source/portable/MPLAB/PIC24_dsPIC/port.c | 3 + FreeRTOS/Source/timers.c | 2 +- 7 files changed, 103 insertions(+), 29 deletions(-) diff --git a/FreeRTOS/Source/event_groups.c b/FreeRTOS/Source/event_groups.c index 5b45f9cc7..5efd43273 100644 --- a/FreeRTOS/Source/event_groups.c +++ b/FreeRTOS/Source/event_groups.c @@ -237,7 +237,7 @@ BaseType_t xTimeoutOccurred = pdFALSE; /* Although the task got here because it timed out before the bits it was waiting for were set, it is possible that since it unblocked another task has set the bits. If this is the case - then it may be required to clear the bits before exiting. */ + then it needs to clear the bits before exiting. */ if( ( uxReturn & uxBitsToWaitFor ) == uxBitsToWaitFor ) { pxEventBits->uxEventBits &= ~uxBitsToWaitFor; @@ -253,13 +253,16 @@ BaseType_t xTimeoutOccurred = pdFALSE; } else { - /* The task unblocked because the bits were set. Clear the control - bits before returning the value. */ - uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES; + /* The task unblocked because the bits were set. */ } + + /* Control bits might be set as the task had blocked should not be + returned. */ + uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES; } traceEVENT_GROUP_SYNC_END( xEventGroup, uxBitsToSet, uxBitsToWaitFor, xTimeoutOccurred ); + return uxReturn; } /*-----------------------------------------------------------*/ @@ -394,16 +397,19 @@ BaseType_t xTimeoutOccurred = pdFALSE; } taskEXIT_CRITICAL(); + /* Prevent compiler warnings when trace macros are not used. */ xTimeoutOccurred = pdFALSE; } else { - /* The task unblocked because the bits were set. Clear the control - bits before returning the value. */ - uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES; + /* The task unblocked because the bits were set. */ } + + /* The task blocked so control bits may have been set. */ + uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES; } traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred ); + return uxReturn; } /*-----------------------------------------------------------*/ @@ -434,26 +440,30 @@ EventBits_t uxReturn; } /*-----------------------------------------------------------*/ -EventBits_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) +#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) + + BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) + { + BaseType_t xReturn; + + traceEVENT_GROUP_CLEAR_BITS_FROM_ISR( xEventGroup, uxBitsToClear ); + xReturn = xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL ); + + return xReturn; + } + +#endif +/*-----------------------------------------------------------*/ + +EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup ) { UBaseType_t uxSavedInterruptStatus; EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; EventBits_t uxReturn; - /* Check the user is not attempting to clear the bits used by the kernel - itself. */ - configASSERT( ( uxBitsToClear & eventEVENT_BITS_CONTROL_BYTES ) == 0 ); - uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); { - traceEVENT_GROUP_CLEAR_BITS_FROM_ISR( xEventGroup, uxBitsToClear ); - - /* The value returned is the event group value prior to the bits being - cleared. */ uxReturn = pxEventBits->uxEventBits; - - /* Clear the bits. */ - pxEventBits->uxEventBits &= ~uxBitsToClear; } portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); @@ -585,6 +595,14 @@ void vEventGroupSetBitsCallback( void *pvEventGroup, const uint32_t ulBitsToSet } /*-----------------------------------------------------------*/ +/* For internal use only - execute a 'clear bits' command that was pended from +an interrupt. */ +void vEventGroupClearBitsCallback( void *pvEventGroup, const uint32_t ulBitsToClear ) +{ + ( void ) xEventGroupClearBits( pvEventGroup, ( EventBits_t ) ulBitsToClear ); +} +/*-----------------------------------------------------------*/ + static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, const EventBits_t uxBitsToWaitFor, const BaseType_t xWaitForAllBits ) { BaseType_t xWaitConditionMet = pdFALSE; @@ -621,6 +639,7 @@ BaseType_t xWaitConditionMet = pdFALSE; /*-----------------------------------------------------------*/ #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) + BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken ) { BaseType_t xReturn; @@ -630,10 +649,12 @@ BaseType_t xWaitConditionMet = pdFALSE; return xReturn; } + #endif /*-----------------------------------------------------------*/ #if (configUSE_TRACE_FACILITY == 1) + UBaseType_t uxEventGroupGetNumber( void* xEventGroup ) { UBaseType_t xReturn; @@ -650,5 +671,6 @@ BaseType_t xWaitConditionMet = pdFALSE; return xReturn; } + #endif diff --git a/FreeRTOS/Source/include/event_groups.h b/FreeRTOS/Source/include/event_groups.h index 41e91276f..3bbb2f74b 100644 --- a/FreeRTOS/Source/include/event_groups.h +++ b/FreeRTOS/Source/include/event_groups.h @@ -325,16 +325,61 @@ EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBit /** * event_groups.h *
-	EventBits_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear );
+	BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );
  
* - * A version of xEventGroupClearBits() that can be called from an interrupt - * service routine. See the xEventGroupClearBits() documentation. + * A version of xEventGroupClearBits() that can be called from an interrupt. * - * \defgroup xEventGroupClearBitsFromISR xEventGroupClearBitsFromISR + * Setting bits in an event group is not a deterministic operation because there + * are an unknown number of tasks that may be waiting for the bit or bits being + * set. FreeRTOS does not allow nondeterministic operations to be performed + * while interrupts are disabled, so protects event groups that are accessed + * from tasks by suspending the scheduler rather than disabling interrupts. As + * a result event groups cannot be accessed directly from an interrupt service + * routine. Therefore xEventGroupClearBitsFromISR() sends a message to the + * timer task to have the clear operation performed in the context of the timer + * task. + * + * @param xEventGroup The event group in which the bits are to be cleared. + * + * @param uxBitsToClear A bitwise value that indicates the bit or bits to clear. + * For example, to clear bit 3 only, set uxBitsToClear to 0x08. To clear bit 3 + * and bit 0 set uxBitsToClear to 0x09. + * + * @return If the request to execute the function was posted successfully then + * pdPASS is returned, otherwise pdFALSE is returned. pdFALSE will be returned + * if the timer service queue was full. + * + * Example usage: +
+   #define BIT_0	( 1 << 0 )
+   #define BIT_4	( 1 << 4 )
+
+   // An event group which it is assumed has already been created by a call to
+   // xEventGroupCreate().
+   EventGroupHandle_t xEventGroup;
+
+   void anInterruptHandler( void )
+   {
+		// Clear bit 0 and bit 4 in xEventGroup.
+		xResult = xEventGroupClearBitsFromISR(
+							xEventGroup,	 // The event group being updated.
+							BIT_0 | BIT_4 ); // The bits being set.
+
+		if( xResult == pdPASS )
+		{
+			// The message was posted successfully.
+		}
+  }
+   
+ * \defgroup xEventGroupSetBitsFromISR xEventGroupSetBitsFromISR * \ingroup EventGroup */ -EventBits_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) PRIVILEGED_FUNCTION; +#if( configUSE_TRACE_FACILITY == 1 ) + BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ); +#else + #define xEventGroupClearBitsFromISR( xEventGroup, uxBitsToClear ) xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL ) +#endif /** * event_groups.h @@ -648,7 +693,7 @@ EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t u * \defgroup xEventGroupGetBitsFromISR xEventGroupGetBitsFromISR * \ingroup EventGroup */ -#define xEventGroupGetBitsFromISR( xEventGroup ) xEventGroupClearBitsFromISR( xEventGroup, 0 ) +EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup ); /** * event_groups.h @@ -666,6 +711,7 @@ void vEventGroupDelete( EventGroupHandle_t xEventGroup ); /* For internal use only. */ void vEventGroupSetBitsCallback( void *pvEventGroup, const uint32_t ulBitsToSet ); +void vEventGroupClearBitsCallback( void *pvEventGroup, const uint32_t ulBitsToClear ); #if (configUSE_TRACE_FACILITY == 1) UBaseType_t uxEventGroupGetNumber( void* xEventGroup ); diff --git a/FreeRTOS/Source/include/timers.h b/FreeRTOS/Source/include/timers.h index 5cd1f3503..68209bcac 100644 --- a/FreeRTOS/Source/include/timers.h +++ b/FreeRTOS/Source/include/timers.h @@ -1097,13 +1097,13 @@ BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvPar /** * const char * const pcTimerGetTimerName( TimerHandle_t xTimer ); * - * Returns the name that was asigned to a timer when the timer was created. + * Returns the name that was assigned to a timer when the timer was created. * * @param xTimer The handle of the timer being queried. * - * @return The name asigned to the timer specified by the xTimer parameter. + * @return The name assigned to the timer specified by the xTimer parameter. */ -const char * const pcTimerGetTimerName( TimerHandle_t xTimer ); +const char * pcTimerGetTimerName( TimerHandle_t xTimer ); /* * Functions beyond this part are not part of the public API and are intended diff --git a/FreeRTOS/Source/portable/GCC/ARM_CA9/port.c b/FreeRTOS/Source/portable/GCC/ARM_CA9/port.c index 9fed5b649..54bf16623 100644 --- a/FreeRTOS/Source/portable/GCC/ARM_CA9/port.c +++ b/FreeRTOS/Source/portable/GCC/ARM_CA9/port.c @@ -110,6 +110,8 @@ #error configMAX_API_CALL_INTERRUPT_PRIORITY must be greater than ( configUNIQUE_INTERRUPT_PRIORITIES / 2 ) #endif +/* Some vendor specific files default configCLEAR_TICK_INTERRUPT() in +portmacro.h. */ #ifndef configCLEAR_TICK_INTERRUPT #define configCLEAR_TICK_INTERRUPT() #endif diff --git a/FreeRTOS/Source/portable/GCC/ARM_CA9/portmacro.h b/FreeRTOS/Source/portable/GCC/ARM_CA9/portmacro.h index 23be87c67..6423dc50b 100644 --- a/FreeRTOS/Source/portable/GCC/ARM_CA9/portmacro.h +++ b/FreeRTOS/Source/portable/GCC/ARM_CA9/portmacro.h @@ -130,6 +130,7 @@ extern void vPortEnterCritical( void ); extern void vPortExitCritical( void ); extern uint32_t ulPortSetInterruptMask( void ); extern void vPortClearInterruptMask( uint32_t ulNewMaskValue ); +extern void vPortInstallFreeRTOSVectorTable( void ); /* These macros do not globally disable/enable interrupts. They do mask off interrupts that have a priority below configMAX_API_CALL_INTERRUPT_PRIORITY. */ diff --git a/FreeRTOS/Source/portable/MPLAB/PIC24_dsPIC/port.c b/FreeRTOS/Source/portable/MPLAB/PIC24_dsPIC/port.c index dcfb65c40..93d092caa 100644 --- a/FreeRTOS/Source/portable/MPLAB/PIC24_dsPIC/port.c +++ b/FreeRTOS/Source/portable/MPLAB/PIC24_dsPIC/port.c @@ -184,6 +184,9 @@ UBaseType_t uxCriticalNesting = 0xef; #ifndef portRESTORE_CONTEXT #error Unrecognised device selected + + /* Note: dsPIC parts with EDS are not supported as there is no easy way to + recover the hardware stacked copies for DOCOUNT, DOHIGH, DOLOW. */ #endif /* diff --git a/FreeRTOS/Source/timers.c b/FreeRTOS/Source/timers.c index d7d429554..f9d3fa116 100644 --- a/FreeRTOS/Source/timers.c +++ b/FreeRTOS/Source/timers.c @@ -363,7 +363,7 @@ DaemonTaskMessage_t xMessage; #endif /*-----------------------------------------------------------*/ -const char * const pcTimerGetTimerName( TimerHandle_t xTimer ) +const char * pcTimerGetTimerName( TimerHandle_t xTimer ) { Timer_t *pxTimer = ( Timer_t * ) xTimer; -- 2.39.5