diff --git a/timers.c b/timers.c index 03765fe7b9..11476a8cab 100644 --- a/timers.c +++ b/timers.c @@ -79,6 +79,17 @@ #define tmrSTATUS_IS_STATICALLY_ALLOCATED ( 0x02U ) #define tmrSTATUS_IS_AUTORELOAD ( 0x04U ) +/* + * Macros to mark the start and end of a critical code region. + */ + #if ( portUSING_GRANULAR_LOCKS == 1 ) + #define tmrENTER_CRITICAL() vTimerEnterCritical() + #define tmrEXIT_CRITICAL() vTimerExitCritical() + #else /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */ + #define tmrENTER_CRITICAL() taskENTER_CRITICAL() + #define tmrEXIT_CRITICAL() taskEXIT_CRITICAL() + #endif /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */ + /* The definition of the timers themselves. */ typedef struct tmrTimerControl /* The old naming convention is used to prevent breaking kernel aware debuggers. */ { @@ -149,6 +160,25 @@ PRIVILEGED_DATA static QueueHandle_t xTimerQueue = NULL; PRIVILEGED_DATA static TaskHandle_t xTimerTaskHandle = NULL; + #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) + PRIVILEGED_DATA static portSPINLOCK_TYPE xTaskSpinlock = portINIT_SPINLOCK_STATIC; + PRIVILEGED_DATA static portSPINLOCK_TYPE xISRSpinlock = portINIT_SPINLOCK_STATIC; + #endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */ + + #if ( portUSING_GRANULAR_LOCKS == 1 ) + +/* + * Enters a critical section for timers. Disables interrupts and takes + * both task and ISR spinlocks to ensure thread safety. + */ + static void vTimerEnterCritical( void ) PRIVILEGED_FUNCTION; + +/* + * Exits a critical section for timers. Releases spinlocks in reverse order + * and conditionally re-enables interrupts and yields if required. + */ + static void vTimerExitCritical( void ) PRIVILEGED_FUNCTION; + #endif /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */ /*-----------------------------------------------------------*/ /* @@ -576,7 +606,7 @@ traceENTER_vTimerSetReloadMode( xTimer, xAutoReload ); configASSERT( xTimer ); - taskENTER_CRITICAL(); + tmrENTER_CRITICAL(); { if( xAutoReload != pdFALSE ) { @@ -587,7 +617,7 @@ pxTimer->ucStatus &= ( ( uint8_t ) ~tmrSTATUS_IS_AUTORELOAD ); } } - taskEXIT_CRITICAL(); + tmrEXIT_CRITICAL(); traceRETURN_vTimerSetReloadMode(); } @@ -601,7 +631,7 @@ traceENTER_xTimerGetReloadMode( xTimer ); configASSERT( xTimer ); - portBASE_TYPE_ENTER_CRITICAL(); + tmrENTER_CRITICAL(); { if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) == 0U ) { @@ -614,7 +644,7 @@ xReturn = pdTRUE; } } - portBASE_TYPE_EXIT_CRITICAL(); + tmrEXIT_CRITICAL(); traceRETURN_xTimerGetReloadMode( xReturn ); @@ -1113,7 +1143,7 @@ /* Check that the list from which active timers are referenced, and the * queue used to communicate with the timer service, have been * initialised. */ - taskENTER_CRITICAL(); + tmrENTER_CRITICAL(); { if( xTimerQueue == NULL ) { @@ -1155,7 +1185,7 @@ mtCOVERAGE_TEST_MARKER(); } } - taskEXIT_CRITICAL(); + tmrEXIT_CRITICAL(); } /*-----------------------------------------------------------*/ @@ -1169,7 +1199,7 @@ configASSERT( xTimer ); /* Is the timer in the list of active timers? */ - portBASE_TYPE_ENTER_CRITICAL(); + tmrENTER_CRITICAL(); { if( ( pxTimer->ucStatus & tmrSTATUS_IS_ACTIVE ) == 0U ) { @@ -1180,7 +1210,7 @@ xReturn = pdTRUE; } } - portBASE_TYPE_EXIT_CRITICAL(); + tmrEXIT_CRITICAL(); traceRETURN_xTimerIsTimerActive( xReturn ); @@ -1197,11 +1227,11 @@ configASSERT( xTimer ); - taskENTER_CRITICAL(); + tmrENTER_CRITICAL(); { pvReturn = pxTimer->pvTimerID; } - taskEXIT_CRITICAL(); + tmrEXIT_CRITICAL(); traceRETURN_pvTimerGetTimerID( pvReturn ); @@ -1218,11 +1248,11 @@ configASSERT( xTimer ); - taskENTER_CRITICAL(); + tmrENTER_CRITICAL(); { pxTimer->pvTimerID = pvNewID; } - taskEXIT_CRITICAL(); + tmrEXIT_CRITICAL(); traceRETURN_vTimerSetTimerID(); } @@ -1334,6 +1364,67 @@ } /*-----------------------------------------------------------*/ + #if ( portUSING_GRANULAR_LOCKS == 1 ) + static void vTimerEnterCritical( void ) + { + portDISABLE_INTERRUPTS(); + { + const BaseType_t xCoreID = ( BaseType_t ) portGET_CORE_ID(); + + /* Task spinlock is always taken first */ + portGET_SPINLOCK( xCoreID, &xTaskSpinlock ); + + /* Take the ISR spinlock next */ + portGET_SPINLOCK( xCoreID, &xISRSpinlock ); + + /* Increment the critical nesting count */ + portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ); + } + } + #endif /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */ + +/*-----------------------------------------------------------*/ + + #if ( portUSING_GRANULAR_LOCKS == 1 ) + static void vTimerExitCritical( void ) + { + const BaseType_t xCoreID = ( BaseType_t ) portGET_CORE_ID(); + + configASSERT( portGET_CRITICAL_NESTING_COUNT( xCoreID ) > 0U ); + + /* Get the xYieldPending status inside the critical section. */ + BaseType_t xYieldCurrentTask = xTaskUnlockCanYield(); + + /* Decrement the critical nesting count */ + portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ); + + /* Release the ISR spinlock */ + portRELEASE_SPINLOCK( xCoreID, &xISRSpinlock ); + + /* Release the task spinlock */ + portRELEASE_SPINLOCK( xCoreID, &xTaskSpinlock ); + + if( portGET_CRITICAL_NESTING_COUNT( xCoreID ) == 0 ) + { + portENABLE_INTERRUPTS(); + + if( xYieldCurrentTask != pdFALSE ) + { + portYIELD(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */ +/*-----------------------------------------------------------*/ + /* This entire source file will be skipped if the application is not configured * to include software timer functionality. If you want to include software timer * functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */