From b68db9e6b8ccc8181fbe1338dbf4359d0be27cab Mon Sep 17 00:00:00 2001 From: rtel Date: Fri, 29 Aug 2014 13:53:58 +0000 Subject: [PATCH] Core kernel code: - Re-introduce the ability to give a mutex from an ISR. Common demo code: - Add additional tests into the GenQTest files for priority inheritance and using a mutex from an ISR. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2294 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- .../settings/RTOSDemo.dbgdt | 10 +- .../settings/RTOSDemo.dni | 4 +- .../settings/RTOSDemo.wsdt | 10 +- FreeRTOS/Demo/Common/Minimal/GenQTest.c | 450 +++++++++++++----- FreeRTOS/Demo/Common/Minimal/TimerDemo.c | 7 +- FreeRTOS/Demo/Common/include/GenQTest.h | 3 +- FreeRTOS/Demo/WIN32-MSVC/main.c | 2 +- FreeRTOS/Demo/WIN32-MSVC/main_full.c | 5 +- FreeRTOS/Source/include/projdefs.h | 2 +- FreeRTOS/Source/include/task.h | 7 +- FreeRTOS/Source/list.c | 2 +- FreeRTOS/Source/queue.c | 21 +- FreeRTOS/Source/tasks.c | 26 +- 13 files changed, 376 insertions(+), 173 deletions(-) diff --git a/FreeRTOS/Demo/CORTEX_A5_SAMA5D3x_Xplained_IAR/settings/RTOSDemo.dbgdt b/FreeRTOS/Demo/CORTEX_A5_SAMA5D3x_Xplained_IAR/settings/RTOSDemo.dbgdt index d3d797e57..4e6cebfa9 100644 --- a/FreeRTOS/Demo/CORTEX_A5_SAMA5D3x_Xplained_IAR/settings/RTOSDemo.dbgdt +++ b/FreeRTOS/Demo/CORTEX_A5_SAMA5D3x_Xplained_IAR/settings/RTOSDemo.dbgdt @@ -34,12 +34,12 @@ 20011 - 200ExpressionLocationTypeValue207150100294200100Frame_I040020300Breakpoint_I05003549782746331300Debug-LogBuild200ExpressionLocationTypeValue100150100100TC0TC0->TC_CHANNEL[ tmrTC0_CHANNEL_0 ].TC_RC30010200100100100100100100100150200100100100100100100 + 200ExpressionLocationTypeValue207150100294200100Frame_I040020300Breakpoint_I05003549782746331300Debug-LogBuild200ExpressionLocationTypeValue100150100100TC0TC0->TC_CHANNEL[ tmrTC0_CHANNEL_0 ].TC_RC30010300200100100100100100100100150300300100100100100100100 - + TabID-24673-23877 @@ -51,20 +51,20 @@ - 0TabID-22902-32031TasksTASKVIEW0TabID-22379-32041QueuesQUEUEVIEW0 + 0TabID-31713-7906Debug LogDebug-Log0 - TextEditor$WS_DIR$\main.c0000014072497249TextEditor$WS_DIR$\Full_Demo\main_full.c000006300TextEditor$WS_DIR$\blinky_demo\main_blinky.c000006313731373TextEditor$WS_DIR$\..\..\Source\portable\IAR\ARM_CA5_No_GIC\portASM.s00000733799379930100000010000001 + TextEditor$WS_DIR$\main.c0000012764116411TextEditor$WS_DIR$\Full_Demo\main_full.c000006300TextEditor$WS_DIR$\blinky_demo\main_blinky.c000006313731373TextEditor$WS_DIR$\..\Common\Minimal\GenQTest.c00000796272382723830100000010000001 - iaridepm.enu1debuggergui.enu1-2-2520332-2-2200200119048203252198810530488-2-21981682-2-216842001002381203252119048203252196-23961682-219616842001002381203252119048203252 + iaridepm.enu1debuggergui.enu1-2-2718332-2-2200200119048203252198810731707-2-21981682-2-216842001002381203252119048203252 diff --git a/FreeRTOS/Demo/CORTEX_A5_SAMA5D3x_Xplained_IAR/settings/RTOSDemo.dni b/FreeRTOS/Demo/CORTEX_A5_SAMA5D3x_Xplained_IAR/settings/RTOSDemo.dni index e66f27a2b..b4bbf9110 100644 --- a/FreeRTOS/Demo/CORTEX_A5_SAMA5D3x_Xplained_IAR/settings/RTOSDemo.dni +++ b/FreeRTOS/Demo/CORTEX_A5_SAMA5D3x_Xplained_IAR/settings/RTOSDemo.dni @@ -14,7 +14,7 @@ Watch0=_ 0 "" 0 "" 0 "" 0 "" 0 0 0 0 Watch1=_ 0 "" 0 "" 0 "" 0 "" 0 0 0 0 CStepIntDis=_ 0 [DebugChecksum] -Checksum=-666464609 +Checksum=-1280642381 [Exceptions] StopOnUncaught=_ 0 StopOnThrow=_ 0 @@ -42,7 +42,7 @@ Exclusions= [Disassemble mode] mode=0 [Breakpoints2] -Bp0=_ 1 "EMUL_CODE" "{$PROJ_DIR$\main.c}.218.24" 0 0 1 "" 0 "" 0 +Bp0=_ 1 "EMUL_CODE" "{$PROJ_DIR$\main.c}.221.2" 0 0 1 "" 0 "" 0 Count=1 [Aliases] Count=0 diff --git a/FreeRTOS/Demo/CORTEX_A5_SAMA5D3x_Xplained_IAR/settings/RTOSDemo.wsdt b/FreeRTOS/Demo/CORTEX_A5_SAMA5D3x_Xplained_IAR/settings/RTOSDemo.wsdt index a7cc6f063..76656626f 100644 --- a/FreeRTOS/Demo/CORTEX_A5_SAMA5D3x_Xplained_IAR/settings/RTOSDemo.wsdt +++ b/FreeRTOS/Demo/CORTEX_A5_SAMA5D3x_Xplained_IAR/settings/RTOSDemo.wsdt @@ -36,7 +36,7 @@ - + TabID-22351-19008 @@ -48,7 +48,7 @@ - 0 + 0 TabID-21076-19237 @@ -58,20 +58,20 @@ TabID-23502-23081Debug LogDebug-LogTabID-24431-23894Ambiguous DefinitionsSelect-Ambiguous-DefinitionsTabID-9033-6116Find in FilesFind-in-Files - 0 + 0 - TextEditor$WS_DIR$\main.c0000059724972490TextEditor$WS_DIR$\Full_Demo\main_full.c000006300TextEditor$WS_DIR$\blinky_demo\main_blinky.c0000063137313730100000010000001 + TextEditor$WS_DIR$\main.c0000063507450740TextEditor$WS_DIR$\Full_Demo\main_full.c000006300TextEditor$WS_DIR$\blinky_demo\main_blinky.c0000063137313730100000010000001 - iaridepm.enu1-2-2668352-2-2190170113095172764210714680894-2-22721682-2-216842741002381278455113095172764 + iaridepm.enu1-2-2668352-2-2190170113095172764210714680894-2-22721682-2-216842741002381278455113095172764 diff --git a/FreeRTOS/Demo/Common/Minimal/GenQTest.c b/FreeRTOS/Demo/Common/Minimal/GenQTest.c index 59e176b16..bd5bbba91 100644 --- a/FreeRTOS/Demo/Common/Minimal/GenQTest.c +++ b/FreeRTOS/Demo/Common/Minimal/GenQTest.c @@ -93,6 +93,7 @@ #define genqMUTEX_MEDIUM_PRIORITY ( tskIDLE_PRIORITY + 2 ) #define genqMUTEX_HIGH_PRIORITY ( tskIDLE_PRIORITY + 3 ) +#define genqINTERRUPT_MUTEX_GIVE_PERIOD_MS ( 100 ) /*-----------------------------------------------------------*/ /* @@ -121,6 +122,28 @@ static void prvLowPriorityMutexTask( void *pvParameters ); static void prvMediumPriorityMutexTask( void *pvParameters ); static void prvHighPriorityMutexTask( void *pvParameters ); +/* + * Exercises the priority inheritance when a task takes two mutexes, returning + * them in a different order to which they were taken. + */ +static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex ); + +/* + * Exercises the priority inheritance when a task takes two mutexes, returning + * them in the same order in which they were taken. + */ +static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex ); + +/* + * Task that receives an a mutex that is given from an interrupt - although + * generally mutexes should not be used given in interrupts (and definitely + * never taken in an interrupt) there are some circumstances when it may be + * desirable. NOTE: This function is not declared static to prevent compiler + * warnings being generated in demos where the function is declared but not + * used. + */ +void vInterruptMutexTask( void *pvParameters ); + /*-----------------------------------------------------------*/ /* Flag that will be latched to pdTRUE should any unexpected behaviour be @@ -139,6 +162,11 @@ static volatile uint32_t ulGuardedVariable = 0; priority mutex test tasks. */ static TaskHandle_t xHighPriorityMutexTask, xMediumPriorityMutexTask; +/* A mutex which is given from an interrupt - although generally mutexes should +not be used given in interrupts (and definitely never taken in an interrupt) +there are some circumstances when it may be desirable. */ +static SemaphoreHandle_t xISRMutex = NULL; + /*-----------------------------------------------------------*/ void vStartGenericQueueTasks( UBaseType_t uxPriority ) @@ -146,6 +174,9 @@ void vStartGenericQueueTasks( UBaseType_t uxPriority ) QueueHandle_t xQueue; SemaphoreHandle_t xMutex; + xISRMutex = xSemaphoreCreateMutex(); + configASSERT( xISRMutex ); + /* Create the queue that we are going to use for the prvSendFrontAndBackTest demo. */ xQueue = xQueueCreate( genqQUEUE_LENGTH, sizeof( uint32_t ) ); @@ -180,6 +211,14 @@ SemaphoreHandle_t xMutex; xTaskCreate( prvLowPriorityMutexTask, "MuLow", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL ); xTaskCreate( prvMediumPriorityMutexTask, "MuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask ); xTaskCreate( prvHighPriorityMutexTask, "MuHigh", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask ); + + /* Only when the windows simulator is being used - create the task that + receives a mutex from an interrupt. */ + #ifdef _WINDOWS_ + { + xTaskCreate( vInterruptMutexTask, "IntMu", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, NULL ); + } + #endif /* __WINDOWS__ */ } /*-----------------------------------------------------------*/ @@ -411,150 +450,286 @@ QueueHandle_t xQueue; } /*-----------------------------------------------------------*/ -static void prvLowPriorityMutexTask( void *pvParameters ) +static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex ) { -SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters, xLocalMutex; + /* Take the mutex. It should be available now. */ + if( xSemaphoreTake( xMutex, genqNO_BLOCK ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } - #ifdef USE_STDIO - void vPrintDisplayMessage( const char * const * ppcMessageToSend ); + /* Set the guarded variable to a known start value. */ + ulGuardedVariable = 0; - const char * const pcTaskStartMsg = "Mutex with priority inheritance test started.\r\n"; + /* This task's priority should be as per that assigned when the task was + created. */ + if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY ) + { + xErrorDetected = pdTRUE; + } - /* Queue a message for printing to say the task has started. */ - vPrintDisplayMessage( &pcTaskStartMsg ); + /* Now unsuspend the high priority task. This will attempt to take the + mutex, and block when it finds it cannot obtain it. */ + vTaskResume( xHighPriorityMutexTask ); + + #if configUSE_PREEMPTION == 0 + taskYIELD(); #endif - /* The local mutex is used to check the 'mutexs held' count. */ - xLocalMutex = xSemaphoreCreateMutex(); - configASSERT( xLocalMutex ); + /* Ensure the task is reporting its priority as blocked and not + suspended (as it would have done in versions up to V7.5.3). */ + #if( INCLUDE_eTaskGetState == 1 ) + { + configASSERT( eTaskGetState( xHighPriorityMutexTask ) == eBlocked ); + } + #endif /* INCLUDE_eTaskGetState */ - for( ;; ) + /* The priority of the high priority task should now have been inherited + as by now it will have attempted to get the mutex. */ + if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY ) { - /* Take the mutex. It should be available now. */ - if( xSemaphoreTake( xMutex, genqNO_BLOCK ) != pdPASS ) - { - xErrorDetected = pdTRUE; - } + xErrorDetected = pdTRUE; + } - /* Set the guarded variable to a known start value. */ - ulGuardedVariable = 0; + /* Attempt to set the priority of this task to the test priority - + between the idle priority and the medium/high test priorities, but the + actual priority should remain at the high priority. */ + vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY ); + if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY ) + { + xErrorDetected = pdTRUE; + } - /* This task's priority should be as per that assigned when the task was - created. */ - if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY ) - { - xErrorDetected = pdTRUE; - } + /* Now unsuspend the medium priority task. This should not run as the + inherited priority of this task is above that of the medium priority + task. */ + vTaskResume( xMediumPriorityMutexTask ); - /* Now unsuspend the high priority task. This will attempt to take the - mutex, and block when it finds it cannot obtain it. */ - vTaskResume( xHighPriorityMutexTask ); + /* If the medium priority task did run then it will have incremented the + guarded variable. */ + if( ulGuardedVariable != 0 ) + { + xErrorDetected = pdTRUE; + } - #if configUSE_PREEMPTION == 0 - taskYIELD(); - #endif + /* Take the local mutex too, so two mutexes are now held. */ + if( xSemaphoreTake( xLocalMutex, genqNO_BLOCK ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } - /* Ensure the task is reporting its priority as blocked and not - suspended (as it would have done in versions up to V7.5.3). */ - #if( INCLUDE_eTaskGetState == 1 ) - { - configASSERT( eTaskGetState( xHighPriorityMutexTask ) == eBlocked ); - } - #endif /* INCLUDE_eTaskGetState */ + /* When the semaphore is given back the priority of this task should not + yet be disinherited because the local mutex is still held. This is a + simplification to allow FreeRTOS to be integrated with middleware that + attempts to hold multiple mutexes without bloating the code with complex + algorithms. It is possible that the high priority mutex task will + execute as it shares a priority with this task. */ + if( xSemaphoreGive( xMutex ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } - /* The priority of the high priority task should now have been inherited - as by now it will have attempted to get the mutex. */ - if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY ) - { - xErrorDetected = pdTRUE; - } + #if configUSE_PREEMPTION == 0 + taskYIELD(); + #endif - /* Attempt to set the priority of this task to the test priority - - between the idle priority and the medium/high test priorities, but the - actual priority should remain at the high priority. */ - vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY ); - if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY ) - { - xErrorDetected = pdTRUE; - } + /* The guarded variable is only incremented by the medium priority task, + which still should not have executed as this task should remain at the + higher priority, ensure this is the case. */ + if( ulGuardedVariable != 0 ) + { + xErrorDetected = pdTRUE; + } - /* Now unsuspend the medium priority task. This should not run as the - inherited priority of this task is above that of the medium priority - task. */ - vTaskResume( xMediumPriorityMutexTask ); + if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY ) + { + xErrorDetected = pdTRUE; + } - /* If the medium priority task did run then it will have incremented the - guarded variable. */ - if( ulGuardedVariable != 0 ) - { - xErrorDetected = pdTRUE; - } + /* Now also give back the local mutex, taking the held count back to 0. + This time the priority of this task should be disinherited back to the + priority to which it was set while the mutex was held. This means + the medium priority task should execute and increment the guarded + variable. When this task next runs both the high and medium priority + tasks will have been suspended again. */ + if( xSemaphoreGive( xLocalMutex ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } - /* Take the local mutex too, so two mutexes are now held. */ - if( xSemaphoreTake( xLocalMutex, genqNO_BLOCK ) != pdPASS ) - { - xErrorDetected = pdTRUE; - } + #if configUSE_PREEMPTION == 0 + taskYIELD(); + #endif - /* When the semaphore is given back the priority of this task should not - yet be disinherited because the local mutex is still held. This is a - simplification to allow FreeRTOS to be integrated with middleware that - attempts to hold multiple mutexes without bloating the code with complex - algorithms. It is possible that the high priority mutex task will - execute as it shares a priority with this task. */ - if( xSemaphoreGive( xMutex ) != pdPASS ) - { - xErrorDetected = pdTRUE; - } + /* Check the guarded variable did indeed increment... */ + if( ulGuardedVariable != 1 ) + { + xErrorDetected = pdTRUE; + } - #if configUSE_PREEMPTION == 0 - taskYIELD(); - #endif + /* ... and that the priority of this task has been disinherited to + genqMUTEX_TEST_PRIORITY. */ + if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY ) + { + xErrorDetected = pdTRUE; + } - /* The guarded variable is only incremented by the medium priority task, - which still should not have executed as this task should remain at the - higher priority, ensure this is the case. */ - if( ulGuardedVariable != 0 ) - { - xErrorDetected = pdTRUE; - } + /* Set the priority of this task back to its original value, ready for + the next loop around this test. */ + vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY ); +} +/*-----------------------------------------------------------*/ - if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY ) - { - xErrorDetected = pdTRUE; - } +static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex ) +{ + /* Take the mutex. It should be available now. */ + if( xSemaphoreTake( xMutex, genqNO_BLOCK ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } - /* Now also give back the local mutex, taking the held count back to 0. - This time the priority of this task should be disinherited back to the - priority to which it was set while the mutex was held. This means - the medium priority task should execute and increment the guarded - variable. When this task next runs both the high and medium priority - tasks will have been suspended again. */ - if( xSemaphoreGive( xLocalMutex ) != pdPASS ) - { - xErrorDetected = pdTRUE; - } + /* Set the guarded variable to a known start value. */ + ulGuardedVariable = 0; + + /* This task's priority should be as per that assigned when the task was + created. */ + if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY ) + { + xErrorDetected = pdTRUE; + } + + /* Now unsuspend the high priority task. This will attempt to take the + mutex, and block when it finds it cannot obtain it. */ + vTaskResume( xHighPriorityMutexTask ); + + #if configUSE_PREEMPTION == 0 + taskYIELD(); + #endif + + /* Ensure the task is reporting its priority as blocked and not + suspended (as it would have done in versions up to V7.5.3). */ + #if( INCLUDE_eTaskGetState == 1 ) + { + configASSERT( eTaskGetState( xHighPriorityMutexTask ) == eBlocked ); + } + #endif /* INCLUDE_eTaskGetState */ + + /* The priority of the high priority task should now have been inherited + as by now it will have attempted to get the mutex. */ + if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY ) + { + xErrorDetected = pdTRUE; + } + + /* Now unsuspend the medium priority task. This should not run as the + inherited priority of this task is above that of the medium priority + task. */ + vTaskResume( xMediumPriorityMutexTask ); + + /* If the medium priority task did run then it will have incremented the + guarded variable. */ + if( ulGuardedVariable != 0 ) + { + xErrorDetected = pdTRUE; + } + + /* Take the local mutex too, so two mutexes are now held. */ + if( xSemaphoreTake( xLocalMutex, genqNO_BLOCK ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + + /* When the local semaphore is given back the priority of this task should + not yet be disinherited because the shared mutex is still held. This is a + simplification to allow FreeRTOS to be integrated with middleware that + attempts to hold multiple mutexes without bloating the code with complex + algorithms. It is possible that the high priority mutex task will + execute as it shares a priority with this task. */ + if( xSemaphoreGive( xLocalMutex ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + + #if configUSE_PREEMPTION == 0 + taskYIELD(); + #endif + + /* The guarded variable is only incremented by the medium priority task, + which still should not have executed as this task should remain at the + higher priority, ensure this is the case. */ + if( ulGuardedVariable != 0 ) + { + xErrorDetected = pdTRUE; + } + + if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY ) + { + xErrorDetected = pdTRUE; + } + + /* Now also give back the shared mutex, taking the held count back to 0. + This time the priority of this task should be disinherited back to the + priority at which it was created. This means the medium priority task + should execute and increment the guarded variable. When this task next runs + both the high and medium priority tasks will have been suspended again. */ + if( xSemaphoreGive( xMutex ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + + #if configUSE_PREEMPTION == 0 + taskYIELD(); + #endif + + /* Check the guarded variable did indeed increment... */ + if( ulGuardedVariable != 1 ) + { + xErrorDetected = pdTRUE; + } + + /* ... and that the priority of this task has been disinherited to + genqMUTEX_LOW_PRIORITY. */ + if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY ) + { + xErrorDetected = pdTRUE; + } +} +/*-----------------------------------------------------------*/ + +static void prvLowPriorityMutexTask( void *pvParameters ) +{ +SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters, xLocalMutex; + + #ifdef USE_STDIO + void vPrintDisplayMessage( const char * const * ppcMessageToSend ); + + const char * const pcTaskStartMsg = "Mutex with priority inheritance test started.\r\n"; + + /* Queue a message for printing to say the task has started. */ + vPrintDisplayMessage( &pcTaskStartMsg ); + #endif + + /* The local mutex is used to check the 'mutexs held' count. */ + xLocalMutex = xSemaphoreCreateMutex(); + configASSERT( xLocalMutex ); + + for( ;; ) + { + /* The first tests exercise the priority inheritance when two mutexes + are taken then returned in a different order to which they were + taken. */ + prvTakeTwoMutexesReturnInDifferentOrder( xMutex, xLocalMutex ); + + /* Just to show this task is still running. */ + ulLoopCounter2++; #if configUSE_PREEMPTION == 0 taskYIELD(); #endif - /* Check the guarded variable did indeed increment... */ - if( ulGuardedVariable != 1 ) - { - xErrorDetected = pdTRUE; - } - - /* ... and that the priority of this task has been disinherited to - genqMUTEX_TEST_PRIORITY. */ - if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY ) - { - xErrorDetected = pdTRUE; - } - - /* Set the priority of this task back to its original value, ready for - the next loop around this test. */ - vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY ); + /* The second tests exercise the priority inheritance when two mutexes + are taken then returned in the same order in which they were taken. */ + prvTakeTwoMutexesReturnInSameOrder( xMutex, xLocalMutex ); /* Just to show this task is still running. */ ulLoopCounter2++; @@ -612,12 +787,53 @@ SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters; } /*-----------------------------------------------------------*/ +/* NOTE: This function is not declared static to prevent compiler warnings in +demos where the function is declared but not used. */ +void vInterruptMutexTask( void *pvParameters ) +{ +const TickType_t xInterruptGivePeriod = pdMS_TO_TICKS( genqINTERRUPT_MUTEX_GIVE_PERIOD_MS ); +volatile uint32_t ulLoops = 0; + + /* Just to avoid compiler warnings. */ + ( void ) pvParameters; + + for( ;; ) + { + /* Has to wait longer than the time between gives to make sure it + should definitely have received the mutex. */ + if( xSemaphoreTake( xISRMutex, ( xInterruptGivePeriod * 2 ) ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + else + { + ulLoops++; + } + } +} +/*-----------------------------------------------------------*/ + +void vMutexISRInteractionTest( void ) +{ +static TickType_t xLastGiveTime = 0; +TickType_t xTimeNow; + + xTimeNow = xTaskGetTickCountFromISR(); + if( ( xTimeNow - xLastGiveTime ) >= pdMS_TO_TICKS( genqINTERRUPT_MUTEX_GIVE_PERIOD_MS ) ) + { + configASSERT( xISRMutex ); + xSemaphoreGiveFromISR( xISRMutex, NULL ); + xLastGiveTime = xTimeNow; + } +} +/*-----------------------------------------------------------*/ + /* This is called to check that all the created tasks are still running. */ BaseType_t xAreGenericQueueTasksStillRunning( void ) { static uint32_t ulLastLoopCounter = 0, ulLastLoopCounter2 = 0; - /* If the demo task is still running then we expect the loopcounters to + /* If the demo task is still running then we expect the loop counters to have incremented since this function was last called. */ if( ulLastLoopCounter == ulLoopCounter ) { diff --git a/FreeRTOS/Demo/Common/Minimal/TimerDemo.c b/FreeRTOS/Demo/Common/Minimal/TimerDemo.c index f600ac97f..35afdc1af 100644 --- a/FreeRTOS/Demo/Common/Minimal/TimerDemo.c +++ b/FreeRTOS/Demo/Common/Minimal/TimerDemo.c @@ -741,7 +741,12 @@ static TickType_t uxTick = ( TickType_t ) -1; as well as late timer expiries. */ const TickType_t xMargin = 6; #else - const TickType_t xMargin = 3; + #ifdef _WINDOWS_ + /* Windows is not real real time. */ + const TickType_t xMargin = 8; + #else + const TickType_t xMargin = 4; + #endif /* _WINDOWS_ */ #endif diff --git a/FreeRTOS/Demo/Common/include/GenQTest.h b/FreeRTOS/Demo/Common/include/GenQTest.h index 804eaab9f..ef63920d1 100644 --- a/FreeRTOS/Demo/Common/include/GenQTest.h +++ b/FreeRTOS/Demo/Common/include/GenQTest.h @@ -1,5 +1,5 @@ /* - FreeRTOS V8.1.0 - Copyright (C) 2014 Real Time Engineers Ltd. + FreeRTOS V8.1.0 - Copyright (C) 2014 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. @@ -68,6 +68,7 @@ void vStartGenericQueueTasks( UBaseType_t uxPriority ); BaseType_t xAreGenericQueueTasksStillRunning( void ); +void vMutexISRInteractionTest( void ); #endif /* GEN_Q_TEST_H */ diff --git a/FreeRTOS/Demo/WIN32-MSVC/main.c b/FreeRTOS/Demo/WIN32-MSVC/main.c index 917f642dc..948a3f6a5 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/main.c +++ b/FreeRTOS/Demo/WIN32-MSVC/main.c @@ -297,7 +297,7 @@ volatile uint32_t ulSetToNonZeroInDebuggerToContinue = 0; ( void ) ulLine; ( void ) pcFileName; - taskENTER_CRITICAL(); + taskENTER_CRITICAL(); { /* Stop the trace recording. */ if( xPrinted == pdFALSE ) diff --git a/FreeRTOS/Demo/WIN32-MSVC/main_full.c b/FreeRTOS/Demo/WIN32-MSVC/main_full.c index 30e93f303..85b6f14e3 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/main_full.c +++ b/FreeRTOS/Demo/WIN32-MSVC/main_full.c @@ -162,7 +162,7 @@ static void prvTestTask( void *pvParameters ); static void prvDemonstrateTaskStateAndHandleGetFunctions( void ); /* - * Called from the idle task hook function to demonstrate the use of + * Called from the idle task hook function to demonstrate the use of * xTimerPendFunctionCall() as xTimerPendFunctionCall() is not demonstrated by * any of the standard demo tasks. */ @@ -401,6 +401,9 @@ void vFullDemoTickHookFunction( void ) /* Exercise event groups from interrupts. */ vPeriodicEventGroupsProcessing(); + + /* Exercise giving mutexes from an interrupt. */ + vMutexISRInteractionTest(); } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Source/include/projdefs.h b/FreeRTOS/Source/include/projdefs.h index f7b9a0e3e..22c810b40 100644 --- a/FreeRTOS/Source/include/projdefs.h +++ b/FreeRTOS/Source/include/projdefs.h @@ -73,7 +73,7 @@ typedef void (*TaskFunction_t)( void * ); /* Converts a time in milliseconds to a time in ticks. */ -#define pdMS_TO_TICKS( xTimeInMs ) ( ( ( TickType_t ) xTimeInMs * configTICK_RATE_HZ ) / ( TickType_t ) 1000 ) +#define pdMS_TO_TICKS( xTimeInMs ) ( ( ( TickType_t ) ( xTimeInMs ) * configTICK_RATE_HZ ) / ( TickType_t ) 1000 ) #define pdFALSE ( ( BaseType_t ) 0 ) #define pdTRUE ( ( BaseType_t ) 1 ) diff --git a/FreeRTOS/Source/include/task.h b/FreeRTOS/Source/include/task.h index bdc60598f..8186a93fa 100644 --- a/FreeRTOS/Source/include/task.h +++ b/FreeRTOS/Source/include/task.h @@ -1554,12 +1554,9 @@ eSleepModeStatus eTaskConfirmSleepModeStatus( void ) PRIVILEGED_FUNCTION; /* * For internal use only. Increment the mutex held count when a mutex is - * taken and decrement the mutex held count when the mutex is given back - * respectively. The mutex held count is used to know when it is safe to - * disinherit a priority. + * taken and return the handle of the task that has taken the mutex. */ -void vTaskIncrementMutexHeldCount( void ); -void vTaskDecrementMutexHeldCount( void ); +void *pvTaskIncrementMutexHeldCount( void ); #ifdef __cplusplus } diff --git a/FreeRTOS/Source/list.c b/FreeRTOS/Source/list.c index 941dafef2..388143aaf 100644 --- a/FreeRTOS/Source/list.c +++ b/FreeRTOS/Source/list.c @@ -144,7 +144,7 @@ const TickType_t xValueOfInsertion = pxNewListItem->xItemValue; see http://www.freertos.org/Stacks-and-stack-overflow-checking.html 2) Incorrect interrupt priority assignment, especially on Cortex-M3 parts where numerically high priority values denote low actual - interrupt priories, which can seem counter intuitive. See + interrupt priorities, which can seem counter intuitive. See configMAX_SYSCALL_INTERRUPT_PRIORITY on http://www.freertos.org/a00110.html 3) Calling an API function from within a critical section or when the scheduler is suspended, or calling an API function that does diff --git a/FreeRTOS/Source/queue.c b/FreeRTOS/Source/queue.c index f9e003759..0e5bc9e3a 100644 --- a/FreeRTOS/Source/queue.c +++ b/FreeRTOS/Source/queue.c @@ -421,10 +421,7 @@ QueueHandle_t xReturn = NULL; traceCREATE_MUTEX( pxNewQueue ); - /* Start with the semaphore in the expected state. Preload the - mutex held count as calling xQueueGenericSend() will decrement the - count back to 0. */ - vTaskIncrementMutexHeldCount(); + /* Start with the semaphore in the expected state. */ ( void ) xQueueGenericSend( pxNewQueue, NULL, ( TickType_t ) 0U, queueSEND_TO_BACK ); } else @@ -702,7 +699,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; the mutexes were given back in an order that is different to that in which they were taken. */ queueYIELD_IF_USING_PREEMPTION(); - } + } else { mtCOVERAGE_TEST_MARKER(); @@ -1125,8 +1122,8 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; { if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) { - /* The task waiting has a higher priority so record that a - context switch is required. */ + /* The task waiting has a higher priority so + record that a context switch is required. */ if( pxHigherPriorityTaskWoken != NULL ) { *pxHigherPriorityTaskWoken = pdTRUE; @@ -1243,7 +1240,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; { /* Record the information required to implement priority inheritance should it become necessary. */ - pxQueue->pxMutexHolder = ( int8_t * ) xTaskGetCurrentTaskHandle(); /*lint !e961 Cast is not redundant as TaskHandle_t is a typedef. */ + pxQueue->pxMutexHolder = ( int8_t * ) pvTaskIncrementMutexHeldCount(); /*lint !e961 Cast is not redundant as TaskHandle_t is a typedef. */ } else { @@ -1633,7 +1630,6 @@ BaseType_t xReturn = pdFALSE; if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) { /* The mutex is no longer being held. */ - vTaskDecrementMutexHeldCount(); xReturn = xTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder ); pxQueue->pxMutexHolder = NULL; } @@ -1699,7 +1695,7 @@ BaseType_t xReturn = pdFALSE; static void prvCopyDataFromQueue( Queue_t * const pxQueue, void * const pvBuffer ) { - if( pxQueue->uxQueueType != queueQUEUE_IS_MUTEX ) + if( pxQueue->uxItemSize != 0 ) { pxQueue->u.pcReadFrom += pxQueue->uxItemSize; if( pxQueue->u.pcReadFrom >= pxQueue->pcTail ) /*lint !e946 MISRA exception justified as use of the relational operator is the cleanest solutions. */ @@ -1712,11 +1708,6 @@ static void prvCopyDataFromQueue( Queue_t * const pxQueue, void * const pvBuffer } ( void ) memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->u.pcReadFrom, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 !e418 MISRA exception as the casts are only redundant for some ports. Also previous logic ensures a null pointer can only be passed to memcpy() when the count is 0. */ } - else - { - /* A mutex was taken. */ - vTaskIncrementMutexHeldCount(); - } } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Source/tasks.c b/FreeRTOS/Source/tasks.c index 5300d09a9..28d1c9632 100644 --- a/FreeRTOS/Source/tasks.c +++ b/FreeRTOS/Source/tasks.c @@ -553,14 +553,14 @@ TCB_t * pxNewTCB; pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ( portPOINTER_SIZE_TYPE ) ~portBYTE_ALIGNMENT_MASK ) ); /*lint !e923 MISRA exception. Avoiding casts between pointers and integers is not practical. Size differences accounted for using portPOINTER_SIZE_TYPE type. */ /* Check the alignment of the calculated top of stack is correct. */ - configASSERT( ( ( ( uint32_t ) pxTopOfStack & ( uint32_t ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); + configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); } #else /* portSTACK_GROWTH */ { pxTopOfStack = pxNewTCB->pxStack; /* Check the alignment of the stack buffer is correct. */ - configASSERT( ( ( ( uint32_t ) pxNewTCB->pxStack & ( uint32_t ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); + configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxNewTCB->pxStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); /* If we want to use stack checking on architectures that use a positive stack growth direction then we also need to store the @@ -3246,6 +3246,9 @@ TCB_t *pxTCB; if( pxMutexHolder != NULL ) { + configASSERT( pxTCB->uxMutexesHeld ); + ( pxTCB->uxMutexesHeld )--; + if( pxTCB->uxPriority != pxTCB->uxBasePriority ) { /* Only disinherit if no other mutexes are held. */ @@ -3584,7 +3587,7 @@ TickType_t uxReturn; } /*-----------------------------------------------------------*/ -void vTaskIncrementMutexHeldCount( void ) +void *pvTaskIncrementMutexHeldCount( void ) { #if ( configUSE_MUTEXES == 1 ) { @@ -3594,25 +3597,12 @@ void vTaskIncrementMutexHeldCount( void ) { ( pxCurrentTCB->uxMutexesHeld )++; } - } - #endif -} -/*-----------------------------------------------------------*/ -void vTaskDecrementMutexHeldCount( void ) -{ - #if ( configUSE_MUTEXES == 1 ) - { - /* If xSemaphoreCreateMutex() is called before any tasks have been created - then pxCurrentTCB will be NULL. */ - if( pxCurrentTCB != NULL ) - { - configASSERT( pxCurrentTCB->uxMutexesHeld ); - ( pxCurrentTCB->uxMutexesHeld )--; - } + return pxCurrentTCB; } #endif } +/*-----------------------------------------------------------*/ #ifdef FREERTOS_MODULE_TEST #include "tasks_test_access_functions.h" -- 2.39.2