summaryrefslogtreecommitdiff
path: root/FreeRTOS/Demo/Common/Minimal
diff options
context:
space:
mode:
authorrtel <rtel@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>2014-08-29 13:53:58 +0000
committerrtel <rtel@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>2014-08-29 13:53:58 +0000
commitacc26e1b1b3e96c67564388aaf296e64335f6066 (patch)
treeddea0168c171c65a8a4b409334233c868bedffe3 /FreeRTOS/Demo/Common/Minimal
parent6a3a00563338fd8175e7d9343b8dedc022dea4a0 (diff)
downloadfreertos-acc26e1b1b3e96c67564388aaf296e64335f6066.tar.gz
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: http://svn.code.sf.net/p/freertos/code/trunk@2294 1d2547de-c912-0410-9cb9-b8ca96c0e9e2
Diffstat (limited to 'FreeRTOS/Demo/Common/Minimal')
-rw-r--r--FreeRTOS/Demo/Common/Minimal/GenQTest.c450
-rw-r--r--FreeRTOS/Demo/Common/Minimal/TimerDemo.c7
2 files changed, 339 insertions, 118 deletions
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