From 9a7437c6177adc3bb695e70ea298865e722c6d52 Mon Sep 17 00:00:00 2001 From: richardbarry Date: Fri, 8 Feb 2013 15:50:14 +0000 Subject: [PATCH] Continue working on queue set implementation and testing. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@1818 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- FreeRTOS/Demo/Common/Minimal/QueueSet.c | 260 +++++++++++++++++++++--- FreeRTOS/Demo/Common/include/QueueSet.h | 5 +- FreeRTOS/Demo/WIN32-MSVC/WIN32.suo | Bin 62464 -> 62976 bytes FreeRTOS/Demo/WIN32-MSVC/main.c | 7 +- FreeRTOS/Source/include/queue.h | 35 ++-- FreeRTOS/Source/queue.c | 125 ++++++------ 6 files changed, 329 insertions(+), 103 deletions(-) diff --git a/FreeRTOS/Demo/Common/Minimal/QueueSet.c b/FreeRTOS/Demo/Common/Minimal/QueueSet.c index ef06c9be0..15a1e6b36 100644 --- a/FreeRTOS/Demo/Common/Minimal/QueueSet.c +++ b/FreeRTOS/Demo/Common/Minimal/QueueSet.c @@ -70,10 +70,13 @@ * Demonstrates the creation an use of queue sets. * * A receive task creates a number of queues and adds them to a queue set before - * blocking on a queue set receive. A transmit task repeatedly unblocks the - * receive task by sending messages to the queues in a pseudo random order. - * The receive task removes the messages from the queues and flags an error if - * the received message does not match that expected. + * blocking on the queue set receive. A transmit task and (optionally) an + * interrupt repeatedly unblocks the receive task by sending messages to the + * queues in a pseudo random order. The receive task removes the messages from + * the queues and flags an error if the received message does not match that + * expected. The task sends values in the range 0 to + * queuesetINITIAL_ISR_TX_VALUE, and the ISR sends value in the range + * queuesetINITIAL_ISR_TX_VALUE to 0xffffffffUL; */ /* Kernel includes. */ @@ -94,6 +97,23 @@ #define queuesetSHORT_DELAY 200 #define queuesetDONT_BLOCK 0 +/* Messages are sent in incrementing order from both a task and an interrupt. +The task sends values in the range 0 to 0xfffe, and the interrupt sends values +in the range of 0xffff to 0xffffffff; */ +#define queuesetINITIAL_ISR_TX_VALUE 0xffffUL + +/* The priorities used in this demo. */ +#define queuesetLOW_PRIORITY ( tskIDLE_PRIORITY ) +#define queuesetMEDIUM_PRIORITY ( queuesetLOW_PRIORITY + 1 ) +#define queuesetHIGH_PRIORITY ( queuesetMEDIUM_PRIORITY + 1 ) + +/* For test purposes the priority of the sending task is changed after every +queuesetPRIORITY_CHANGE_LOOPS number of values are sent to a queue. */ +#define queuesetPRIORITY_CHANGE_LOOPS 100UL + +/* The ISR sends to the queue every queuesetISR_TX_PERIOD ticks. */ +#define queuesetISR_TX_PERIOD ( 100UL ) + /* * The task that periodically sends to the queue set. */ @@ -107,6 +127,10 @@ static void prvQueueSetReceivingTask( void *pvParameters ); /* The queues that are added to the set. */ static xQueueHandle xQueues[ queuesetNUM_QUEUES_IN_SET ] = { 0 }; +/* Counts how many times each queue in the set is used to ensure all the +queues are used. */ +static unsigned long ulQueueUsedCounter[ queuesetNUM_QUEUES_IN_SET ] = { 0 }; + /* The handle of the queue set to which the queues are added. */ static xQueueSetHandle xQueueSet; @@ -115,24 +139,32 @@ it increments ulCycleCounter on each iteration. xAreQueueSetTasksStillRunning() returns pdPASS if the value of ulCycleCounter has changed between consecutive calls, and pdFALSE if ulCycleCounter has stopped incrementing (indicating an error condition). */ -volatile unsigned long ulCycleCounter = 0UL; +static volatile unsigned long ulCycleCounter = 0UL; /* Set to pdFAIL if an error is detected by any queue set task. ulCycleCounter will only be incremented if xQueueSetTasksSatus equals pdPASS. */ -volatile portBASE_TYPE xQueueSetTasksStatus = pdPASS; +static volatile portBASE_TYPE xQueueSetTasksStatus = pdPASS; + +/* Just a flag to let the function that writes to a queue from an ISR know that +the queues are setup and can be used. */ +static volatile portBASE_TYPE xSetupComplete = pdFALSE; +/* The value sent to the queue from the ISR is file scope so the +xAreQueeuSetTasksStillRunning() function can check it is incrementing as +expected. */ +static volatile unsigned long ulISRTxValue = queuesetINITIAL_ISR_TX_VALUE; /*-----------------------------------------------------------*/ -void vStartQueueSetTasks( unsigned portBASE_TYPE uxPriority ) +void vStartQueueSetTasks( void ) { xTaskHandle xQueueSetSendingTask; /* Create the two queues. The handle of the sending task is passed into the receiving task using the task parameter. The receiving task uses the handle to resume the sending task after it has created the queues. */ - xTaskCreate( prvQueueSetSendingTask, ( signed char * ) "Check", configMINIMAL_STACK_SIZE, NULL, uxPriority, &xQueueSetSendingTask ); - xTaskCreate( prvQueueSetReceivingTask, ( signed char * ) "Check", configMINIMAL_STACK_SIZE, ( void * ) xQueueSetSendingTask, uxPriority, NULL ); + xTaskCreate( prvQueueSetSendingTask, ( signed char * ) "Check", configMINIMAL_STACK_SIZE, NULL, queuesetMEDIUM_PRIORITY, &xQueueSetSendingTask ); + xTaskCreate( prvQueueSetReceivingTask, ( signed char * ) "Check", configMINIMAL_STACK_SIZE, ( void * ) xQueueSetSendingTask, queuesetMEDIUM_PRIORITY, NULL ); /* It is important that the sending task does not attempt to write to a queue before the queue has been created. It is therefore placed into the @@ -145,8 +177,9 @@ xTaskHandle xQueueSetSendingTask; portBASE_TYPE xAreQueueSetTasksStillRunning( void ) { -static unsigned long ulLastCycleCounter; -portBASE_TYPE xReturn; +static unsigned long ulLastCycleCounter, ulLastISRTxValue = 0; +static unsigned long ulLastQueueUsedCounter[ queuesetNUM_QUEUES_IN_SET ] = { 0 }; +portBASE_TYPE xReturn = pdPASS, x; if( ulLastCycleCounter == ulCycleCounter ) { @@ -154,44 +187,180 @@ portBASE_TYPE xReturn; tasks is stalled or an error has been detected. */ xReturn = pdFAIL; } + + ulLastCycleCounter = ulCycleCounter; + + /* Ensure that all the queues in the set have been used. This ensures the + test is working as intended and guards against the rand() in the Tx task + missing some values. */ + for( x = 0; x < queuesetNUM_QUEUES_IN_SET; x++ ) + { + if( ulLastQueueUsedCounter[ x ] == ulQueueUsedCounter[ x ] ) + { + xReturn = pdFAIL; + } + + ulLastQueueUsedCounter[ x ] = ulQueueUsedCounter[ x ]; + } + + /* Check the global status flag. */ + if( xQueueSetTasksStatus != pdPASS ) + { + xReturn = pdFAIL; + } + + /* Check that the ISR is still sending values to the queues too. */ + if( ulISRTxValue == ulLastISRTxValue ) + { + xReturn = pdFAIL; + } else { - xReturn = pdPASS; + ulLastISRTxValue = ulISRTxValue; } return xReturn; } /*-----------------------------------------------------------*/ +void vQueueSetWriteToQueueFromISR( void ) +{ +portBASE_TYPE x = 0; +static unsigned long ulCallCount = 0; + + /* xSetupComplete is set to pdTRUE when the queues have been created and + are available for use. */ + if( xSetupComplete == pdTRUE ) + { + /* It is intended that this function is called from the tick hook + function, so each call is one tick period apart. */ + ulCallCount++; + if( ulCallCount > queuesetISR_TX_PERIOD ) + { + ulCallCount = 0; + + /* Look for a queue that can be written to. */ + for( x = 0; x < queuesetNUM_QUEUES_IN_SET; x++ ) + { + if( xQueues[ x ] != NULL ) + { + /* xQueues[ x ] can be written to. Send the next value. */ + if( xQueueSendFromISR( xQueues[ x ], &ulISRTxValue, NULL ) == pdPASS ) + { + ulISRTxValue++; + + /* If the Tx value has wrapped then set it back to its + initial value. */ + if( ulISRTxValue == 0UL ) + { + ulISRTxValue = queuesetINITIAL_ISR_TX_VALUE; + } + } + + break; + } + } + } + } +} +/*-----------------------------------------------------------*/ + static void prvQueueSetSendingTask( void *pvParameters ) { -unsigned long ulTxValue = 0; +unsigned long ulTaskTxValue = 0; portBASE_TYPE xQueueToWriteTo; +xQueueHandle xQueueInUse; +unsigned portBASE_TYPE uxPriority = queuesetMEDIUM_PRIORITY, ulLoops = 0; /* Remove compiler warning about the unused parameter. */ ( void ) pvParameters; - srand( ( unsigned int ) &ulTxValue ); + srand( ( unsigned int ) &ulTaskTxValue ); for( ;; ) { /* Generate the index for the queue to which a value is to be sent. */ xQueueToWriteTo = rand() % queuesetNUM_QUEUES_IN_SET; - if( xQueueSendToBack( xQueues[ xQueueToWriteTo ], &ulTxValue, portMAX_DELAY ) != pdPASS ) + xQueueInUse = xQueues[ xQueueToWriteTo ]; + + /* Note which index is being written to to ensure all the queues are + used. */ + ( ulQueueUsedCounter[ xQueueToWriteTo ] )++; + + /* Send to the queue to unblock the task that is waiting for data to + arrive on a queue within the queue set to which this queue belongs. */ + if( xQueueSendToBack( xQueueInUse, &ulTaskTxValue, portMAX_DELAY ) != pdPASS ) { /* The send should always pass as an infinite block time was used. */ xQueueSetTasksStatus = pdFAIL; } - ulTxValue++; + /* Attempt to remove the queue from a queue set it does not belong + to (NULL being passed as the queue set in this case). */ + if( xQueueRemoveFromQueueSet( xQueueInUse, NULL ) != pdFAIL ) + { + /* It is not possible to successfully remove a queue from a queue + set it does not belong to. */ + xQueueSetTasksStatus = pdFAIL; + } + + /* Mark the space in the array of queues as being empty before actually + removing the queue from the queue set. This is to prevent the code + that accesses the queue set from an interrupt from attempting to access + a queue that is no longer in the set. */ + xQueues[ xQueueToWriteTo ] = 0; + + /* Attempt to remove the queue from the queue set it does belong to. */ + if( xQueueRemoveFromQueueSet( xQueueInUse, xQueueSet ) != pdPASS ) + { + /* It should be possible to remove the queue from the queue set it + does belong to. */ + xQueueSetTasksStatus = pdFAIL; + } + + /* Add the queue back before cycling back to run again. */ + if( xQueueAddToQueueSet( xQueueInUse, xQueueSet ) != pdPASS ) + { + /* If the queue was successfully removed from the queue set then it + should be possible to add it back in again. */ + xQueueSetTasksStatus = pdFAIL; + } + + /* Now the queue is back in the set it is ok for the interrupt that + writes to the queues to access it again. */ + xQueues[ xQueueToWriteTo ] = xQueueInUse; + + ulTaskTxValue++; + + /* If the Tx value has reached the range used by the ISR then set it + back to 0. */ + if( ulTaskTxValue == queuesetINITIAL_ISR_TX_VALUE ) + { + ulTaskTxValue = 0; + } + + /* Occasionally change the task priority relative to the priority of + the receiving task. */ + ulLoops++; + if( ulLoops >= queuesetPRIORITY_CHANGE_LOOPS ) + { + ulLoops = 0; + uxPriority++; + if( uxPriority > queuesetHIGH_PRIORITY ) + { + uxPriority = queuesetLOW_PRIORITY; + } + + vTaskPrioritySet( NULL, uxPriority ); + } } } /*-----------------------------------------------------------*/ static void prvQueueSetReceivingTask( void *pvParameters ) { -unsigned long ulReceived, ulLastReceived = ~0UL; +unsigned long ulReceived, ulExpectedReceivedFromTask = 0, ulExpectedReceivedFromISR = queuesetINITIAL_ISR_TX_VALUE; xQueueHandle xActivatedQueue; portBASE_TYPE x; xTaskHandle xQueueSetSendingTask; @@ -208,7 +377,8 @@ xTaskHandle xQueueSetSendingTask; for( x = 0; x < queuesetNUM_QUEUES_IN_SET; x++ ) { - /* Create the queue and add it to the set. */ + /* Create the queue and add it to the set. The queue is just holding + unsigned long value. */ xQueues[ x ] = xQueueCreate( queuesetQUEUE_LENGTH, sizeof( unsigned long ) ); configASSERT( xQueues[ x ] ); if( xQueueAddToQueueSet( xQueues[ x ], xQueueSet ) != pdPASS ) @@ -227,16 +397,19 @@ xTaskHandle xQueueSetSendingTask; /* The task that sends to the queues is not running yet, so attempting to read from the queue set should fail, resulting in xActivatedQueue being set to NULL. */ - xActivatedQueue = xQueueReadMultiple( xQueueSet, queuesetSHORT_DELAY ); + xActivatedQueue = xQueueBlockMultiple( xQueueSet, queuesetSHORT_DELAY ); configASSERT( xActivatedQueue == NULL ); /* Resume the task that writes to the queues. */ vTaskResume( xQueueSetSendingTask ); + /* Let the ISR access the queues also. */ + xSetupComplete = pdTRUE; + for( ;; ) { /* Wait for a message to arrive on one of the queues in the set. */ - xActivatedQueue = xQueueReadMultiple( xQueueSet, portMAX_DELAY ); + xActivatedQueue = xQueueBlockMultiple( xQueueSet, portMAX_DELAY ); configASSERT( xActivatedQueue ); if( xActivatedQueue == NULL ) @@ -254,16 +427,51 @@ xTaskHandle xQueueSetSendingTask; xQueueSetTasksStatus = pdFAIL; } - /* It is always expected that the received value will be one - greater than the previously received value. */ - configASSERT( ulReceived == ( ulLastReceived + 1 ) ); - if( ulReceived != ( ulLastReceived + 1 ) ) + /* If the received value is equal to or greater than + queuesetINITIAL_ISR_TX_VALUE then it was sent by an ISR. */ + if( ulReceived >= queuesetINITIAL_ISR_TX_VALUE ) { - xQueueSetTasksStatus = pdFAIL; + /* The value was sent from the ISR. Check it against its + expected value. */ + configASSERT( ulReceived == ulExpectedReceivedFromISR ); + if( ulReceived != ulExpectedReceivedFromISR ) + { + xQueueSetTasksStatus = pdFAIL; + } + else + { + /* It is expected to receive an incrementing value. */ + ulExpectedReceivedFromISR++; + + /* If the expected value has wrapped then set it back to + its initial value. */ + if( ulExpectedReceivedFromISR == 0 ) + { + ulExpectedReceivedFromISR = queuesetINITIAL_ISR_TX_VALUE; + } + } } else { - ulLastReceived = ulReceived; + /* The value was sent from the Tx task. Check it against its + expected value. */ + configASSERT( ulReceived == ulExpectedReceivedFromTask ); + if( ulReceived != ulExpectedReceivedFromTask ) + { + xQueueSetTasksStatus = pdFAIL; + } + else + { + /* It is expected to receive an incrementing value. */ + ulExpectedReceivedFromTask++; + + /* If the expected value has reached the range of values + used by the ISR then set it back to 0. */ + if( ulExpectedReceivedFromTask >= queuesetINITIAL_ISR_TX_VALUE ) + { + ulExpectedReceivedFromTask = 0; + } + } } } diff --git a/FreeRTOS/Demo/Common/include/QueueSet.h b/FreeRTOS/Demo/Common/include/QueueSet.h index 107b7a8bc..eb203ec0e 100644 --- a/FreeRTOS/Demo/Common/include/QueueSet.h +++ b/FreeRTOS/Demo/Common/include/QueueSet.h @@ -69,9 +69,10 @@ #ifndef QUEUE_WAIT_MULTIPLE_H #define QUEUE_WAIT_MULTIPLE_H -void vStartQueueSetTasks( unsigned portBASE_TYPE uxPriority ); +void vStartQueueSetTasks( void ); portBASE_TYPE xAreQueueSetTasksStillRunning( void ); +void vQueueSetWriteToQueueFromISR( void ); -#endif +#endif /* QUEUE_WAIT_MULTIPLE_H */ diff --git a/FreeRTOS/Demo/WIN32-MSVC/WIN32.suo b/FreeRTOS/Demo/WIN32-MSVC/WIN32.suo index e48277fabc56a98f4bb5a1bdece4dce299c8bef3..96f9643bf0cfb5675778629313c6b8e5597ab45a 100644 GIT binary patch delta 1728 zcma)7dr(wW7(eIUyURsk*#{v$c10p%MZsqjnl5DOg0di}p$NMmCGikteXLrp%2-mP zvY%sRCUmo>r0X6_n;ckEOATfKC$$C*OwB1laH!N8>AUN$WB>Kd{PuhO&Uen7`+aAf zH+bhw-hG;*6X6Uul+J-`T%yKI2$_vYMWi7TU<|)bQ-)S4;(mXBf4Qt{G9M3ipn-lr zIzwGTsnV;AwCj{?g|L?63MlJV{vZUC^++0sfT_>MhE$;u$>9$Q(BO$|Vn{Ys@aQ=~ zqpozR?$BtstNLEFV@NHNa2520?be9s6p|#8i`plwR{bFrSEC(@@bT>07BLK+LH>Yp zJ|$!n2Wxd^1z9Ht?~fnN`gE5?8U?lb;W8H`p3ERCND--qjRzc1XVq%%rY2qf^yrtT zE*3Ac30q&8JQ6ym>cX;#g=FCYvXNa(Y|y$d*<-k)2y){tDA2oSFpG?77nPII8#SKY z8$Bdguwar!K4s-8WsYY&p_=A1weA1xZ!siX_{w42Un$nHDKi^Yisr%Bq-4+hx{wf~ zd}xGx)lgqBR!Bt$Itns!=Ae=8&t#y^M9f8GA+izk5b~-8s9!+jAQmGQA#xFNE)R7+ z!iuo@WB1wC!qvjSYcb2igzECEbJOm@#wWtr@THwp+R1rJ<2bEzOWWU#$0HY<9g}Y{ zPkXf{mO`sp$1=*@RNBQ!D>%@;HH-~=`zn=Ian#D_%l*_fDVjyEy&MFlP3tr>CGqRi z>)-h<{i7?-{VpW!jFGRD)o!v;se=2!dyq;iDRX+96r7Ga7FFHBOH~4lZ;l7+_HdTs zYM^ktK7(bvjvHQdrhigO>5Jlt69NQeYL>b`FAt`mtdSyjmNnB=VCI zhj-KHJ|1Y8&z-KrvxFi{$n(tXhb>e=7R#=0aKFgq)bAbR8>W72_$00}q4Tfq=YyE_ zXa|KWYa+nZqyp1xD(0z3r{Fzk@*F$C!3kj;^fg$5X+Bo5JuKXqLB#^}3ImZoZz@mU z#4l(8^^C~4|I-{eN4Q#oWKSjRC^10G$-UCIN^qA%K-H=BuBM8I^Vyt z=5KKfc=OR#Kv@^i@&`k(Ta9meCR^Uk^NK0B#tn`hBS@xbaSeJw2;bj9A~uH`9a*6B jl1@GYGv2;HT|Lnty)joYTP6U#l?Eq!r-1s_^hfo-V%8e* delta 1372 zcmah|drVtp6#u^4+tRX2X(=fc!sr%5n2eV|af%2GHy)cSt`bFX9S@!IkU`l4F{`+j z%Qk^S*n$pB$CgELsr^`jOhy+LGq+(FL>Ch%FvFb8vCV)Y8tS=a#XtR$U%vDD{q8;I zo@@P0V!bP|U*%{Pe8+{*=U|FUQpXTNHX*VRIf%^=C3!D#7h2_rMYr2siTAsRD#T7i zHKGP#LDVAlAjG;wn3RMynfYeETsD-`JCiPD)qEYtB@;Fy`+-+bu}~yI%JUJzel+S4 z;sL5iUe{!(6-qq18i79k5}{oB+cLp%jb7vWfk>I{_!q3eh6 z)L8h%qW=3lGvJJ8cN zkYSSNKImY{8~c^gQyn9}#yj#p6NGF^$Ww?U1auX}dL&??$OtEkBbv-A>Fby%fTrRw zcC^^S3zJblXLseV($g9}EZcNhO4CRI>ELF3R+E6F&3^ zTt1cxw4sh&YNKz06U^x$|jnBe^R|MGb zqpNv1lV9Q0vkY758kig2%KI;eMohfVvg(My!Dw_kym_k)!guPJZd9OPd&>l>zCd>F zV;zp-Cns|@rs5dJj9_euRrr#10fY#o6Vk?aL&u$HXmNFcVX_Q@?#Dpt_!sn?Cv$D; zX?AZshr+$_5{SL)1BI?6W|$o1wJUHry~l)x29e>F%TWI5&5@N(p0Y=GVkGJX-Wv>b zs&R&aEN(hdq8^ud!*b^|+QCq9AE2r>AIvAT&@$Evd2^Luo+|;fJi_tNLZuP-Y&+!2 VbKuHsGJN3DK#E<<*8F~p{tKfc(Zc`$ diff --git a/FreeRTOS/Demo/WIN32-MSVC/main.c b/FreeRTOS/Demo/WIN32-MSVC/main.c index fa0eadbda..d4c972c2f 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/main.c +++ b/FreeRTOS/Demo/WIN32-MSVC/main.c @@ -130,7 +130,6 @@ #define mainINTEGER_TASK_PRIORITY ( tskIDLE_PRIORITY ) #define mainGEN_QUEUE_TASK_PRIORITY ( tskIDLE_PRIORITY ) #define mainFLOP_TASK_PRIORITY ( tskIDLE_PRIORITY ) -#define mainQUEUE_SET_TASK_PRIORITY ( tskIDLE_PRIORITY ) #define mainTIMER_TEST_PERIOD ( 50 ) @@ -167,7 +166,7 @@ int main( void ) vStartTimerDemoTask( mainTIMER_TEST_PERIOD ); vStartCountingSemaphoreTasks(); vStartDynamicPriorityTasks(); - vStartQueueSetTasks( mainQUEUE_SET_TASK_PRIORITY ); + vStartQueueSetTasks(); /* The suicide tasks must be created last as they need to know how many tasks were running prior to their creation. This then allows them to @@ -406,6 +405,10 @@ void vApplicationTickHook( void ) /* Call the periodic timer test, which tests the timer API functions that can be called from an ISR. */ vTimerPeriodicISRTests(); + + /* Write to a queue that is in use as part of the queue set demo to + demonstrate using queue sets from an ISR. */ + vQueueSetWriteToQueueFromISR(); } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Source/include/queue.h b/FreeRTOS/Source/include/queue.h index b9452662c..f2b466c21 100644 --- a/FreeRTOS/Source/include/queue.h +++ b/FreeRTOS/Source/include/queue.h @@ -91,10 +91,17 @@ typedef void * xQueueHandle; /** * Type by which queue sets are referenced. For example, a call to * xQueueSetCreate() returns an xQueueSet variable that can then be used as a - * parameter to xQueueReadMultiple(), xQueueAddToQueueSet(), etc. + * parameter to xQueueBlockMultiple(), xQueueAddToQueueSet(), etc. */ typedef void * xQueueSetHandle; +/** + * Queue sets can contain both queues and semaphores, so the + * xQueueSetMemberHandle is defined as a type to be used where a parameter or + * return value can be either an xQueueHandle or an xSemaphoreHandle. + */ +typedef void * xQueueSetMemberHandle; + /* For internal use only. */ #define queueSEND_TO_BACK ( 0 ) #define queueSEND_TO_FRONT ( 1 ) @@ -1305,7 +1312,7 @@ xQueueHandle xQueueGenericCreate( unsigned portBASE_TYPE uxQueueLength, unsigned * A queue set must be explicitly created using a call to xQueueSetCreate() * before it can be used. Once created, standard FreeRTOS queues and semaphores * can be added to the set using calls to xQueueAddToQueueSet(). - * xQueueReadMultiple() is then used to determine which, if any, of the queues + * xQueueBlockMultiple() is then used to determine which, if any, of the queues * or semaphores contained in the set is in a state where a queue read or * semaphore take operation would be successful. * @@ -1349,10 +1356,8 @@ xQueueSetHandle xQueueSetCreate( unsigned portBASE_TYPE uxEventQueueLength ); * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this * function. * - * @param xQueue The handle of the queue or semaphore being added to the - * queue set. Variables of type xSemaphoreHandle can be safely added to a - * queue set but may require casting to an xQueueHandle type to avoid compiler - * warnings. + * @param xQueueOrSemaphore The handle of the queue or semaphore being added to + * the queue set (cast to an xQueueSetMemberHandle type). * * @param xQueueSet The handle of the queue set to which the queue or semaphore * is being added. @@ -1362,7 +1367,7 @@ xQueueSetHandle xQueueSetCreate( unsigned portBASE_TYPE uxEventQueueLength ); * queue set because it is already a member of a different queue set then pdFAIL * is returned. */ -portBASE_TYPE xQueueAddToQueueSet( xQueueHandle xQueue, xQueueSetHandle xQueueSet ); +portBASE_TYPE xQueueAddToQueueSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ); /* * Removes a queue or semaphore from a queue set. @@ -1370,9 +1375,8 @@ portBASE_TYPE xQueueAddToQueueSet( xQueueHandle xQueue, xQueueSetHandle xQueueSe * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this * function. * - * @param xQueue The handle of the queue or semaphore being removed from the - * queue set. Variables of type xSemaphoreHandle can be safely used but may - * require casting to an xQueueHandle type to avoid compiler warnings. + * @param xQueueOrSemaphore The handle of the queue or semaphore being removed + * from the queue set (cast to an xQueueSetMemberHandle type). * * @param xQueueSet The handle of the queue set in which the queue or semaphore * is included. @@ -1381,10 +1385,10 @@ portBASE_TYPE xQueueAddToQueueSet( xQueueHandle xQueue, xQueueSetHandle xQueueSe * then pdPASS is returned. If the queue was not in the queue set then pdFAIL * is returned. */ -portBASE_TYPE xQueueRemoveFromQueueSet( xQueueSetHandle xQueueSet, xQueueHandle xQueue ); +portBASE_TYPE xQueueRemoveFromQueueSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ); /* - * xQueueReadMultiple() allows a task to block (pend) on a read operation on + * xQueueBlockMultiple() allows a task to block (pend) on a read operation on * all the queues and semaphores in a queue set simultaneously. * * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this @@ -1405,12 +1409,13 @@ portBASE_TYPE xQueueRemoveFromQueueSet( xQueueSetHandle xQueueSet, xQueueHandle * of the queue set to be ready for a successful queue read or semaphore take * operation. * - * @return xQueueReadMultiple() will return the handle of a queue contained - * in the queue set that contains data, or the handle of a semaphore contained + * @return xQueueBlockMultiple() will return the handle of a queue (cast to + * a xQueueSetMemberHandle type) contained in the queue set that contains data, + * or the handle of a semaphore (cast to a xQueueSetMemberHandle type) contained * in the queue set that is available, or NULL if no such queue or semaphore * exists before before the specified block time expires. */ -xQueueHandle xQueueReadMultiple( xQueueSetHandle xQueueSet, portTickType xBlockTimeTicks ); +xQueueSetMemberHandle xQueueBlockMultiple( xQueueSetHandle xQueueSet, portTickType xBlockTimeTicks ); /* Not public API functions. */ void vQueueWaitForMessageRestricted( xQueueHandle pxQueue, portTickType xTicksToWait ); diff --git a/FreeRTOS/Source/queue.c b/FreeRTOS/Source/queue.c index db21c3c07..5d6b5aec2 100644 --- a/FreeRTOS/Source/queue.c +++ b/FreeRTOS/Source/queue.c @@ -1,7 +1,7 @@ /* FreeRTOS V7.3.0 - Copyright (C) 2012 Real Time Engineers Ltd. - FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME. PLEASE VISIT + FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME. PLEASE VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. *************************************************************************** @@ -42,7 +42,7 @@ FreeRTOS WEB site. 1 tab == 4 spaces! - + *************************************************************************** * * * Having a problem? Start by reading the FAQ "My application does * @@ -52,17 +52,17 @@ * * *************************************************************************** - - http://www.FreeRTOS.org - Documentation, training, latest versions, license - and contact details. - + + http://www.FreeRTOS.org - Documentation, training, latest versions, license + and contact details. + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool. - Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell - the code with commercial support, indemnification, and middleware, under + Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell + the code with commercial support, indemnification, and middleware, under the OpenRTOS brand: http://www.OpenRTOS.com. High Integrity Systems also - provide a safety engineered and independently SIL3 certified version under + provide a safety engineered and independently SIL3 certified version under the SafeRTOS brand: http://www.SafeRTOS.com. */ @@ -148,15 +148,22 @@ typedef struct QueueDefinition /*-----------------------------------------------------------*/ /* - * Inside this file xQueueHandle is a pointer to a xQUEUE structure. - * To keep the definition private the API header file defines it as a - * pointer to void. + * Inside this file xQueueHandle and xQueueSetHandle are both pointers to xQUEUE + * structures. To keep the definition private the API header file defines both + * as pointers to void. */ typedef xQUEUE * xQueueHandle; typedef xQUEUE * xQueueSetHandle; +/** + * Queue sets can contain both queues and semaphores, so the + * xQueueSetMemberHandle is defined as a type to be used where a parameter or + * return value can be either an xQueueHandle or an xSemaphoreHandle. + */ +typedef xQUEUE * xQueueSetMemberHandle; + /* - * In order to implement strict data hiding, the queue.h header file defines + * In order to implement strict data hiding, the queue.h header file defines * xQueueHandle and xQueueSetHandle as pointers to void. In this file * xQueueHandle and xQueueSetHandle are defined as pointers to xQUEUE objects. * Therefore the queue.h header file cannot be included in this source file, @@ -185,9 +192,9 @@ unsigned char ucQueueGetQueueType( xQueueHandle pxQueue ) PRIVILEGED_FUNCTION; portBASE_TYPE xQueueGenericReset( xQueueHandle pxQueue, portBASE_TYPE xNewQueue ) PRIVILEGED_FUNCTION; xTaskHandle xQueueGetMutexHolder( xQueueHandle xSemaphore ) PRIVILEGED_FUNCTION; xQueueSetHandle xQueueSetCreate( unsigned portBASE_TYPE uxEventQueueLength ) PRIVILEGED_FUNCTION; -xQueueHandle xQueueReadMultiple( xQueueSetHandle xQueueSet, portTickType xBlockTimeTicks ) PRIVILEGED_FUNCTION; -portBASE_TYPE xQueueAddToQueueSet( xQueueHandle xQueue, xQueueSetHandle xQueueSet ) PRIVILEGED_FUNCTION; -portBASE_TYPE xQueueRemoveFromQueueSet( xQueueSetHandle xQueueSet, xQueueHandle xQueue ) PRIVILEGED_FUNCTION; +xQueueSetMemberHandle xQueueBlockMultiple( xQueueSetHandle xQueueSet, portTickType xBlockTimeTicks ) PRIVILEGED_FUNCTION; +portBASE_TYPE xQueueAddToQueueSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ) PRIVILEGED_FUNCTION; +portBASE_TYPE xQueueRemoveFromQueueSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ) PRIVILEGED_FUNCTION; /* * Co-routine queue functions differ from task queue functions. Co-routines are @@ -266,7 +273,7 @@ static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer ) * Checks to see if a queue is a member of a queue set, and if so, notifies * the queue set that the queue contains data. */ - static portBASE_TYPE prvCheckForMembershipOfQueueSet( xQUEUE *pxQueue, portBASE_TYPE xCopyPosition ); + static portBASE_TYPE prvNotifyQueueSetContainer( xQUEUE *pxQueue, portBASE_TYPE xCopyPosition ); #endif /*-----------------------------------------------------------*/ @@ -361,7 +368,7 @@ xQueueHandle xReturn = NULL; pxNewQueue->uxLength = uxQueueLength; pxNewQueue->uxItemSize = uxItemSize; xQueueGenericReset( pxNewQueue, pdTRUE ); - + #if ( configUSE_TRACE_FACILITY == 1 ) { pxNewQueue->ucQueueType = ucQueueType; @@ -640,12 +647,15 @@ xTimeOutType xTimeOut; { #if ( configUSE_QUEUE_SETS == 1 ) { - if( prvCheckForMembershipOfQueueSet( pxQueue, xCopyPosition ) == pdTRUE ) + if( pxQueue->pxQueueSetContainer != NULL ) { - /* The queue is a member of a queue set, and posting to - the queue set caused a higher priority task to unblock. - A context switch is required. */ - portYIELD_WITHIN_API(); + if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) == pdTRUE ) + { + /* The queue is a member of a queue set, and posting to + the queue set caused a higher priority task to unblock. + A context switch is required. */ + portYIELD_WITHIN_API(); + } } } #endif /* configUSE_QUEUE_SETS */ @@ -985,7 +995,16 @@ unsigned portBASE_TYPE uxSavedInterruptStatus; { if( pxQueue->pxQueueSetContainer != NULL ) { - xQueueGenericSendFromISR( pxQueue->pxQueueSetContainer, &pxQueue, pxHigherPriorityTaskWoken, queueSEND_TO_BACK ); + if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) == pdTRUE ) + { + /* The queue is a member of a queue set, and posting + to the queue set caused a higher priority task to + unblock. A context switch is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + } } } #endif /* configUSE_QUEUE_SETS */ @@ -1068,7 +1087,7 @@ signed char *pcOriginalReadPosition; { traceQUEUE_PEEK( pxQueue ); - /* The data is not being removed, so reset the read + /* The data is not being removed, so reset the read pointer. */ pxQueue->pcReadFrom = pcOriginalReadPosition; @@ -1084,17 +1103,6 @@ signed char *pcOriginalReadPosition; portYIELD_WITHIN_API(); } } - else - { - #if ( configUSE_QUEUE_SETS == 1 ) - { - if( pxQueue->pxQueueSetContainer != NULL ) - { - xQueueGenericSend( pxQueue->pxQueueSetContainer, &pxQueue, 0, queueSEND_TO_BACK ); - } - } - #endif /* configUSE_QUEUE_SETS */ - } } taskEXIT_CRITICAL(); @@ -1379,10 +1387,11 @@ static void prvUnlockQueue( xQueueHandle pxQueue ) { if( pxQueue->pxQueueSetContainer != NULL ) { - portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; - xQueueGenericSendFromISR( pxQueue->pxQueueSetContainer, &pxQueue, &xHigherPriorityTaskWoken, queueSEND_TO_BACK ); - if( xHigherPriorityTaskWoken != pdFALSE ) + if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) == pdTRUE ) { + /* The queue is a member of a queue set, and posting to + the queue set caused a higher priority task to unblock. + A context switch is required. */ vTaskMissedYield(); } } @@ -1784,11 +1793,11 @@ signed portBASE_TYPE xReturn; #if ( configUSE_QUEUE_SETS == 1 ) - portBASE_TYPE xQueueAddToQueueSet( xQueueHandle xQueue, xQueueSetHandle xQueueSet ) + portBASE_TYPE xQueueAddToQueueSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ) { portBASE_TYPE xReturn; - if( xQueue->pxQueueSetContainer != NULL ) + if( xQueueOrSemaphore->pxQueueSetContainer != NULL ) { xReturn = pdFAIL; } @@ -1796,7 +1805,7 @@ signed portBASE_TYPE xReturn; { taskENTER_CRITICAL(); { - xQueue->pxQueueSetContainer = xQueueSet; + xQueueOrSemaphore->pxQueueSetContainer = xQueueSet; } taskEXIT_CRITICAL(); xReturn = pdPASS; @@ -1810,11 +1819,11 @@ signed portBASE_TYPE xReturn; #if ( configUSE_QUEUE_SETS == 1 ) - portBASE_TYPE xQueueRemoveFromQueueSet( xQueueSetHandle xQueueSet, xQueueHandle xQueue ) + portBASE_TYPE xQueueRemoveFromQueueSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ) { portBASE_TYPE xReturn; - if( xQueue->pxQueueSetContainer != xQueueSet ) + if( xQueueOrSemaphore->pxQueueSetContainer != xQueueSet ) { xReturn = pdFAIL; } @@ -1822,7 +1831,7 @@ signed portBASE_TYPE xReturn; { taskENTER_CRITICAL(); { - xQueue->pxQueueSetContainer = NULL; + xQueueOrSemaphore->pxQueueSetContainer = NULL; } taskEXIT_CRITICAL(); xReturn = pdPASS; @@ -1836,10 +1845,10 @@ signed portBASE_TYPE xReturn; #if ( configUSE_QUEUE_SETS == 1 ) - xQueueHandle xQueueReadMultiple( xQueueSetHandle xQueueSet, portTickType xBlockTimeTicks ) + xQueueSetMemberHandle xQueueBlockMultiple( xQueueSetHandle xQueueSet, portTickType xBlockTimeTicks ) { - xQueueHandle xReturn = NULL; - + xQueueSetMemberHandle xReturn = NULL; + xQueueGenericReceive( ( xQueueHandle ) xQueueSet, &xReturn, xBlockTimeTicks, pdFALSE ); return xReturn; } @@ -1849,23 +1858,23 @@ signed portBASE_TYPE xReturn; #if ( configUSE_QUEUE_SETS == 1 ) - static portBASE_TYPE prvCheckForMembershipOfQueueSet( xQUEUE *pxQueue, portBASE_TYPE xCopyPosition ) + static portBASE_TYPE prvNotifyQueueSetContainer( xQUEUE *pxQueue, portBASE_TYPE xCopyPosition ) { xQUEUE *pxQueueSetContainer = pxQueue->pxQueueSetContainer; portBASE_TYPE xReturn = pdFALSE; - if( pxQueueSetContainer != NULL ) + configASSERT( pxQueueSetContainer ); + configASSERT( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength ); + + if( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength ) { - if( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength ) + prvCopyDataToQueue( pxQueueSetContainer, &pxQueue, xCopyPosition ); + if( listLIST_IS_EMPTY( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) == pdFALSE ) { - prvCopyDataToQueue( pxQueueSetContainer, &pxQueue, xCopyPosition ); - if( listLIST_IS_EMPTY( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) == pdFALSE ) + if( xTaskRemoveFromEventList( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) != pdFALSE ) { - if( xTaskRemoveFromEventList( &( pxQueue->pxQueueSetContainer->xTasksWaitingToReceive ) ) != pdFALSE ) - { - /* The task waiting has a higher priority */ - xReturn = pdTRUE; - } + /* The task waiting has a higher priority */ + xReturn = pdTRUE; } } } -- 2.39.5