mirror of
https://github.com/FreeRTOS/FreeRTOS.git
synced 2025-06-20 23:27:39 +08:00
Add macro to break from potential infinite loops (#349)
* Break from potentially infinite loops in connection sharing demo * Use QoS1 subscription for resilience against network disconnect Co-authored-by: Oscar Michael Abrina <abrinao@amazon.com>
This commit is contained in:
@ -250,6 +250,18 @@
|
|||||||
*/
|
*/
|
||||||
#define mqttexampleUNSUBSCRIBE_COMPLETE_BIT ( 1U << 1 )
|
#define mqttexampleUNSUBSCRIBE_COMPLETE_BIT ( 1U << 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The maximum number of loop iterations to wait before declaring failure.
|
||||||
|
*
|
||||||
|
* Each `while` loop waiting for a task notification will wait for a total
|
||||||
|
* number of ticks equal to `mqttexampleDEMO_TICKS_TO_WAIT` * this number of
|
||||||
|
* iterations before the loop exits.
|
||||||
|
*
|
||||||
|
* @note This value should not be too small, as the reason for a long loop
|
||||||
|
* may be a loss of network connection.
|
||||||
|
*/
|
||||||
|
#define mqttexampleMAX_WAIT_ITERATIONS ( 20 )
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Topic filter used by the subscriber task.
|
* @brief Topic filter used by the subscriber task.
|
||||||
*/
|
*/
|
||||||
@ -823,7 +835,7 @@ static MQTTStatus_t prvMQTTConnect( MQTTContext_t * pxMQTTContext,
|
|||||||
{
|
{
|
||||||
pxResendSubscriptions[ j ].pTopicFilter = pxSubscriptions[ i ].pcSubscriptionFilter;
|
pxResendSubscriptions[ j ].pTopicFilter = pxSubscriptions[ i ].pcSubscriptionFilter;
|
||||||
pxResendSubscriptions[ j ].topicFilterLength = pxSubscriptions[ i ].usFilterLength;
|
pxResendSubscriptions[ j ].topicFilterLength = pxSubscriptions[ i ].usFilterLength;
|
||||||
pxResendSubscriptions[ j ].qos = MQTTQoS0;
|
pxResendSubscriptions[ j ].qos = MQTTQoS1;
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1546,6 +1558,7 @@ void prvPublishTask( void * pvParameters )
|
|||||||
char * payloadBuffers[ mqttexamplePUBLISH_COUNT ];
|
char * payloadBuffers[ mqttexamplePUBLISH_COUNT ];
|
||||||
char * topicBuffers[ mqttexamplePUBLISH_COUNT ];
|
char * topicBuffers[ mqttexamplePUBLISH_COUNT ];
|
||||||
CommandContext_t * pxContexts[ mqttexamplePUBLISH_COUNT ] = { 0 };
|
CommandContext_t * pxContexts[ mqttexamplePUBLISH_COUNT ] = { 0 };
|
||||||
|
uint32_t ulWaitCounter = 0;
|
||||||
|
|
||||||
/* We use QoS 1 so that the operation won't be counted as complete until we
|
/* We use QoS 1 so that the operation won't be counted as complete until we
|
||||||
* receive the publish acknowledgment. */
|
* receive the publish acknowledgment. */
|
||||||
@ -1571,13 +1584,23 @@ void prvPublishTask( void * pvParameters )
|
|||||||
xCommandAdded = prvAddCommandToQueue( &xCommand );
|
xCommandAdded = prvAddCommandToQueue( &xCommand );
|
||||||
/* Ensure command was added to queue. */
|
/* Ensure command was added to queue. */
|
||||||
configASSERT( xCommandAdded == pdTRUE );
|
configASSERT( xCommandAdded == pdTRUE );
|
||||||
|
ulWaitCounter = 0;
|
||||||
|
|
||||||
while( ( ulNotification & ( 1U << i ) ) != ( 1U << i ) )
|
while( ( ulNotification & ( 1U << i ) ) != ( 1U << i ) )
|
||||||
{
|
{
|
||||||
LogInfo( ( "Waiting for publish %d to complete.", i + 1 ) );
|
LogInfo( ( "Waiting for publish %d to complete.", i + 1 ) );
|
||||||
xTaskNotifyWait( 0, ( 1U << i ), &ulNotification, mqttexampleDEMO_TICKS_TO_WAIT );
|
xTaskNotifyWait( 0, ( 1U << i ), &ulNotification, mqttexampleDEMO_TICKS_TO_WAIT );
|
||||||
|
|
||||||
|
if( ++ulWaitCounter > mqttexampleMAX_WAIT_ITERATIONS )
|
||||||
|
{
|
||||||
|
LogError( ( "Synchronous publish loop iteration %d"
|
||||||
|
" exceeded maximum wait time.", ( i + 1 ) ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configASSERT( ( ulNotification & ( 1U << i ) ) == ( 1U << i ) );
|
||||||
|
|
||||||
LogInfo( ( "Publish operation complete. Sleeping for %d ms.\n", mqttexamplePUBLISH_DELAY_SYNC_MS ) );
|
LogInfo( ( "Publish operation complete. Sleeping for %d ms.\n", mqttexamplePUBLISH_DELAY_SYNC_MS ) );
|
||||||
vTaskDelay( pdMS_TO_TICKS( mqttexamplePUBLISH_DELAY_SYNC_MS ) );
|
vTaskDelay( pdMS_TO_TICKS( mqttexamplePUBLISH_DELAY_SYNC_MS ) );
|
||||||
}
|
}
|
||||||
@ -1629,12 +1652,23 @@ void prvPublishTask( void * pvParameters )
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ulWaitCounter = 0;
|
||||||
|
|
||||||
while( ( ulNotification & ( 1U << i ) ) != ( 1U << i ) )
|
while( ( ulNotification & ( 1U << i ) ) != ( 1U << i ) )
|
||||||
{
|
{
|
||||||
LogInfo( ( "Waiting to free publish context %d.", i + 1 ) );
|
LogInfo( ( "Waiting to free publish context %d.", i + 1 ) );
|
||||||
xTaskNotifyWait( 0, ( 1U << i ), &ulNotification, mqttexampleDEMO_TICKS_TO_WAIT );
|
xTaskNotifyWait( 0, ( 1U << i ), &ulNotification, mqttexampleDEMO_TICKS_TO_WAIT );
|
||||||
|
|
||||||
|
if( ++ulWaitCounter > mqttexampleMAX_WAIT_ITERATIONS )
|
||||||
|
{
|
||||||
|
LogError( ( "Loop free iteration %d exceeded maximum"
|
||||||
|
" wait time.", ( i + 1 ) ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configASSERT( ( ulNotification & ( 1U < i ) ) == ( 1U << i ) );
|
||||||
|
|
||||||
vPortFree( pxContexts[ i ] );
|
vPortFree( pxContexts[ i ] );
|
||||||
vPortFree( topicBuffers[ i ] );
|
vPortFree( topicBuffers[ i ] );
|
||||||
vPortFree( payloadBuffers[ i ] );
|
vPortFree( payloadBuffers[ i ] );
|
||||||
@ -1666,11 +1700,12 @@ void prvSubscribeTask( void * pvParameters )
|
|||||||
uint32_t ulNotification = 0;
|
uint32_t ulNotification = 0;
|
||||||
CommandContext_t xContext;
|
CommandContext_t xContext;
|
||||||
PublishElement_t xReceivedPublish;
|
PublishElement_t xReceivedPublish;
|
||||||
|
uint32_t ulWaitCounter = 0;
|
||||||
|
|
||||||
/* The QoS does not affect when subscribe operations are marked completed
|
/* The QoS does not affect when subscribe operations are marked completed
|
||||||
* as it does for publishes. Since the QoS does not impact this demo, we
|
* as it does for publishes. However, we still use QoS 1 here so that the
|
||||||
* will use QoS 0, as it is the simplest. */
|
* broker will resend publishes if there is a network disconnect. */
|
||||||
xSubscribeInfo.qos = MQTTQoS0;
|
xSubscribeInfo.qos = MQTTQoS1;
|
||||||
xSubscribeInfo.pTopicFilter = mqttexampleSUBSCRIBE_TOPIC_FILTER;
|
xSubscribeInfo.pTopicFilter = mqttexampleSUBSCRIBE_TOPIC_FILTER;
|
||||||
xSubscribeInfo.topicFilterLength = ( uint16_t ) strlen( xSubscribeInfo.pTopicFilter );
|
xSubscribeInfo.topicFilterLength = ( uint16_t ) strlen( xSubscribeInfo.pTopicFilter );
|
||||||
LogInfo( ( "Topic filter: %.*s", xSubscribeInfo.topicFilterLength, xSubscribeInfo.pTopicFilter ) );
|
LogInfo( ( "Topic filter: %.*s", xSubscribeInfo.topicFilterLength, xSubscribeInfo.pTopicFilter ) );
|
||||||
@ -1689,13 +1724,27 @@ void prvSubscribeTask( void * pvParameters )
|
|||||||
/* Ensure command was added to queue. */
|
/* Ensure command was added to queue. */
|
||||||
configASSERT( xCommandAdded == pdTRUE );
|
configASSERT( xCommandAdded == pdTRUE );
|
||||||
|
|
||||||
|
/* This demo relies on the server processing our subscription before any publishes.
|
||||||
|
* Since this demo uses multiple tasks, we do not retry failed subscriptions, as the
|
||||||
|
* server has likely already processed our first publish, and so this demo will not
|
||||||
|
* complete successfully. */
|
||||||
while( ( ulNotification & mqttexampleSUBSCRIBE_COMPLETE_BIT ) != mqttexampleSUBSCRIBE_COMPLETE_BIT )
|
while( ( ulNotification & mqttexampleSUBSCRIBE_COMPLETE_BIT ) != mqttexampleSUBSCRIBE_COMPLETE_BIT )
|
||||||
{
|
{
|
||||||
LogInfo( ( "Waiting for subscribe operation to complete." ) );
|
LogInfo( ( "Waiting for subscribe operation to complete." ) );
|
||||||
xTaskNotifyWait( 0, mqttexampleSUBSCRIBE_COMPLETE_BIT, &ulNotification, mqttexampleDEMO_TICKS_TO_WAIT );
|
xTaskNotifyWait( 0, mqttexampleSUBSCRIBE_COMPLETE_BIT, &ulNotification, mqttexampleDEMO_TICKS_TO_WAIT );
|
||||||
|
|
||||||
|
if( ++ulWaitCounter > mqttexampleMAX_WAIT_ITERATIONS )
|
||||||
|
{
|
||||||
|
LogError( ( "Subscribe Loop exceeded maximum wait time." ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configASSERT( ( ulNotification & mqttexampleSUBSCRIBE_COMPLETE_BIT ) == mqttexampleSUBSCRIBE_COMPLETE_BIT );
|
||||||
|
configASSERT( xContext.xReturnStatus == MQTTSuccess );
|
||||||
|
|
||||||
LogInfo( ( "Operation wait complete.\n" ) );
|
LogInfo( ( "Operation wait complete.\n" ) );
|
||||||
|
ulWaitCounter = 0;
|
||||||
|
|
||||||
while( 1 )
|
while( 1 )
|
||||||
{
|
{
|
||||||
@ -1712,6 +1761,8 @@ void prvSubscribeTask( void * pvParameters )
|
|||||||
LogInfo( ( "Received publish on topic %.*s", pxReceivedPublish->topicNameLength, pxReceivedPublish->pTopicName ) );
|
LogInfo( ( "Received publish on topic %.*s", pxReceivedPublish->topicNameLength, pxReceivedPublish->pTopicName ) );
|
||||||
LogInfo( ( "Message payload: %.*s\n", ( int ) pxReceivedPublish->payloadLength, ( const char * ) pxReceivedPublish->pPayload ) );
|
LogInfo( ( "Message payload: %.*s\n", ( int ) pxReceivedPublish->payloadLength, ( const char * ) pxReceivedPublish->pPayload ) );
|
||||||
usNumReceived++;
|
usNumReceived++;
|
||||||
|
/* Reset the wait counter every time a publish is received. */
|
||||||
|
ulWaitCounter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Break if all publishes have been received. */
|
/* Break if all publishes have been received. */
|
||||||
@ -1720,6 +1771,17 @@ void prvSubscribeTask( void * pvParameters )
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Break if we have been stuck in this loop for too long. The total wait
|
||||||
|
* here will be ( (loop delay + queue check delay) * `mqttexampleMAX_WAIT_ITERATIONS` ).
|
||||||
|
* For example, with a 1000 ms queue delay, a 400 ms loop delay, and a
|
||||||
|
* maximum iteration of 20, this will wait 28 seconds after receiving
|
||||||
|
* the last publish. */
|
||||||
|
if( ++ulWaitCounter > mqttexampleMAX_WAIT_ITERATIONS )
|
||||||
|
{
|
||||||
|
LogError( ( "Publish receive loop exceeded maximum wait time." ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
LogInfo( ( "No messages queued, received %u publishes, sleeping for %d ms\n",
|
LogInfo( ( "No messages queued, received %u publishes, sleeping for %d ms\n",
|
||||||
usNumReceived,
|
usNumReceived,
|
||||||
mqttexampleSUBSCRIBE_TASK_DELAY_MS ) );
|
mqttexampleSUBSCRIBE_TASK_DELAY_MS ) );
|
||||||
@ -1739,13 +1801,21 @@ void prvSubscribeTask( void * pvParameters )
|
|||||||
/* Ensure command was added to queue. */
|
/* Ensure command was added to queue. */
|
||||||
configASSERT( xCommandAdded == pdTRUE );
|
configASSERT( xCommandAdded == pdTRUE );
|
||||||
LogInfo( ( "Starting wait on operation\n" ) );
|
LogInfo( ( "Starting wait on operation\n" ) );
|
||||||
|
ulWaitCounter = 0;
|
||||||
|
|
||||||
while( ( ulNotification & mqttexampleUNSUBSCRIBE_COMPLETE_BIT ) != mqttexampleUNSUBSCRIBE_COMPLETE_BIT )
|
while( ( ulNotification & mqttexampleUNSUBSCRIBE_COMPLETE_BIT ) != mqttexampleUNSUBSCRIBE_COMPLETE_BIT )
|
||||||
{
|
{
|
||||||
LogInfo( ( "Waiting for unsubscribe operation to complete." ) );
|
LogInfo( ( "Waiting for unsubscribe operation to complete." ) );
|
||||||
xTaskNotifyWait( 0, mqttexampleUNSUBSCRIBE_COMPLETE_BIT, &ulNotification, mqttexampleDEMO_TICKS_TO_WAIT );
|
xTaskNotifyWait( 0, mqttexampleUNSUBSCRIBE_COMPLETE_BIT, &ulNotification, mqttexampleDEMO_TICKS_TO_WAIT );
|
||||||
|
|
||||||
|
if( ++ulWaitCounter > mqttexampleMAX_WAIT_ITERATIONS )
|
||||||
|
{
|
||||||
|
LogError( ( "Unsubscribe loop exceeded maximum wait time." ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configASSERT( ( ulNotification & mqttexampleUNSUBSCRIBE_COMPLETE_BIT ) == mqttexampleUNSUBSCRIBE_COMPLETE_BIT );
|
||||||
LogInfo( ( "Operation wait complete.\n" ) );
|
LogInfo( ( "Operation wait complete.\n" ) );
|
||||||
|
|
||||||
/* Create command to stop command loop. */
|
/* Create command to stop command loop. */
|
||||||
@ -1773,6 +1843,7 @@ static void prvMQTTDemoTask( void * pvParameters )
|
|||||||
uint32_t ulNotification = 0;
|
uint32_t ulNotification = 0;
|
||||||
Command_t xCommand;
|
Command_t xCommand;
|
||||||
MQTTStatus_t xMQTTStatus;
|
MQTTStatus_t xMQTTStatus;
|
||||||
|
uint32_t ulWaitCounter = 0;
|
||||||
|
|
||||||
( void ) pvParameters;
|
( void ) pvParameters;
|
||||||
|
|
||||||
@ -1838,6 +1909,7 @@ static void prvMQTTDemoTask( void * pvParameters )
|
|||||||
|
|
||||||
LogInfo( ( "Running command loop" ) );
|
LogInfo( ( "Running command loop" ) );
|
||||||
prvCommandLoop();
|
prvCommandLoop();
|
||||||
|
ulWaitCounter = 0;
|
||||||
|
|
||||||
/* Delete created tasks and queues.
|
/* Delete created tasks and queues.
|
||||||
* Wait for subscriber task to exit before cleaning up. */
|
* Wait for subscriber task to exit before cleaning up. */
|
||||||
@ -1845,15 +1917,28 @@ static void prvMQTTDemoTask( void * pvParameters )
|
|||||||
{
|
{
|
||||||
LogInfo( ( "Waiting for subscribe task to exit." ) );
|
LogInfo( ( "Waiting for subscribe task to exit." ) );
|
||||||
xTaskNotifyWait( 0, mqttexampleSUBSCRIBE_TASK_COMPLETE_BIT, &ulNotification, mqttexampleDEMO_TICKS_TO_WAIT );
|
xTaskNotifyWait( 0, mqttexampleSUBSCRIBE_TASK_COMPLETE_BIT, &ulNotification, mqttexampleDEMO_TICKS_TO_WAIT );
|
||||||
|
|
||||||
|
if( ++ulWaitCounter > mqttexampleMAX_WAIT_ITERATIONS )
|
||||||
|
{
|
||||||
|
LogError( ( "Subscribe task exceeded maximum wait time." ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configASSERT( ( ulNotification & mqttexampleSUBSCRIBE_TASK_COMPLETE_BIT ) == mqttexampleSUBSCRIBE_TASK_COMPLETE_BIT );
|
configASSERT( ( ulNotification & mqttexampleSUBSCRIBE_TASK_COMPLETE_BIT ) == mqttexampleSUBSCRIBE_TASK_COMPLETE_BIT );
|
||||||
|
ulWaitCounter = 0;
|
||||||
|
|
||||||
/* Wait for publishing task to exit before cleaning up. */
|
/* Wait for publishing task to exit before cleaning up. */
|
||||||
while( ( ulNotification & mqttexamplePUBLISHER_TASK_COMPLETE_BIT ) != mqttexamplePUBLISHER_TASK_COMPLETE_BIT )
|
while( ( ulNotification & mqttexamplePUBLISHER_TASK_COMPLETE_BIT ) != mqttexamplePUBLISHER_TASK_COMPLETE_BIT )
|
||||||
{
|
{
|
||||||
LogInfo( ( "Waiting for publish task to exit." ) );
|
LogInfo( ( "Waiting for publish task to exit." ) );
|
||||||
xTaskNotifyWait( 0, mqttexamplePUBLISHER_TASK_COMPLETE_BIT, &ulNotification, mqttexampleDEMO_TICKS_TO_WAIT );
|
xTaskNotifyWait( 0, mqttexamplePUBLISHER_TASK_COMPLETE_BIT, &ulNotification, mqttexampleDEMO_TICKS_TO_WAIT );
|
||||||
|
|
||||||
|
if( ++ulWaitCounter > mqttexampleMAX_WAIT_ITERATIONS )
|
||||||
|
{
|
||||||
|
LogError( ( "Publish task exceeded maximum wait time." ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configASSERT( ( ulNotification & mqttexamplePUBLISHER_TASK_COMPLETE_BIT ) == mqttexamplePUBLISHER_TASK_COMPLETE_BIT );
|
configASSERT( ( ulNotification & mqttexamplePUBLISHER_TASK_COMPLETE_BIT ) == mqttexamplePUBLISHER_TASK_COMPLETE_BIT );
|
||||||
|
Reference in New Issue
Block a user