X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=FreeRTOS%2FDemo%2FCommon%2FMinimal%2FEventGroupsDemo.c;h=21b2d7769da04b53297b599e5e105c6593da26ab;hb=d1fc4416501043db46eaf4e5173dfebad4e98da7;hp=abbf0699183dc71ef13d0444baa235223dbba8d4;hpb=32e09465ce1b21b95b8f2915c2ef97a3dcc0f2fe;p=freertos diff --git a/FreeRTOS/Demo/Common/Minimal/EventGroupsDemo.c b/FreeRTOS/Demo/Common/Minimal/EventGroupsDemo.c index abbf06991..21b2d7769 100644 --- a/FreeRTOS/Demo/Common/Minimal/EventGroupsDemo.c +++ b/FreeRTOS/Demo/Common/Minimal/EventGroupsDemo.c @@ -1,76 +1,41 @@ /* - FreeRTOS V7.6.0 - Copyright (C) 2013 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! -*/ + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ /* - * This file contains fairly comprehensive checks on the behaviour of event - * groups. It is not intended to be a user friendly demonstration of the event - * groups API. - */ - +* This file contains fairly comprehensive checks on the behaviour of event +* groups. It is not intended to be a user friendly demonstration of the +* event groups API. +* +* NOTE: The tests implemented in this file are informal 'sanity' tests +* only and are not part of the module tests that make use of the +* mtCOVERAGE_TEST_MARKER macro within the event groups implementation. +*/ /* Scheduler include files. */ @@ -78,21 +43,28 @@ #include "task.h" #include "event_groups.h" +/* Demo app includes. */ +#include "EventGroupsDemo.h" + +#if( INCLUDE_eTaskGetState != 1 ) + #error INCLUDE_eTaskGetState must be set to 1 in FreeRTOSConfig.h to use this demo file. +#endif + /* Priorities used by the tasks. */ #define ebSET_BIT_TASK_PRIORITY ( tskIDLE_PRIORITY ) #define ebWAIT_BIT_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 ) /* Generic bit definitions. */ -#define ebBIT_0 ( 0x01UL ) -#define ebBIT_1 ( 0x02UL ) -#define ebBIT_2 ( 0x04UL ) -#define ebBIT_3 ( 0x08UL ) -#define ebBIT_4 ( 0x10UL ) -#define ebBIT_5 ( 0x20UL ) -#define ebBIT_6 ( 0x40UL ) -#define ebBIT_7 ( 0x80UL ) - -/* Combinations of bits used in the tests. */ +#define ebBIT_0 ( 0x01 ) +#define ebBIT_1 ( 0x02 ) +#define ebBIT_2 ( 0x04 ) +#define ebBIT_3 ( 0x08 ) +#define ebBIT_4 ( 0x10 ) +#define ebBIT_5 ( 0x20 ) +#define ebBIT_6 ( 0x40 ) +#define ebBIT_7 ( 0x80 ) + +/* Combinations of bits used in the demo. */ #define ebCOMBINED_BITS ( ebBIT_1 | ebBIT_5 | ebBIT_7 ) #define ebALL_BITS ( ebBIT_0 | ebBIT_1 | ebBIT_2 | ebBIT_3 | ebBIT_4 | ebBIT_5 | ebBIT_6 | ebBIT_7 ) @@ -106,340 +78,324 @@ that synchronise with the xEventGroupSync() function. */ /* A block time of zero simply means "don't block". */ #define ebDONT_BLOCK ( 0 ) +#define ebONE_TICK ( ( TickType_t ) 1 ) /* A 5ms delay. */ -#define ebSHORT_DELAY ( 5 / portTICK_RATE_MS ) +#define ebSHORT_DELAY pdMS_TO_TICKS( ( TickType_t ) 5 ) + +/* Used in the selective bits test which checks no, one or both tasks blocked on +event bits in a group are unblocked as appropriate as different bits get set. */ +#define ebSELECTIVE_BITS_1 0x03 +#define ebSELECTIVE_BITS_2 0x05 + +#ifndef ebRENDESVOUS_TEST_TASK_STACK_SIZE + #define ebRENDESVOUS_TEST_TASK_STACK_SIZE configMINIMAL_STACK_SIZE +#endif + +#ifndef ebEVENT_GROUP_SET_BITS_TEST_TASK_STACK_SIZE + #define ebEVENT_GROUP_SET_BITS_TEST_TASK_STACK_SIZE configMINIMAL_STACK_SIZE +#endif /*-----------------------------------------------------------*/ /* - * The primary task that manages and controls all the behavioural tests. + * NOTE: The tests implemented in this function are informal 'sanity' tests + * only and are not part of the module tests that make use of the + * mtCOVERAGE_TEST_MARKER macro within the event groups implementation. + * + * The master test task. This task: + * + * 1) Calls prvSelectiveBitsTestMasterFunction() to test the behaviour when two + * tasks are blocked on different bits in an event group. The counterpart of + * this test is implemented by the prvSelectiveBitsTestSlaveFunction() + * function (which is called by the two tasks that block on the event group). + * + * 2) Calls prvBitCombinationTestMasterFunction() to test the behaviour when + * just one task is blocked on various combinations of bits within an event + * group. The counterpart of this test is implemented within the 'test + * slave' task. + * + * 3) Calls prvPerformTaskSyncTests() to test task synchronisation behaviour. + */ +static void prvTestMasterTask( void *pvParameters ); + +/* + * A helper task that enables the 'test master' task to perform several + * behavioural tests. See the comments above the prvTestMasterTask() prototype + * above. + */ +static void prvTestSlaveTask( void *pvParameters ); + +/* + * The part of the test that is performed between the 'test master' task and the + * 'test slave' task to test the behaviour when the slave blocks on various + * event bit combinations. */ -static void prvSetBitsTask( void *pvParameters ); +static BaseType_t prvBitCombinationTestMasterFunction( BaseType_t xError, TaskHandle_t xTestSlaveTaskHandle ); /* - * The task that participates in most of the non 'single task' tests performed - * by prvSetBitsTask(). + * The part of the test that uses all the tasks to test the task synchronisation + * behaviour. */ -static void prvWaitBitsTask( void *pvParameters ); +static BaseType_t prvPerformTaskSyncTests( BaseType_t xError, TaskHandle_t xTestSlaveTaskHandle ); /* - * Two instances of prvSyncTask() are created. Their only purpose is to - * participate in synchronisations and test the behaviour when an event group on - * which they are blocked is deleted. + * Two instances of prvSyncTask() are created. They start by calling + * prvSelectiveBitsTestSlaveFunction() to act as slaves when the test master is + * executing the prvSelectiveBitsTestMasterFunction() function. They then loop + * to test the task synchronisation (rendezvous) behaviour. */ static void prvSyncTask( void *pvParameters ); /* - * Contains a set of behavioural tests that can be performed from a single task. - * This function is called by prvSetBitsTask() before prvSetBitsTasks() starts - * the tests that make use of the prvWaitBitsTask(). + * Functions used in a test that blocks two tasks on various different bits + * within an event group - then sets each bit in turn and checks that the + * correct tasks unblock at the correct times. */ -static portBASE_TYPE prvSingleTaskTests( void ); +static BaseType_t prvSelectiveBitsTestMasterFunction( void ); +static void prvSelectiveBitsTestSlaveFunction( void ); /*-----------------------------------------------------------*/ /* Variables that are incremented by the tasks on each cycle provided no errors have been found. Used to detect an error or stall in the test cycling. */ -static volatile unsigned long ulSetBitCycles = 0, ulWaitBitCycles = 0; +static volatile uint32_t ulTestMasterCycles = 0, ulTestSlaveCycles = 0, ulISRCycles = 0; -/* The event group used by all the tests. */ -static xEventGroupHandle xEventBits = NULL; +/* The event group used by all the task based tests. */ +static EventGroupHandle_t xEventGroup = NULL; + +/* The event group used by the interrupt based tests. */ +static EventGroupHandle_t xISREventGroup = NULL; /* Handles to the tasks that only take part in the synchronisation calls. */ -static xTaskHandle xSyncTask1 = NULL, xSyncTask2 = NULL; +static TaskHandle_t xSyncTask1 = NULL, xSyncTask2 = NULL; /*-----------------------------------------------------------*/ -void vStartEventBitTasks( void ) +void vStartEventGroupTasks( void ) { -xTaskHandle xWaitBitsTaskHandle; +TaskHandle_t xTestSlaveTaskHandle; /* * This file contains fairly comprehensive checks on the behaviour of event * groups. It is not intended to be a user friendly demonstration of the * event groups API. + * + * NOTE: The tests implemented in this file are informal 'sanity' tests + * only and are not part of the module tests that make use of the + * mtCOVERAGE_TEST_MARKER macro within the event groups implementation. + * + * Create the test tasks as described at the top of this file. */ - - /* Create the event bits that will be used by the tasks. */ - xEventBits = xEventGroupCreate(); - configASSERT( xEventBits ); - - xTaskCreate( prvWaitBitsTask, ( signed char * ) "WaitO", configMINIMAL_STACK_SIZE, NULL, ebWAIT_BIT_TASK_PRIORITY, &xWaitBitsTaskHandle ); - xTaskCreate( prvSetBitsTask, ( signed char * ) "SetB", configMINIMAL_STACK_SIZE, ( void * ) xWaitBitsTaskHandle, ebSET_BIT_TASK_PRIORITY, NULL ); - xTaskCreate( prvSyncTask, ( signed char * ) "Rndv", configMINIMAL_STACK_SIZE, ( void * ) ebRENDESVOUS_TASK_1_SYNC_BIT, ebWAIT_BIT_TASK_PRIORITY, &xSyncTask1 ); - xTaskCreate( prvSyncTask, ( signed char * ) "Rndv", configMINIMAL_STACK_SIZE, ( void * ) ebRENDESVOUS_TASK_2_SYNC_BIT, ebWAIT_BIT_TASK_PRIORITY, &xSyncTask2 ); + xTaskCreate( prvTestSlaveTask, "WaitO", ebRENDESVOUS_TEST_TASK_STACK_SIZE, NULL, ebWAIT_BIT_TASK_PRIORITY, &xTestSlaveTaskHandle ); + xTaskCreate( prvTestMasterTask, "SetB", ebEVENT_GROUP_SET_BITS_TEST_TASK_STACK_SIZE, ( void * ) xTestSlaveTaskHandle, ebSET_BIT_TASK_PRIORITY, NULL ); + xTaskCreate( prvSyncTask, "Rndv", ebRENDESVOUS_TEST_TASK_STACK_SIZE, ( void * ) ebRENDESVOUS_TASK_1_SYNC_BIT, ebWAIT_BIT_TASK_PRIORITY, &xSyncTask1 ); + xTaskCreate( prvSyncTask, "Rndv", ebRENDESVOUS_TEST_TASK_STACK_SIZE, ( void * ) ebRENDESVOUS_TASK_2_SYNC_BIT, ebWAIT_BIT_TASK_PRIORITY, &xSyncTask2 ); /* If the last task was created then the others will have been too. */ configASSERT( xSyncTask2 ); + + /* Create the event group used by the ISR tests. The event group used by + the tasks is created by the tasks themselves. */ + xISREventGroup = xEventGroupCreate(); + configASSERT( xISREventGroup ); } /*-----------------------------------------------------------*/ -static portBASE_TYPE prvSingleTaskTests( void ) +static void prvTestMasterTask( void *pvParameters ) { -xEventBitsType uxReturned; -portBASE_TYPE xError = pdFALSE, xHigherPriorityTaskWoken; -portTickType xTimeOnEntering, xTimeOnExiting; - - /* Check no bits are currently set. */ - uxReturned = xEventGroupWaitBits( xEventBits, /* The event flags being tested. */ - ebBIT_1, /* The bit being tested. */ - pdFALSE, /* Don't clear the bit on exit. */ - pdFALSE, /* Wait for a single bit, not all the bits. */ - ebDONT_BLOCK ); /* Block time. */ - - if( uxReturned != 0x00 ) - { - xError = pdTRUE; - } - - /* Set selected bits. */ - xEventGroupSetBits( xEventBits, ebCOMBINED_BITS ); - - /* Wait on all the selected bits. This should return immediately even - though a block time is specified. */ - uxReturned = xEventGroupWaitBits( xEventBits, ebCOMBINED_BITS, pdFALSE, pdTRUE, portMAX_DELAY ); - - if( uxReturned != ebCOMBINED_BITS ) - { - xError = pdTRUE; - } - - /* Now try waiting on all the selected bits plus a bit that is not set. - This should time out. */ - xTimeOnEntering = xTaskGetTickCount(); - uxReturned = xEventGroupWaitBits( xEventBits, /* The event flags being tested. */ - ebCOMBINED_BITS | ebBIT_0, /* The bits being tested. */ - pdFALSE, /* Don't clear the bits on exit. */ - pdTRUE, /* Wait for all the bits to be set, not just a single bit. */ - ebSHORT_DELAY ); /* Block time. */ - xTimeOnExiting = xTaskGetTickCount(); - - if( ( xTimeOnExiting - xTimeOnEntering ) < ebSHORT_DELAY ) - { - /* Did not block as expected. */ - xError = pdTRUE; - } - - if( uxReturned != ebCOMBINED_BITS ) - { - xError = pdTRUE; - } - - - /* This time pass in the same bit combination, but wait for only a single - bit. This time it should not block even though one of the bits in the - combination is not set. */ - xTimeOnEntering = xTaskGetTickCount(); - uxReturned = xEventGroupWaitBits( xEventBits, /* The event flags being tested. */ - ebCOMBINED_BITS | ebBIT_0, /* The bits being tested. */ - pdFALSE, /* Don't clear the bits on exit. */ - pdFALSE, /* Don't wait for all the bits to be set, a single bit is all that is required. */ - ebSHORT_DELAY ); /* Block time. */ - xTimeOnExiting = xTaskGetTickCount(); +BaseType_t xError; - if( ( xTimeOnExiting - xTimeOnEntering ) >= ebSHORT_DELAY ) - { - /* Blocked, but didn't expect to. */ - xError = pdTRUE; - } - - if( uxReturned != ebCOMBINED_BITS ) - { - xError = pdTRUE; - } - - - /* Now set all the bits. */ - xEventGroupSetBits( xEventBits, ebALL_BITS ); - - /* Read the bits back to ensure they are all set. Read back with a timeout - to ensure the task does not block (all the bits are already set), and leave - the bits set on exit. */ - xTimeOnEntering = xTaskGetTickCount(); - uxReturned = xEventGroupWaitBits( xEventBits, /* The event flags being tested. */ - ebALL_BITS, /* The bits being tested. */ - pdFALSE, /* Don't clear the bits on exit. */ - pdTRUE, /* Wait for all the bits to be set. */ - ebSHORT_DELAY );/* Block time. */ - xTimeOnExiting = xTaskGetTickCount(); - - if( ( xTimeOnExiting - xTimeOnEntering ) >= ebSHORT_DELAY ) - { - /* Blocked, but didn't expect to. */ - xError = pdTRUE; - } +/* The handle to the slave task is passed in as the task parameter. */ +TaskHandle_t xTestSlaveTaskHandle = ( TaskHandle_t ) pvParameters; - if( uxReturned != ebALL_BITS ) - { - xError = pdTRUE; - } - - - /* Now wait for some bits to be set (which are all set), and clear the bits - on exit. Again this should not block. */ - xTimeOnEntering = xTaskGetTickCount(); - uxReturned = xEventGroupWaitBits( xEventBits, /* The event flags being tested. */ - ebCOMBINED_BITS, /* The bits being tested, which are a subset of the bits now set. */ - pdTRUE, /* Clear the bits on exit. */ - pdTRUE, /* Wait for all the bits to be set (which they already are. */ - ebSHORT_DELAY ); /* Block time. */ - xTimeOnExiting = xTaskGetTickCount(); - - if( ( xTimeOnExiting - xTimeOnEntering ) >= ebSHORT_DELAY ) - { - /* Blocked, but didn't expect to. */ - xError = pdTRUE; - } - - if( uxReturned != ebALL_BITS ) - { - xError = pdTRUE; - } + /* Avoid compiler warnings. */ + ( void ) pvParameters; - /* Now the bits set by the ebCOMBINED_BITS constant should be clear, but - all the other bits should be set. Call xEventGroupWaitBits() again, this time - waiting for any bit within ebALL_BITS, and clearing all bits on exit to - leave the event bits all clear again. */ - xTimeOnEntering = xTaskGetTickCount(); - uxReturned = xEventGroupWaitBits( xEventBits, /* The event flags being tested. */ - ebALL_BITS, /* The bits being tested, which are a subset of the bits now set. */ - pdTRUE, /* Clear the bits on exit. */ - pdFALSE, /* Wait for any bit to be set. */ - ebSHORT_DELAY ); /* Block time. */ - xTimeOnExiting = xTaskGetTickCount(); + /* Create the event group used by the tasks ready for the initial tests. */ + xEventGroup = xEventGroupCreate(); + configASSERT( xEventGroup ); - if( ( xTimeOnExiting - xTimeOnEntering ) >= ebSHORT_DELAY ) - { - /* Blocked, but didn't expect to. */ - xError = pdTRUE; - } + /* Perform the tests that block two tasks on different combinations of bits, + then set each bit in turn and check the correct tasks unblock at the correct + times. */ + xError = prvSelectiveBitsTestMasterFunction(); - /* The bits defined in ebCOMBINED_BITS were already cleared, so this time - only the remaining bits should have been set. */ - if( uxReturned != ( ebALL_BITS & ~ebCOMBINED_BITS ) ) + for( ;; ) { - xError = pdTRUE; - } + /* Recreate the event group ready for the next cycle. */ + xEventGroup = xEventGroupCreate(); + configASSERT( xEventGroup ); + /* Perform the tests that check the behaviour when a single task is + blocked on various combinations of event bits. */ + xError = prvBitCombinationTestMasterFunction( xError, xTestSlaveTaskHandle ); + /* Perform the task synchronisation tests. */ + xError = prvPerformTaskSyncTests( xError, xTestSlaveTaskHandle ); - /* All the bits should be clear again as the last call to xEventGroupWaitBits() - had the "clear on exit" parameter set to pdTRUE. */ - uxReturned = xEventGroupGetBits( xEventBits ); + /* Delete the event group. */ + vEventGroupDelete( xEventGroup ); - if( uxReturned != 0x00 ) - { - /* Expected all bits to be clear. */ - xError = pdTRUE; - } + /* Now all the other tasks should have completed and suspended + themselves ready for the next go around the loop. */ + if( eTaskGetState( xTestSlaveTaskHandle ) != eSuspended ) + { + xError = pdTRUE; + } - /* Try the 'set from ISR' function, which will pend the set to the timer - daemon task. */ - xHigherPriorityTaskWoken = pdFALSE; - if( xEventGroupSetBitsFromISR( xEventBits, ebBIT_3, &xHigherPriorityTaskWoken ) != pdPASS ) - { - xError = pdTRUE; - } + if( eTaskGetState( xSyncTask1 ) != eSuspended ) + { + xError = pdTRUE; + } - if( xHigherPriorityTaskWoken == pdTRUE ) - { - /* If the daemon task has a higher priority then a yield should be - performed to ensure it runs before the bits are tested. */ - taskYIELD(); - } + if( eTaskGetState( xSyncTask2 ) != eSuspended ) + { + xError = pdTRUE; + } - /* Is the bit set? */ - uxReturned = xEventGroupGetBits( xEventBits ); + /* Only increment the cycle variable if no errors have been detected. */ + if( xError == pdFALSE ) + { + ulTestMasterCycles++; + } - if( uxReturned != ebBIT_3 ) - { - /* Expected all bits to be clear. */ - xError = pdTRUE; + configASSERT( xError == pdFALSE ); } - - /* Clear all bits again ready for infinite loop tests. */ - xEventGroupClearBits( xEventBits, ebALL_BITS ); - - return xError; } /*-----------------------------------------------------------*/ static void prvSyncTask( void *pvParameters ) { -xEventBitsType uxSynchronisationBit, uxReturned; +EventBits_t uxSynchronisationBit, uxReturned; + + /* A few tests that check the behaviour when two tasks are blocked on + various different bits within an event group are performed before this task + enters its infinite loop to carry out its main demo function. */ + prvSelectiveBitsTestSlaveFunction(); /* The bit to use to indicate this task is at the synchronisation point is passed in as the task parameter. */ - uxSynchronisationBit = ( xEventBitsType ) pvParameters; + uxSynchronisationBit = ( EventBits_t ) pvParameters; for( ;; ) { - /* Wait until the 'set bit' task unsuspends this task. */ + /* Now this task takes part in a task synchronisation - sometimes known + as a 'rendezvous'. Its execution pattern is controlled by the 'test + master' task, which is responsible for taking this task out of the + Suspended state when it is time to test the synchronisation behaviour. + See: http://www.freertos.org/xEventGroupSync.html. */ vTaskSuspend( NULL ); /* Set the bit that indicates this task is at the synchronisation - point. The first time this is done the 'set bit' task has a lower - priority than this task. */ - uxReturned = xEventGroupSync( xEventBits, uxSynchronisationBit, ebALL_SYNC_BITS, portMAX_DELAY ); + point. The first time this is done the 'test master' task has a lower + priority than this task so this task will get to the sync point before + the set bits task - test this by first calling xEventGroupSync() with + a zero block time, and a block time that is too short for the other + task, before calling again with a max delay - the first two calls should + return before the rendezvous completes, the third only after the + rendezvous is complete. */ + uxReturned = xEventGroupSync( xEventGroup, /* The event group used for the synchronisation. */ + uxSynchronisationBit, /* The bit to set in the event group to indicate this task is at the sync point. */ + ebALL_SYNC_BITS,/* The bits to wait for - these bits are set by the other tasks taking part in the sync. */ + ebDONT_BLOCK ); /* The maximum time to wait for the sync condition to be met before giving up. */ + + /* No block time was specified, so as per the comments above, the + rendezvous is not expected to have completed yet. */ + configASSERT( ( uxReturned & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS ); + + uxReturned = xEventGroupSync( xEventGroup, /* The event group used for the synchronisation. */ + uxSynchronisationBit, /* The bit to set in the event group to indicate this task is at the sync point. */ + ebALL_SYNC_BITS, /* The bits to wait for - these bits are set by the other tasks taking part in the sync. */ + ebONE_TICK ); /* The maximum time to wait for the sync condition to be met before giving up. */ + + /* A short block time was specified, so as per the comments above, the + rendezvous is not expected to have completed yet. */ + configASSERT( ( uxReturned & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS ); + + uxReturned = xEventGroupSync( xEventGroup, /* The event group used for the synchronisation. */ + uxSynchronisationBit, /* The bit to set in the event group to indicate this task is at the sync point. */ + ebALL_SYNC_BITS,/* The bits to wait for - these bits are set by the other tasks taking part in the sync. */ + portMAX_DELAY );/* The maximum time to wait for the sync condition to be met before giving up. */ + + /* A max delay was used, so this task should only exit the above + function call when the sync condition is met. Check this is the + case. */ configASSERT( ( uxReturned & ebALL_SYNC_BITS ) == ebALL_SYNC_BITS ); - /* Wait until the 'set bit' task unsuspends this task again. */ + /* Remove compiler warning if configASSERT() is not defined. */ + ( void ) uxReturned; + + /* Wait until the 'test master' task unsuspends this task again. */ vTaskSuspend( NULL ); /* Set the bit that indicates this task is at the synchronisation - point again. This time the 'set bit' task has a higher priority than - this task. */ - uxReturned = xEventGroupSync( xEventBits, uxSynchronisationBit, ebALL_SYNC_BITS, portMAX_DELAY ); + point again. This time the 'test master' task has a higher priority + than this task so will get to the sync point before this task. */ + uxReturned = xEventGroupSync( xEventGroup, uxSynchronisationBit, ebALL_SYNC_BITS, portMAX_DELAY ); + + /* Again a max delay was used, so this task should only exit the above + function call when the sync condition is met. Check this is the + case. */ configASSERT( ( uxReturned & ebALL_SYNC_BITS ) == ebALL_SYNC_BITS ); /* Block on the event group again. This time the event group is going - to be deleted, so 0 should be returned. */ - uxReturned = xEventGroupWaitBits( xEventBits, ebALL_SYNC_BITS, pdFALSE, pdTRUE, portMAX_DELAY ); + to be deleted while this task is blocked on it so it is expected that 0 + be returned. */ + uxReturned = xEventGroupWaitBits( xEventGroup, ebALL_SYNC_BITS, pdFALSE, pdTRUE, portMAX_DELAY ); configASSERT( uxReturned == 0 ); } } /*-----------------------------------------------------------*/ -static void prvWaitBitsTask( void *pvParameters ) +static void prvTestSlaveTask( void *pvParameters ) { -xEventBitsType uxReturned; -portBASE_TYPE xError = pdFALSE; +EventBits_t uxReturned; +BaseType_t xError = pdFALSE; /* Avoid compiler warnings. */ ( void ) pvParameters; for( ;; ) { - /* This task is controller by the prvSetBitsTask(). Suspend until resumed - by prvSetBitsTask(). */ + /********************************************************************** + * Part 1: This section is the counterpart to the + * prvBitCombinationTestMasterFunction() function which is called by the + * test master task. + *********************************************************************** + + This task is controller by the 'test master' task (which is + implemented by prvTestMasterTask()). Suspend until resumed by the + 'test master' task. */ vTaskSuspend( NULL ); /* Wait indefinitely for one of the bits in ebCOMBINED_BITS to get set. Clear the bit on exit. */ - uxReturned = xEventGroupWaitBits( xEventBits, /* The event bits being queried. */ - ebBIT_1, /* The bit to wait for. */ - pdTRUE, /* Clear the bit on exit. */ - pdTRUE, /* Wait for all the bits (only one in this case anyway. */ - portMAX_DELAY ); - - /* Should unblock after the 'set bit' task has set all the bits in the - ebCOMBINED_BITS constant, therefore ebCOMBINED_BITS is what should have - been returned. */ + uxReturned = xEventGroupWaitBits( xEventGroup, /* The event group that contains the event bits being queried. */ + ebBIT_1, /* The bit to wait for. */ + pdTRUE, /* Clear the bit on exit. */ + pdTRUE, /* Wait for all the bits (only one in this case anyway). */ + portMAX_DELAY ); /* Block indefinitely to wait for the condition to be met. */ + + /* The 'test master' task set all the bits defined by ebCOMBINED_BITS, + only one of which was being waited for by this task. The return value + shows the state of the event bits when the task was unblocked, however + because the task was waiting for ebBIT_1 and 'clear on exit' was set to + the current state of the event bits will have ebBIT_1 clear. */ if( uxReturned != ebCOMBINED_BITS ) { xError = pdTRUE; } - /* Now call xEventGroupWaitBits() again, this time waiting for all the bits - in ebCOMBINED_BITS to be set. This call should block until the 'set - bits' task sets ebBIT_1 - which was the bit cleared in the call to - xEventGroupWaitBits() above. */ - uxReturned = xEventGroupWaitBits( xEventBits, - ebCOMBINED_BITS, /* The bits being waited on. */ - pdFALSE, /* Don't clear the bits on exit. */ - pdTRUE, /* All the bits must be set to unblock. */ - portMAX_DELAY ); + /* Now call xEventGroupWaitBits() again, this time waiting for all the + bits in ebCOMBINED_BITS to be set. This call should block until the + 'test master' task sets ebBIT_1 - which was the bit cleared in the call + to xEventGroupWaitBits() above. */ + uxReturned = xEventGroupWaitBits( xEventGroup, + ebCOMBINED_BITS, /* The bits being waited on. */ + pdFALSE, /* Don't clear the bits on exit. */ + pdTRUE, /* All the bits must be set to unblock. */ + portMAX_DELAY ); /* Were all the bits set? */ if( ( uxReturned & ebCOMBINED_BITS ) != ebCOMBINED_BITS ) @@ -447,29 +403,49 @@ portBASE_TYPE xError = pdFALSE; xError = pdTRUE; } - /* Suspend again to wait for the 'set bit' task. */ + /* Suspend again to wait for the 'test master' task. */ vTaskSuspend( NULL ); - /* Now call xEventGroupWaitBits() again, again waiting for all the bits in - ebCOMBINED_BITS to be set, but this time clearing the bits when the task - is unblocked. */ - uxReturned = xEventGroupWaitBits( xEventBits, + /* Now call xEventGroupWaitBits() again, again waiting for all the bits + in ebCOMBINED_BITS to be set, but this time clearing the bits when the + task is unblocked. */ + uxReturned = xEventGroupWaitBits( xEventGroup, ebCOMBINED_BITS, /* The bits being waited on. */ pdTRUE, /* Clear the bits on exit. */ pdTRUE, /* All the bits must be set to unblock. */ portMAX_DELAY ); - + /* The 'test master' task set all the bits in the event group, so that + is the value that should have been returned. The bits defined by + ebCOMBINED_BITS will have been clear again in the current value though + as 'clear on exit' was set to pdTRUE. */ if( uxReturned != ebALL_BITS ) { xError = pdTRUE; } + + + + + /********************************************************************** + * Part 2: This section is the counterpart to the + * prvPerformTaskSyncTests() function which is called by the + * test master task. + *********************************************************************** + + + Once again wait for the 'test master' task to unsuspend this task + when it is time for the next test. */ vTaskSuspend( NULL ); - /* Now to synchronise with when 'set bit' task has the lowest - priority. */ - uxReturned = xEventGroupSync( xEventBits, ebWAIT_BIT_TASK_SYNC_BIT, ebALL_SYNC_BITS, portMAX_DELAY ); + /* Now peform a synchronisation with all the other tasks. At this point + the 'test master' task has the lowest priority so will get to the sync + point after all the other synchronising tasks. */ + uxReturned = xEventGroupSync( xEventGroup, /* The event group used for the sync. */ + ebWAIT_BIT_TASK_SYNC_BIT, /* The bit in the event group used to indicate this task is at the sync point. */ + ebALL_SYNC_BITS, /* The bits to wait for. These bits are set by the other tasks taking part in the sync. */ + portMAX_DELAY ); /* The maximum time to wait for the sync condition to be met before giving up. */ /* A sync with a max delay should only exit when all the synchronisation bits are set... */ @@ -478,8 +454,17 @@ portBASE_TYPE xError = pdFALSE; xError = pdTRUE; } - /* ...but now the synchronisation bits should be clear again. */ - if( xEventGroupSetBits( xEventBits, 0x00 ) != 0 ) + /* ...but now the synchronisation bits should be clear again. Read back + the current value of the bits within the event group to check that is + the case. Setting the bits to zero will return the bits previous value + then leave all the bits clear. */ + if( xEventGroupSetBits( xEventGroup, 0x00 ) != 0 ) + { + xError = pdTRUE; + } + + /* Check the bits are indeed 0 now by simply reading then. */ + if( xEventGroupGetBits( xEventGroup ) != 0 ) { xError = pdTRUE; } @@ -487,14 +472,15 @@ portBASE_TYPE xError = pdFALSE; if( xError == pdFALSE ) { /* This task is still cycling without finding an error. */ - ulWaitBitCycles++; + ulTestSlaveCycles++; } vTaskSuspend( NULL ); - /* This time sync when the 'set bit' task has the highest priority - at the point where it sets its sync bit. */ - uxReturned = xEventGroupSync( xEventBits, ebWAIT_BIT_TASK_SYNC_BIT, ebALL_SYNC_BITS, portMAX_DELAY ); + /* This time sync when the 'test master' task has the highest priority + at the point where it sets its sync bit - so this time the 'test master' + task will get to the sync point before this task. */ + uxReturned = xEventGroupSync( xEventGroup, ebWAIT_BIT_TASK_SYNC_BIT, ebALL_SYNC_BITS, portMAX_DELAY ); /* A sync with a max delay should only exit when all the synchronisation bits are set... */ @@ -504,14 +490,15 @@ portBASE_TYPE xError = pdFALSE; } /* ...but now the sync bits should be clear again. */ - if( xEventGroupSetBits( xEventBits, 0x00 ) != 0 ) + if( xEventGroupSetBits( xEventGroup, 0x00 ) != 0 ) { xError = pdTRUE; } /* Block on the event group again. This time the event group is going - to be deleted, so 0 should be returned. */ - uxReturned = xEventGroupWaitBits( xEventBits, ebALL_SYNC_BITS, pdFALSE, pdTRUE, portMAX_DELAY ); + to be deleted while this task is blocked on it, so it is expected that 0 + will be returned. */ + uxReturned = xEventGroupWaitBits( xEventGroup, ebALL_SYNC_BITS, pdFALSE, pdTRUE, portMAX_DELAY ); if( uxReturned != 0 ) { @@ -521,7 +508,7 @@ portBASE_TYPE xError = pdFALSE; if( xError == pdFALSE ) { /* This task is still cycling without finding an error. */ - ulWaitBitCycles++; + ulTestSlaveCycles++; } configASSERT( xError == pdFALSE ); @@ -529,219 +516,390 @@ portBASE_TYPE xError = pdFALSE; } /*-----------------------------------------------------------*/ -static void prvSetBitsTask( void *pvParameters ) +static BaseType_t prvPerformTaskSyncTests( BaseType_t xError, TaskHandle_t xTestSlaveTaskHandle ) { -xEventBitsType uxBits; -portBASE_TYPE xError; +EventBits_t uxBits; -/* The handle to the other task is passed in as the task parameter. */ -xTaskHandle xWaitBitsTaskHandle = ( xTaskHandle ) pvParameters; + /* The three tasks that take part in the synchronisation (rendezvous) are + expected to be in the suspended state at the start of the test. */ + if( eTaskGetState( xTestSlaveTaskHandle ) != eSuspended ) + { + xError = pdTRUE; + } - /* Avoid compiler warnings. */ - ( void ) pvParameters; + if( eTaskGetState( xSyncTask1 ) != eSuspended ) + { + xError = pdTRUE; + } + + if( eTaskGetState( xSyncTask2 ) != eSuspended ) + { + xError = pdTRUE; + } - xError = prvSingleTaskTests(); + /* Try a synch with no other tasks involved. First set all the bits other + than this task's bit. */ + xEventGroupSetBits( xEventGroup, ( ebALL_SYNC_BITS & ~ebSET_BIT_TASK_SYNC_BIT ) ); - for( ;; ) + /* Then wait on just one bit - the bit that is being set. */ + uxBits = xEventGroupSync( xEventGroup, /* The event group used for the synchronisation. */ + ebSET_BIT_TASK_SYNC_BIT,/* The bit set by this task when it reaches the sync point. */ + ebSET_BIT_TASK_SYNC_BIT,/* The bits to wait for - in this case it is just waiting for itself. */ + portMAX_DELAY ); /* The maximum time to wait for the sync condition to be met. */ + + /* A sync with a max delay should only exit when all the synchronise + bits are set...check that is the case. In this case there is only one + sync bit anyway. */ + if( ( uxBits & ebSET_BIT_TASK_SYNC_BIT ) != ebSET_BIT_TASK_SYNC_BIT ) { - /* Resume the other task. It will block, pending a single bit from - within ebCOMBINED_BITS. */ - vTaskResume( xWaitBitsTaskHandle ); + xError = pdTRUE; + } - /* Ensure the other task is blocked on the task. */ - if( eTaskGetState( xWaitBitsTaskHandle ) != eBlocked ) - { - xError = pdTRUE; - } + /* ...but now the sync bits should be clear again, leaving all the other + bits set (as only one bit was being waited for). */ + if( xEventGroupGetBits( xEventGroup ) != ( ebALL_SYNC_BITS & ~ebSET_BIT_TASK_SYNC_BIT ) ) + { + xError = pdTRUE; + } - /* Set all the bits in ebCOMBINED_BITS - the 'wait bits' task is only - blocked waiting for one of them. */ - xEventGroupSetBits( xEventBits, ebCOMBINED_BITS ); + /* Clear all the bits to zero again. */ + xEventGroupClearBits( xEventGroup, ( ebALL_SYNC_BITS & ~ebSET_BIT_TASK_SYNC_BIT ) ); + if( xEventGroupGetBits( xEventGroup ) != 0 ) + { + xError = pdTRUE; + } - /* The 'wait bits' task should now have executed, clearing ebBIT_1 (the - bit it was blocked on), then re-entered the Blocked state to wait for - all the other bits in ebCOMBINED_BITS to be set again. First check - ebBIT_1 is clear. */ - uxBits = xEventGroupWaitBits( xEventBits, ebALL_BITS, pdFALSE, pdFALSE, ebDONT_BLOCK ); + /* Unsuspend the other tasks then check they have executed up to the + synchronisation point. */ + vTaskResume( xTestSlaveTaskHandle ); + vTaskResume( xSyncTask1 ); + vTaskResume( xSyncTask2 ); - if( uxBits != ( ebCOMBINED_BITS & ~ebBIT_1 ) ) - { - xError = pdTRUE; - } + if( eTaskGetState( xTestSlaveTaskHandle ) != eBlocked ) + { + xError = pdTRUE; + } - /* Ensure the other task is still in the blocked state. */ - if( eTaskGetState( xWaitBitsTaskHandle ) != eBlocked ) - { - xError = pdTRUE; - } + if( eTaskGetState( xSyncTask1 ) != eBlocked ) + { + xError = pdTRUE; + } - /* Set all the bits other than ebBIT_1 - which is the bit that must be - set before the other task unblocks. */ - xEventGroupSetBits( xEventBits, ebALL_BITS & ~ebBIT_1 ); + if( eTaskGetState( xSyncTask2 ) != eBlocked ) + { + xError = pdTRUE; + } - /* Ensure all the expected bits are still set. */ - uxBits = xEventGroupWaitBits( xEventBits, ebALL_BITS, pdFALSE, pdFALSE, ebDONT_BLOCK ); + /* Set this task's sync bit. */ + uxBits = xEventGroupSync( xEventGroup, /* The event group used for the synchronisation. */ + ebSET_BIT_TASK_SYNC_BIT,/* The bit set by this task when it reaches the sync point. */ + ebALL_SYNC_BITS, /* The bits to wait for - these bits are set by the other tasks that take part in the sync. */ + portMAX_DELAY ); /* The maximum time to wait for the sync condition to be met. */ - if( uxBits != ( ebALL_BITS & ~ebBIT_1 ) ) - { - xError = pdTRUE; - } + /* A sync with a max delay should only exit when all the synchronise + bits are set...check that is the case. */ + if( ( uxBits & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS ) + { + xError = pdTRUE; + } - /* Ensure the other task is still in the blocked state. */ - if( eTaskGetState( xWaitBitsTaskHandle ) != eBlocked ) - { - xError = pdTRUE; - } + /* ...but now the sync bits should be clear again. */ + if( xEventGroupGetBits( xEventGroup ) != 0 ) + { + xError = pdTRUE; + } - /* Now also set ebBIT_1, which should unblock the other task, which will - then suspend itself. */ - xEventGroupSetBits( xEventBits, ebBIT_1 ); - /* Ensure the other task is suspended. */ - if( eTaskGetState( xWaitBitsTaskHandle ) != eSuspended ) - { - xError = pdTRUE; - } + /* The other tasks should now all be suspended again, ready for the next + synchronisation. */ + if( eTaskGetState( xTestSlaveTaskHandle ) != eSuspended ) + { + xError = pdTRUE; + } - /* The other task should not have cleared the bits - so all the bits - should still be set. */ - if( xEventGroupSetBits( xEventBits, 0x00 ) != ebALL_BITS ) - { - xError = pdTRUE; - } + if( eTaskGetState( xSyncTask1 ) != eSuspended ) + { + xError = pdTRUE; + } - /* Clear ebBIT_1 again. */ - if( xEventGroupClearBits( xEventBits, ebBIT_1 ) != ebALL_BITS ) - { - xError = pdTRUE; - } + if( eTaskGetState( xSyncTask2 ) != eSuspended ) + { + xError = pdTRUE; + } - /* Resume the other task - which will wait on all the ebCOMBINED_BITS - again - this time clearing the bits when it is unblocked. */ - vTaskResume( xWaitBitsTaskHandle ); - /* Ensure the other task is blocked once again. */ - if( eTaskGetState( xWaitBitsTaskHandle ) != eBlocked ) - { - xError = pdTRUE; - } + /* Sync again - but this time set the last necessary bit as the + highest priority task, rather than the lowest priority task. Unsuspend + the other tasks then check they have executed up to the synchronisation + point. */ + vTaskResume( xTestSlaveTaskHandle ); + vTaskResume( xSyncTask1 ); + vTaskResume( xSyncTask2 ); - /* Set the bit the other task is waiting for. */ - xEventGroupSetBits( xEventBits, ebBIT_1 ); + if( eTaskGetState( xTestSlaveTaskHandle ) != eBlocked ) + { + xError = pdTRUE; + } - /* Ensure the other task is suspended once again. */ - if( eTaskGetState( xWaitBitsTaskHandle ) != eSuspended ) - { - xError = pdTRUE; - } + if( eTaskGetState( xSyncTask1 ) != eBlocked ) + { + xError = pdTRUE; + } - /* The other task should have cleared the bits in ebCOMBINED_BITS. - Clear the remaining bits. */ - uxBits = xEventGroupWaitBits( xEventBits, ebALL_BITS, pdFALSE, pdFALSE, ebDONT_BLOCK ); + if( eTaskGetState( xSyncTask2 ) != eBlocked ) + { + xError = pdTRUE; + } - if( uxBits != ( ebALL_BITS & ~ebCOMBINED_BITS ) ) - { - xError = pdTRUE; - } + /* Raise the priority of this task above that of the other tasks. */ + vTaskPrioritySet( NULL, ebWAIT_BIT_TASK_PRIORITY + 1 ); - /* Clear all bits ready for the sync with the other three tasks. The - value returned is the value prior to the bits being cleared. */ - if( xEventGroupClearBits( xEventBits, ebALL_BITS ) != ( ebALL_BITS & ~ebCOMBINED_BITS ) ) - { - xError = pdTRUE; - } + /* Set this task's sync bit. */ + uxBits = xEventGroupSync( xEventGroup, ebSET_BIT_TASK_SYNC_BIT, ebALL_SYNC_BITS, portMAX_DELAY ); - /* The bits should be clear now. */ - if( xEventGroupGetBits( xEventBits ) != 0x00 ) - { - xError = pdTRUE; - } + /* A sync with a max delay should only exit when all the synchronisation + bits are set... */ + if( ( uxBits & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS ) + { + xError = pdTRUE; + } - /* Check the other three tasks are suspended. */ - if( eTaskGetState( xWaitBitsTaskHandle ) != eSuspended ) - { - xError = pdTRUE; - } + /* ...but now the sync bits should be clear again. */ + if( xEventGroupGetBits( xEventGroup ) != 0 ) + { + xError = pdTRUE; + } - if( eTaskGetState( xSyncTask1 ) != eSuspended ) - { - xError = pdTRUE; - } - if( eTaskGetState( xSyncTask2 ) != eSuspended ) - { - xError = pdTRUE; - } + /* The other tasks should now all be in the ready state again, but not + executed yet as this task still has a higher relative priority. */ + if( eTaskGetState( xTestSlaveTaskHandle ) != eReady ) + { + xError = pdTRUE; + } - /* Unsuspend the other tasks then check they have executed up to the - synchronisation point. */ - vTaskResume( xWaitBitsTaskHandle ); - vTaskResume( xSyncTask1 ); - vTaskResume( xSyncTask2 ); + if( eTaskGetState( xSyncTask1 ) != eReady ) + { + xError = pdTRUE; + } - if( eTaskGetState( xWaitBitsTaskHandle ) != eBlocked ) - { - xError = pdTRUE; - } + if( eTaskGetState( xSyncTask2 ) != eReady ) + { + xError = pdTRUE; + } - if( eTaskGetState( xSyncTask1 ) != eBlocked ) - { - xError = pdTRUE; - } - if( eTaskGetState( xSyncTask2 ) != eBlocked ) - { - xError = pdTRUE; - } + /* Reset the priority of this task back to its original value. */ + vTaskPrioritySet( NULL, ebSET_BIT_TASK_PRIORITY ); - /* Set this task's sync bit. */ - uxBits = xEventGroupSync( xEventBits, ebSET_BIT_TASK_SYNC_BIT, ebALL_SYNC_BITS, portMAX_DELAY ); + /* Now all the other tasks should have reblocked on the event bits + to test the behaviour when the event bits are deleted. */ + if( eTaskGetState( xTestSlaveTaskHandle ) != eBlocked ) + { + xError = pdTRUE; + } - /* A sync with a max delay should only exit when all the synchronise - bits are set... */ - if( ( uxBits & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS ) - { - xError = pdTRUE; - } + if( eTaskGetState( xSyncTask1 ) != eBlocked ) + { + xError = pdTRUE; + } - /* ...but now the sync bits should be clear again. */ - if( xEventGroupSetBits( xEventBits, 0x00 ) != 0 ) - { - xError = pdTRUE; - } + if( eTaskGetState( xSyncTask2 ) != eBlocked ) + { + xError = pdTRUE; + } + return xError; +} +/*-----------------------------------------------------------*/ - /* The other tasks should now all be suspended again, ready for the next - synchronisation. */ - if( eTaskGetState( xWaitBitsTaskHandle ) != eSuspended ) - { - xError = pdTRUE; - } +static BaseType_t prvBitCombinationTestMasterFunction( BaseType_t xError, TaskHandle_t xTestSlaveTaskHandle ) +{ +EventBits_t uxBits; - if( eTaskGetState( xSyncTask1 ) != eSuspended ) - { - xError = pdTRUE; - } + /* Resume the other task. It will block, pending a single bit from + within ebCOMBINED_BITS. */ + vTaskResume( xTestSlaveTaskHandle ); - if( eTaskGetState( xSyncTask2 ) != eSuspended ) + /* Ensure the other task is blocked on the task. */ + if( eTaskGetState( xTestSlaveTaskHandle ) != eBlocked ) + { + xError = pdTRUE; + } + + /* Set all the bits in ebCOMBINED_BITS - the 'test slave' task is only + blocked waiting for one of them. */ + xEventGroupSetBits( xEventGroup, ebCOMBINED_BITS ); + + /* The 'test slave' task should now have executed, clearing ebBIT_1 (the + bit it was blocked on), then re-entered the Blocked state to wait for + all the other bits in ebCOMBINED_BITS to be set again. First check + ebBIT_1 is clear. */ + uxBits = xEventGroupWaitBits( xEventGroup, ebALL_BITS, pdFALSE, pdFALSE, ebDONT_BLOCK ); + + if( uxBits != ( ebCOMBINED_BITS & ~ebBIT_1 ) ) + { + xError = pdTRUE; + } + + /* Ensure the other task is still in the blocked state. */ + if( eTaskGetState( xTestSlaveTaskHandle ) != eBlocked ) + { + xError = pdTRUE; + } + + /* Set all the bits other than ebBIT_1 - which is the bit that must be + set before the other task unblocks. */ + xEventGroupSetBits( xEventGroup, ebALL_BITS & ~ebBIT_1 ); + + /* Ensure all the expected bits are still set. */ + uxBits = xEventGroupWaitBits( xEventGroup, ebALL_BITS, pdFALSE, pdFALSE, ebDONT_BLOCK ); + + if( uxBits != ( ebALL_BITS & ~ebBIT_1 ) ) + { + xError = pdTRUE; + } + + /* Ensure the other task is still in the blocked state. */ + if( eTaskGetState( xTestSlaveTaskHandle ) != eBlocked ) + { + xError = pdTRUE; + } + + /* Now also set ebBIT_1, which should unblock the other task, which will + then suspend itself. */ + xEventGroupSetBits( xEventGroup, ebBIT_1 ); + + /* Ensure the other task is suspended. */ + if( eTaskGetState( xTestSlaveTaskHandle ) != eSuspended ) + { + xError = pdTRUE; + } + + /* The other task should not have cleared the bits - so all the bits + should still be set. */ + if( xEventGroupSetBits( xEventGroup, 0x00 ) != ebALL_BITS ) + { + xError = pdTRUE; + } + + /* Clear ebBIT_1 again. */ + if( xEventGroupClearBits( xEventGroup, ebBIT_1 ) != ebALL_BITS ) + { + xError = pdTRUE; + } + + /* Resume the other task - which will wait on all the ebCOMBINED_BITS + again - this time clearing the bits when it is unblocked. */ + vTaskResume( xTestSlaveTaskHandle ); + + /* Ensure the other task is blocked once again. */ + if( eTaskGetState( xTestSlaveTaskHandle ) != eBlocked ) + { + xError = pdTRUE; + } + + /* Set the bit the other task is waiting for. */ + xEventGroupSetBits( xEventGroup, ebBIT_1 ); + + /* Ensure the other task is suspended once again. */ + if( eTaskGetState( xTestSlaveTaskHandle ) != eSuspended ) + { + xError = pdTRUE; + } + + /* The other task should have cleared the bits in ebCOMBINED_BITS. + Clear the remaining bits. */ + uxBits = xEventGroupWaitBits( xEventGroup, ebALL_BITS, pdFALSE, pdFALSE, ebDONT_BLOCK ); + + if( uxBits != ( ebALL_BITS & ~ebCOMBINED_BITS ) ) + { + xError = pdTRUE; + } + + /* Clear all bits ready for the sync with the other three tasks. The + value returned is the value prior to the bits being cleared. */ + if( xEventGroupClearBits( xEventGroup, ebALL_BITS ) != ( ebALL_BITS & ~ebCOMBINED_BITS ) ) + { + xError = pdTRUE; + } + + /* The bits should be clear now. */ + if( xEventGroupGetBits( xEventGroup ) != 0x00 ) + { + xError = pdTRUE; + } + + return xError; +} +/*-----------------------------------------------------------*/ + +static void prvSelectiveBitsTestSlaveFunction( void ) +{ +EventBits_t uxPendBits, uxReturned; + + /* Used in a test that blocks two tasks on various different bits within an + event group - then sets each bit in turn and checks that the correct tasks + unblock at the correct times. + + This function is called by two different tasks - each of which will use a + different bit. Check the task handle to see which task the function was + called by. */ + if( xTaskGetCurrentTaskHandle() == xSyncTask1 ) + { + uxPendBits = ebSELECTIVE_BITS_1; + } + else + { + uxPendBits = ebSELECTIVE_BITS_2; + } + + for( ;; ) + { + /* Wait until it is time to perform the next cycle of the test. The + task is unsuspended by the tests implemented in the + prvSelectiveBitsTestMasterFunction() function. */ + vTaskSuspend( NULL ); + uxReturned = xEventGroupWaitBits( xEventGroup, uxPendBits, pdTRUE, pdFALSE, portMAX_DELAY ); + + if( uxReturned == ( EventBits_t ) 0 ) { - xError = pdTRUE; + break; } + } +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvSelectiveBitsTestMasterFunction( void ) +{ +BaseType_t xError = pdFALSE; +EventBits_t uxBit; + + /* Used in a test that blocks two tasks on various different bits within an + event group - then sets each bit in turn and checks that the correct tasks + unblock at the correct times. The two other tasks (xSyncTask1 and + xSyncTask2) call prvSelectiveBitsTestSlaveFunction() to perform their parts in + this test. + + Both other tasks should start in the suspended state. */ + if( eTaskGetState( xSyncTask1 ) != eSuspended ) + { + xError = pdTRUE; + } + if( eTaskGetState( xSyncTask2 ) != eSuspended ) + { + xError = pdTRUE; + } - /* Sync again - but this time set the last necessary bit as the - highest priority task, rather than the lowest priority task. Unsuspend - the other tasks then check they have executed up to the synchronisation - point. */ - vTaskResume( xWaitBitsTaskHandle ); + /* Test each bit in the byte individually. */ + for( uxBit = 0x01; uxBit < 0x100; uxBit <<= 1 ) + { + /* Resume both tasks. */ vTaskResume( xSyncTask1 ); vTaskResume( xSyncTask2 ); - if( eTaskGetState( xWaitBitsTaskHandle ) != eBlocked ) - { - xError = pdTRUE; - } - + /* Now both tasks should be blocked on the event group. */ if( eTaskGetState( xSyncTask1 ) != eBlocked ) { xError = pdTRUE; @@ -752,117 +910,158 @@ xTaskHandle xWaitBitsTaskHandle = ( xTaskHandle ) pvParameters; xError = pdTRUE; } - /* Raise the priority of this task above that of the other tasks. */ - vTaskPrioritySet( NULL, ebWAIT_BIT_TASK_PRIORITY + 1 ); - - /* Set this task's sync bit. */ - uxBits = xEventGroupSync( xEventBits, ebSET_BIT_TASK_SYNC_BIT, ebALL_SYNC_BITS, portMAX_DELAY ); + /* Set one bit. */ + xEventGroupSetBits( xEventGroup, uxBit ); - /* A sync with a max delay should only exit when all the synchronisation - bits are set... */ - if( ( uxBits & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS ) + /* Is the bit set in the first set of selective bits? If so the first + sync task should have unblocked and returned to the suspended state. */ + if( ( uxBit & ebSELECTIVE_BITS_1 ) == 0 ) { - xError = pdTRUE; + /* Task should not have unblocked. */ + if( eTaskGetState( xSyncTask1 ) != eBlocked ) + { + xError = pdTRUE; + } } - - /* ...but now the sync bits should be clear again. */ - if( xEventGroupSetBits( xEventBits, 0x00 ) != 0 ) + else { - xError = pdTRUE; + /* Task should have unblocked and returned to the suspended state. */ + if( eTaskGetState( xSyncTask1 ) != eSuspended ) + { + xError = pdTRUE; + } } - - /* The other tasks should now all be in the ready state again, but not - executed yet as this task still has a higher relative priority. */ - if( eTaskGetState( xWaitBitsTaskHandle ) != eReady ) + /* Same checks for the second sync task. */ + if( ( uxBit & ebSELECTIVE_BITS_2 ) == 0 ) { - xError = pdTRUE; + /* Task should not have unblocked. */ + if( eTaskGetState( xSyncTask2 ) != eBlocked ) + { + xError = pdTRUE; + } } - - if( eTaskGetState( xSyncTask1 ) != eReady ) + else { - xError = pdTRUE; + /* Task should have unblocked and returned to the suspended state. */ + if( eTaskGetState( xSyncTask2 ) != eSuspended ) + { + xError = pdTRUE; + } } + } - if( eTaskGetState( xSyncTask2 ) != eReady ) - { - xError = pdTRUE; - } + /* Ensure both tasks are blocked on the event group again, then delete the + event group so the other tasks leave this portion of the test. */ + vTaskResume( xSyncTask1 ); + vTaskResume( xSyncTask2 ); + /* Deleting the event group is the signal that the two other tasks should + leave the prvSelectiveBitsTestSlaveFunction() function and continue to the main + part of their functionality. */ + vEventGroupDelete( xEventGroup ); - /* Reset the priority of this task back to its original value. */ - vTaskPrioritySet( NULL, ebSET_BIT_TASK_PRIORITY ); + return xError; +} +/*-----------------------------------------------------------*/ - /* Now all the other tasks should have reblocked on the event bits - to test the behaviour when the event bits are deleted. */ - if( eTaskGetState( xWaitBitsTaskHandle ) != eBlocked ) - { - xError = pdTRUE; - } +void vPeriodicEventGroupsProcessing( void ) +{ +static BaseType_t xCallCount = 0, xISRTestError = pdFALSE; +const BaseType_t xSetBitCount = 100, xGetBitsCount = 200, xClearBitsCount = 300; +const EventBits_t uxBitsToSet = 0x12U; +EventBits_t uxReturned; +BaseType_t xMessagePosted; - if( eTaskGetState( xSyncTask1 ) != eBlocked ) - { - xError = pdTRUE; - } + /* Called periodically from the tick hook to exercise the "FromISR" + functions. */ - if( eTaskGetState( xSyncTask2 ) != eBlocked ) - { - xError = pdTRUE; - } + /* Check the even group tasks were actually created. */ + configASSERT( xISREventGroup ); - /* Delete the event group. */ - vEventGroupDelete( xEventBits ); + xCallCount++; - /* Now all the other tasks should have completed and suspended - themselves ready for the next go around the loop. */ - if( eTaskGetState( xWaitBitsTaskHandle ) != eSuspended ) + if( xCallCount == xSetBitCount ) + { + /* All the event bits should start clear. */ + uxReturned = xEventGroupGetBitsFromISR( xISREventGroup ); + if( uxReturned != 0x00 ) { - xError = pdTRUE; + xISRTestError = pdTRUE; } - - if( eTaskGetState( xSyncTask1 ) != eSuspended ) + else { - xError = pdTRUE; + /* Set the bits. This is called from the tick hook so it is not + necessary to use the last parameter to ensure a context switch + occurs immediately. */ + xMessagePosted = xEventGroupSetBitsFromISR( xISREventGroup, uxBitsToSet, NULL ); + if( xMessagePosted != pdPASS ) + { + xISRTestError = pdTRUE; + } } - - if( eTaskGetState( xSyncTask2 ) != eSuspended ) + } + else if( xCallCount == xGetBitsCount ) + { + /* Check the bits were set as expected. */ + uxReturned = xEventGroupGetBitsFromISR( xISREventGroup ); + if( uxReturned != uxBitsToSet ) { - xError = pdTRUE; + xISRTestError = pdTRUE; } + } + else if( xCallCount == xClearBitsCount ) + { + /* Clear the bits again. */ + uxReturned = ( EventBits_t ) xEventGroupClearBitsFromISR( xISREventGroup, uxBitsToSet ); + /* Check the message was posted. */ + if( uxReturned != pdPASS ) + { + xISRTestError = pdTRUE; + } - /* Recreate the event group ready for the next cycle. */ - xEventBits = xEventGroupCreate(); - configASSERT( xEventBits ); + /* Go back to the start. */ + xCallCount = 0; - if( xError == pdFALSE ) + /* If no errors have been detected then increment the count of test + cycles. */ + if( xISRTestError == pdFALSE ) { - ulSetBitCycles++; + ulISRCycles++; } - - configASSERT( xError == pdFALSE ); + } + else + { + /* Nothing else to do. */ } } -/*-----------------------------------------------------------*/ +/*-----------------------------------------------------------*/ /* This is called to check that all the created tasks are still running. */ -portBASE_TYPE xAreEventBitTasksStillRunning( void ) +BaseType_t xAreEventGroupTasksStillRunning( void ) { -static unsigned long ulPreviousWaitBitCycles = 0, ulPreviousSetBitCycles = 0; -portBASE_TYPE xStatus = pdPASS; +static uint32_t ulPreviousWaitBitCycles = 0, ulPreviousSetBitCycles = 0, ulPreviousISRCycles = 0; +BaseType_t xStatus = pdPASS; /* Check the tasks are still cycling without finding any errors. */ - if( ulPreviousSetBitCycles == ulSetBitCycles ) + if( ulPreviousSetBitCycles == ulTestMasterCycles ) + { + xStatus = pdFAIL; + } + ulPreviousSetBitCycles = ulTestMasterCycles; + + if( ulPreviousWaitBitCycles == ulTestSlaveCycles ) { xStatus = pdFAIL; } - ulPreviousSetBitCycles = ulSetBitCycles; + ulPreviousWaitBitCycles = ulTestSlaveCycles; - if( ulPreviousWaitBitCycles == ulWaitBitCycles ) + if( ulPreviousISRCycles == ulISRCycles ) { xStatus = pdFAIL; } - ulPreviousWaitBitCycles = ulWaitBitCycles; + ulPreviousISRCycles = ulISRCycles; return xStatus; }