From 1bd4f2abcc20cdbcd7d4f8c12ebde29856fdc486 Mon Sep 17 00:00:00 2001 From: rtel Date: Thu, 11 Sep 2014 12:06:27 +0000 Subject: [PATCH] Demo tasks only, with the aim of improving test coverage: + Split out the code that uses a mutex from an interrupt from GenQTest.c and add to new common demo task IntSemTest.c. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2303 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- FreeRTOS/Demo/Common/Minimal/GenQTest.c | 122 ++----- FreeRTOS/Demo/Common/Minimal/IntSemTest.c | 389 ++++++++++++++++++++++ FreeRTOS/Demo/Common/Minimal/TimerDemo.c | 2 +- FreeRTOS/Demo/Common/include/IntSemTest.h | 76 +++++ 4 files changed, 488 insertions(+), 101 deletions(-) create mode 100644 FreeRTOS/Demo/Common/Minimal/IntSemTest.c create mode 100644 FreeRTOS/Demo/Common/include/IntSemTest.h diff --git a/FreeRTOS/Demo/Common/Minimal/GenQTest.c b/FreeRTOS/Demo/Common/Minimal/GenQTest.c index 2a303652d..250379db5 100644 --- a/FreeRTOS/Demo/Common/Minimal/GenQTest.c +++ b/FreeRTOS/Demo/Common/Minimal/GenQTest.c @@ -86,14 +86,13 @@ #include "GenQTest.h" #define genqQUEUE_LENGTH ( 5 ) -#define genqNO_BLOCK ( 0 ) +#define intsemNO_BLOCK ( 0 ) #define genqMUTEX_LOW_PRIORITY ( tskIDLE_PRIORITY ) #define genqMUTEX_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 ) #define genqMUTEX_MEDIUM_PRIORITY ( tskIDLE_PRIORITY + 2 ) #define genqMUTEX_HIGH_PRIORITY ( tskIDLE_PRIORITY + 3 ) -#define genqINTERRUPT_MUTEX_GIVE_PERIOD_MS ( 100 ) /*-----------------------------------------------------------*/ /* @@ -122,28 +121,6 @@ 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 @@ -162,11 +139,6 @@ 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 ) @@ -174,8 +146,6 @@ 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. */ @@ -211,14 +181,6 @@ 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__ */ } /*-----------------------------------------------------------*/ @@ -244,14 +206,14 @@ QueueHandle_t xQueue; should have the same efect as sending it to the front of the queue. First send to the front and check everything is as expected. */ - xQueueSendToFront( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK ); + xQueueSendToFront( xQueue, ( void * ) &ulLoopCounter, intsemNO_BLOCK ); if( uxQueueMessagesWaiting( xQueue ) != 1 ) { xErrorDetected = pdTRUE; } - if( xQueueReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS ) + if( xQueueReceive( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != pdPASS ) { xErrorDetected = pdTRUE; } @@ -270,14 +232,14 @@ QueueHandle_t xQueue; xErrorDetected = pdTRUE; } - xQueueSendToBack( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK ); + xQueueSendToBack( xQueue, ( void * ) &ulLoopCounter, intsemNO_BLOCK ); if( uxQueueMessagesWaiting( xQueue ) != 1 ) { xErrorDetected = pdTRUE; } - if( xQueueReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS ) + if( xQueueReceive( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != pdPASS ) { xErrorDetected = pdTRUE; } @@ -303,7 +265,7 @@ QueueHandle_t xQueue; /* Place 2, 3, 4 into the queue, adding items to the back of the queue. */ for( ulData = 2; ulData < 5; ulData++ ) { - xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ); + xQueueSendToBack( xQueue, ( void * ) &ulData, intsemNO_BLOCK ); } /* Now the order in the queue should be 2, 3, 4, with 2 being the first @@ -313,9 +275,9 @@ QueueHandle_t xQueue; xErrorDetected = pdTRUE; } ulData = 1; - xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ); + xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ); ulData = 0; - xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ); + xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ); /* Now the queue should be full, and when we read the data out we should receive 0, 1, 2, 3, 4. */ @@ -324,12 +286,12 @@ QueueHandle_t xQueue; xErrorDetected = pdTRUE; } - if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL ) + if( xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL ) { xErrorDetected = pdTRUE; } - if( xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL ) + if( xQueueSendToBack( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL ) { xErrorDetected = pdTRUE; } @@ -342,7 +304,7 @@ QueueHandle_t xQueue; for( ulData = 0; ulData < genqQUEUE_LENGTH; ulData++ ) { /* Try peeking the data first. */ - if( xQueuePeek( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS ) + if( xQueuePeek( xQueue, &ulData2, intsemNO_BLOCK ) != pdPASS ) { xErrorDetected = pdTRUE; } @@ -356,7 +318,7 @@ QueueHandle_t xQueue; /* Now try receiving the data for real. The value should be the same. Clobber the value first so we know we really received it. */ ulData2 = ~ulData2; - if( xQueueReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS ) + if( xQueueReceive( xQueue, &ulData2, intsemNO_BLOCK ) != pdPASS ) { xErrorDetected = pdTRUE; } @@ -380,12 +342,12 @@ QueueHandle_t xQueue; /* Our queue is empty once more, add 10, 11 to the back. */ ulData = 10; - if( xQueueSend( xQueue, &ulData, genqNO_BLOCK ) != pdPASS ) + if( xQueueSend( xQueue, &ulData, intsemNO_BLOCK ) != pdPASS ) { xErrorDetected = pdTRUE; } ulData = 11; - if( xQueueSend( xQueue, &ulData, genqNO_BLOCK ) != pdPASS ) + if( xQueueSend( xQueue, &ulData, intsemNO_BLOCK ) != pdPASS ) { xErrorDetected = pdTRUE; } @@ -399,7 +361,7 @@ QueueHandle_t xQueue; front. */ for( ulData = 9; ulData >= 7; ulData-- ) { - if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS ) + if( xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != pdPASS ) { xErrorDetected = pdTRUE; } @@ -412,12 +374,12 @@ QueueHandle_t xQueue; xErrorDetected = pdTRUE; } - if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL ) + if( xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL ) { xErrorDetected = pdTRUE; } - if( xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL ) + if( xQueueSendToBack( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL ) { xErrorDetected = pdTRUE; } @@ -429,7 +391,7 @@ QueueHandle_t xQueue; /* Check the data we read out is in the expected order. */ for( ulData = 7; ulData < ( 7 + genqQUEUE_LENGTH ); ulData++ ) { - if( xQueueReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS ) + if( xQueueReceive( xQueue, &ulData2, intsemNO_BLOCK ) != pdPASS ) { xErrorDetected = pdTRUE; } @@ -453,7 +415,7 @@ QueueHandle_t xQueue; static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex ) { /* Take the mutex. It should be available now. */ - if( xSemaphoreTake( xMutex, genqNO_BLOCK ) != pdPASS ) + if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS ) { xErrorDetected = pdTRUE; } @@ -513,7 +475,7 @@ static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, S } /* Take the local mutex too, so two mutexes are now held. */ - if( xSemaphoreTake( xLocalMutex, genqNO_BLOCK ) != pdPASS ) + if( xSemaphoreTake( xLocalMutex, intsemNO_BLOCK ) != pdPASS ) { xErrorDetected = pdTRUE; } @@ -583,7 +545,7 @@ static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, S static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex ) { /* Take the mutex. It should be available now. */ - if( xSemaphoreTake( xMutex, genqNO_BLOCK ) != pdPASS ) + if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS ) { xErrorDetected = pdTRUE; } @@ -634,7 +596,7 @@ static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, Semaph } /* Take the local mutex too, so two mutexes are now held. */ - if( xSemaphoreTake( xLocalMutex, genqNO_BLOCK ) != pdPASS ) + if( xSemaphoreTake( xLocalMutex, intsemNO_BLOCK ) != pdPASS ) { xErrorDetected = pdTRUE; } @@ -787,46 +749,6 @@ 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 ) diff --git a/FreeRTOS/Demo/Common/Minimal/IntSemTest.c b/FreeRTOS/Demo/Common/Minimal/IntSemTest.c new file mode 100644 index 000000000..310047a2b --- /dev/null +++ b/FreeRTOS/Demo/Common/Minimal/IntSemTest.c @@ -0,0 +1,389 @@ +/* + FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +/* + * Demonstrates and tests mutexes being used from an interrupt. + */ + + +#include + +/* Scheduler include files. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + +/* Demo program include files. */ +#include "IntSemTest.h" + +/*-----------------------------------------------------------*/ + +/* The priorities of the test tasks. */ +#define intsemMASTER_PRIORITY ( tskIDLE_PRIORITY ) +#define intsemSLAVE_PRIORITY ( tskIDLE_PRIORITY + 1 ) + +/* The rate at which the tick hook will give the mutex. */ +#define intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS ( 100 ) + +/* A block time of 0 means 'don't block'. */ +#define intsemNO_BLOCK 0 + +/*-----------------------------------------------------------*/ + +/* + * The master is a task that receives 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. + * + * The slave task is just used by the master task to force priority inheritance + * on a mutex that is shared between the master and the slave - which is a + * separate mutex to that given by the interrupt. + */ +static void vInterruptMutexSlaveTask( void *pvParameters ); +static void vInterruptMutexMasterTask( void *pvParameters ); + +/*-----------------------------------------------------------*/ + +/* Flag that will be latched to pdTRUE should any unexpected behaviour be +detected in any of the tasks. */ +static volatile BaseType_t xErrorDetected = pdFALSE; + +/* Counters that are incremented on each cycle of a test. This is used to +detect a stalled task - a test that is no longer running. */ +static volatile uint32_t ulMasterLoops = 0; + +/* Handles of the test tasks that must be accessed from other test tasks. */ +static TaskHandle_t xSlaveHandle; + +/* 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; + +/* A mutex which is shared between the master and slave tasks - the master +does both sharing of this mutex with the slave and receiving a mutex from the +interrupt. */ +static SemaphoreHandle_t xMasterSlaveMutex = NULL; + +/* Flag that allows the master task to control when the interrupt gives or does +not give the mutex. There is no mutual exclusion on this variable, but this is +only test code and it should be fine in the 32=bit test environment. */ +static BaseType_t xOkToGiveMutex = pdFALSE; + +/*-----------------------------------------------------------*/ + +void vStartInterruptSemaphoreTasks( void ) +{ + /* Create the mutex that is given from an interrupt. */ + xISRMutex = xSemaphoreCreateMutex(); + configASSERT( xISRMutex ); + + /* Create the mutex that is shared between the master and slave tasks (the + master receives a mutex from an interrupt and shares a mutex with the + slave. */ + xMasterSlaveMutex = xSemaphoreCreateMutex(); + configASSERT( xMasterSlaveMutex ); + + /* Create the tasks that share mutexes between then and with interrupts. */ + xTaskCreate( vInterruptMutexSlaveTask, "IntMuS", configMINIMAL_STACK_SIZE, NULL, intsemSLAVE_PRIORITY, &xSlaveHandle ); + xTaskCreate( vInterruptMutexMasterTask, "IntMuM", configMINIMAL_STACK_SIZE, NULL, intsemMASTER_PRIORITY, NULL ); +} +/*-----------------------------------------------------------*/ + +static void vInterruptMutexMasterTask( void *pvParameters ) +{ +const TickType_t xInterruptGivePeriod = pdMS_TO_TICKS( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS ); + + /* Just to avoid compiler warnings. */ + ( void ) pvParameters; + + for( ;; ) + { + /* Ensure the slave is suspended, and that this task is running at the + lower priority as expected as the start conditions. */ + #if( INCLUDE_eTaskGetState == 1 ) + { + configASSERT( eTaskGetState( xSlaveHandle ) == eSuspended ); + } + #endif /* INCLUDE_eTaskGetState */ + + if( uxTaskPriorityGet( NULL ) != intsemMASTER_PRIORITY ) + { + xErrorDetected = pdTRUE; + } + + /* Take the semaphore that is shared with the slave. */ + if( xSemaphoreTake( xMasterSlaveMutex, intsemNO_BLOCK ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + + /* This task now has the mutex. Unsuspend the slave so it too + attempts to take the mutex. */ + vTaskResume( xSlaveHandle ); + + /* The slave has the higher priority so should now have executed and + blocked on the semaphore. */ + #if( INCLUDE_eTaskGetState == 1 ) + { + configASSERT( eTaskGetState( xSlaveHandle ) == eBlocked ); + } + #endif /* INCLUDE_eTaskGetState */ + + /* This task should now have inherited the priority of the slave + task. */ + if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY ) + { + xErrorDetected = pdTRUE; + } + + /* Now wait a little longer than the time between ISR gives to also + obtain the ISR mutex. */ + xOkToGiveMutex = pdTRUE; + if( xSemaphoreTake( xISRMutex, ( xInterruptGivePeriod * 2 ) ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + xOkToGiveMutex = pdFALSE; + + /* Attempting to take again immediately should fail as the mutex is + already held. */ + if( xSemaphoreTake( xISRMutex, intsemNO_BLOCK ) != pdFAIL ) + { + xErrorDetected = pdTRUE; + } + + /* Should still be at the priority of the slave task. */ + if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY ) + { + xErrorDetected = pdTRUE; + } + + /* Give back the ISR semaphore to ensure the priority is not + disinherited as the shared mutex (which the higher priority task is + attempting to obtain) is still held. */ + if( xSemaphoreGive( xISRMutex ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + + if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY ) + { + xErrorDetected = pdTRUE; + } + + /* Finally give back the shared mutex. This time the higher priority + task should run before this task runs again - so this task should have + disinherited the priority and the higher priority task should be in the + suspended state again. */ + if( xSemaphoreGive( xMasterSlaveMutex ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + + if( uxTaskPriorityGet( NULL ) != intsemMASTER_PRIORITY ) + { + xErrorDetected = pdTRUE; + } + + #if( INCLUDE_eTaskGetState == 1 ) + { + configASSERT( eTaskGetState( xSlaveHandle ) == eSuspended ); + } + #endif /* INCLUDE_eTaskGetState */ + + /* Ensure not to starve out other tests. */ + ulMasterLoops++; + vTaskDelay( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS ); + + + /* Repeat exactly up to the point where the mutexes are given back. + This time the shared mutex is given back first. */ + if( xSemaphoreTake( xMasterSlaveMutex, intsemNO_BLOCK ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + + vTaskResume( xSlaveHandle ); + + #if( INCLUDE_eTaskGetState == 1 ) + { + configASSERT( eTaskGetState( xSlaveHandle ) == eBlocked ); + } + #endif /* INCLUDE_eTaskGetState */ + + if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY ) + { + xErrorDetected = pdTRUE; + } + + xOkToGiveMutex = pdTRUE; + if( xSemaphoreTake( xISRMutex, ( xInterruptGivePeriod * 2 ) ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + xOkToGiveMutex = pdFALSE; + + if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY ) + { + xErrorDetected = pdTRUE; + } + + /* This is where the differences start as this time the shared mutex is + given back first. This time to the higher priority task should run + before this task gets to the point of releasing the interrupt mutex - so + this task should have disinherited the priority and the higher priority + task should be in the suspended state again. */ + if( xSemaphoreGive( xMasterSlaveMutex ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + + /* Give back the interrupt semaphore too, so the mutex held count goes + back to 0. The mutex will then have to be reset so the ISR can give it + in the next cycle. */ + xSemaphoreGive( xISRMutex ); + xQueueReset( ( QueueHandle_t ) xISRMutex ); + + /* Ensure not to starve out other tests. */ + ulMasterLoops++; + vTaskDelay( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS ); + } +} +/*-----------------------------------------------------------*/ + +static void vInterruptMutexSlaveTask( void *pvParameters ) +{ + /* Just to avoid compiler warnings. */ + ( void ) pvParameters; + + for( ;; ) + { + /* This task starts by suspending itself so when it executes can be + controlled by the master task. */ + vTaskSuspend( NULL ); + + /* This task will execute when the master task already holds the mutex. + Attempting to take the mutex will place this task in the Blocked + state. */ + if( xSemaphoreTake( xMasterSlaveMutex, portMAX_DELAY ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + + if( xSemaphoreGive( xMasterSlaveMutex ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + } +} +/*-----------------------------------------------------------*/ + +void vInterruptSemaphorePeriodicTest( void ) +{ +static TickType_t xLastGiveTime = 0; +TickType_t xTimeNow; + + /* No mutual exclusion on xOkToGiveMutex, but this is only test code (and + only executed on a 32-bit architecture) so ignore that in this case. */ + xTimeNow = xTaskGetTickCountFromISR(); + if( ( xTimeNow - xLastGiveTime ) >= pdMS_TO_TICKS( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS ) ) + { + configASSERT( xISRMutex ); + if( xOkToGiveMutex != pdFALSE ) + { + xSemaphoreGiveFromISR( xISRMutex, NULL ); + + /* Second give attempt should fail. */ + configASSERT( xSemaphoreGiveFromISR( xISRMutex, NULL ) == pdFAIL ); + } + xLastGiveTime = xTimeNow; + } +} +/*-----------------------------------------------------------*/ + +/* This is called to check that all the created tasks are still running. */ +BaseType_t xAreInterruptSemaphoreTasksStillRunning( void ) +{ +static uint32_t ulLastMasterLoopCounter = 0; + + /* If the demo tasks are running then it is expected that the loop counters + will have changed since this function was last called. */ + if( ulLastMasterLoopCounter == ulMasterLoops ) + { + xErrorDetected = pdTRUE; + } + + ulLastMasterLoopCounter = ulMasterLoops; + + /* Errors detected in the task itself will have latched xErrorDetected + to true. */ + + return ( BaseType_t ) !xErrorDetected; +} + + diff --git a/FreeRTOS/Demo/Common/Minimal/TimerDemo.c b/FreeRTOS/Demo/Common/Minimal/TimerDemo.c index c27122568..3f2cef08a 100644 --- a/FreeRTOS/Demo/Common/Minimal/TimerDemo.c +++ b/FreeRTOS/Demo/Common/Minimal/TimerDemo.c @@ -743,7 +743,7 @@ static TickType_t uxTick = ( TickType_t ) -1; #else #ifdef _WINDOWS_ /* Windows is not real real time. */ - const TickType_t xMargin = 8; + const TickType_t xMargin = 10; #else const TickType_t xMargin = 4; #endif /* _WINDOWS_ */ diff --git a/FreeRTOS/Demo/Common/include/IntSemTest.h b/FreeRTOS/Demo/Common/include/IntSemTest.h new file mode 100644 index 000000000..7a8c002c3 --- /dev/null +++ b/FreeRTOS/Demo/Common/include/IntSemTest.h @@ -0,0 +1,76 @@ +/* + FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef INT_SEM_TEST_H +#define INT_SEM_TEST_H + +void vStartInterruptSemaphoreTasks( void ); +BaseType_t xAreInterruptSemaphoreTasksStillRunning( void ); +void vInterruptSemaphorePeriodicTest( void ); + +#endif /* INT_SEM_TEST_H */ + + + -- 2.39.5