signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait ) { signed portBASE_TYPE xReturn; /* If the queue is already empty we may have to block. A critical section is required to prevent an interrupt adding something to the queue between the check to see if the queue is empty and blocking on the queue. */ portDISABLE_INTERRUPTS(); { if( prvIsQueueEmpty( pxQueue ) ) { /* There are no messages in the queue, do we want to block or just leave with nothing? */ if( xTicksToWait > ( portTickType ) 0 ) { /* As this is a co-routine we cannot block directly, but return indicating that we need to block. */ vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToReceive ) ); portENABLE_INTERRUPTS(); return errQUEUE_BLOCKED; } else { portENABLE_INTERRUPTS(); return errQUEUE_FULL; } } } portENABLE_INTERRUPTS(); portNOP(); portDISABLE_INTERRUPTS(); { if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) { /* Data is available from the queue. */ pxQueue->pcReadFrom += pxQueue->uxItemSize; if( pxQueue->pcReadFrom >= pxQueue->pcTail ) { pxQueue->pcReadFrom = pxQueue->pcHead; } --( pxQueue->uxMessagesWaiting ); memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); xReturn = pdPASS; /* Were any co-routines waiting for space to become available? */ if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) ) { /* In this instance the co-routine could be placed directly into the ready list as we are within a critical section. Instead the same pending ready list mechansim is used as if the event were caused from within an interrupt. */ if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) { xReturn = errQUEUE_YIELD; } } } else { xReturn = pdFAIL; } } portENABLE_INTERRUPTS(); return xReturn; }
signed portBASE_TYPE xQueueReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait ) { signed portBASE_TYPE xReturn; /* This function is very similar to xQueueSend(). See comments within xQueueSend() for a more detailed explanation. Make sure other tasks do not access the queue. */ vTaskSuspendAll(); /* Make sure interrupts do not access the queue. */ prvLockQueue( pxQueue ); /* If there are no messages in the queue we may have to block. */ if( prvIsQueueEmpty( pxQueue ) ) { /* There are no messages in the queue, do we want to block or just leave with nothing? */ if( xTicksToWait > ( portTickType ) 0 ) { vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); taskENTER_CRITICAL(); { prvUnlockQueue( pxQueue ); if( !xTaskResumeAll() ) { taskYIELD(); } vTaskSuspendAll(); prvLockQueue( pxQueue ); } taskEXIT_CRITICAL(); } } taskENTER_CRITICAL(); { if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) { pxQueue->pcReadFrom += pxQueue->uxItemSize; if( pxQueue->pcReadFrom >= pxQueue->pcTail ) { pxQueue->pcReadFrom = pxQueue->pcHead; } --( pxQueue->uxMessagesWaiting ); memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); /* Increment the lock count so prvUnlockQueue knows to check for tasks waiting for space to become available on the queue. */ ++( pxQueue->xRxLock ); xReturn = pdPASS; } else { xReturn = pdFAIL; } } taskEXIT_CRITICAL(); /* We no longer require exclusive access to the queue. */ if( prvUnlockQueue( pxQueue ) ) { if( !xTaskResumeAll() ) { taskYIELD(); } } else { xTaskResumeAll(); } return xReturn; }
signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ) { signed portBASE_TYPE xReturn = pdTRUE; xTimeOutType xTimeOut; signed portCHAR *pcOriginalReadPosition; /* The source code that implements the alternative (Alt) API is simpler because it makes more use of critical sections. This is the approach taken by many other RTOSes, but FreeRTOS.org has the preferred fully featured API too. The fully featured API has more complex code that takes longer to execute, but makes less use of critical sections. */ do { /* If there are no messages in the queue we may have to block. */ if( xTicksToWait > ( portTickType ) 0 ) { portENTER_CRITICAL(); { if( xReturn == pdPASS ) { /* This is the first time through - capture the time inside the critical section to ensure we attempt to block at least once. */ vTaskSetTimeOutState( &xTimeOut ); } if( prvIsQueueEmpty( pxQueue ) ) { /* Need to call xTaskCheckForTimeout again as time could have passed since it was last called if this is not the first time around this loop. */ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) { traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); #if ( configUSE_MUTEXES == 1 ) { if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) { vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder ); } } #endif vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); taskYIELD(); } } } portEXIT_CRITICAL(); } taskENTER_CRITICAL(); { if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) { /* Remember our read position in case we are just peeking. */ pcOriginalReadPosition = pxQueue->pcReadFrom; prvCopyDataFromQueue( pxQueue, pvBuffer ); if( xJustPeeking == pdFALSE ) { traceQUEUE_RECEIVE( pxQueue ); /* We are actually removing data. */ --( pxQueue->uxMessagesWaiting ); #if ( configUSE_MUTEXES == 1 ) { if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) { /* Record the information required to implement priority inheritance should it become necessary. */ pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle(); } } #endif if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) { if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE ) { taskYIELD(); } } } else { traceQUEUE_PEEK( pxQueue ); /* We are not removing the data, so reset our read pointer. */ pxQueue->pcReadFrom = pcOriginalReadPosition; /* The data is being left in the queue, so see if there are any other tasks waiting for the data. */ if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) ) { /* Tasks that are removed from the event list will get added to the pending ready list as the scheduler is still suspended. */ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) { /* The task waiting has a higher priority that this task. */ taskYIELD(); } } } xReturn = pdPASS; } else { xReturn = errQUEUE_EMPTY; } } taskEXIT_CRITICAL(); if( xReturn == errQUEUE_EMPTY ) { if( xTicksToWait > ( portTickType ) 0 ) { if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) { xReturn = queueERRONEOUS_UNBLOCK; } else { traceQUEUE_RECEIVE_FAILED( pxQueue ); } } else { traceQUEUE_RECEIVE_FAILED( pxQueue ); } } } while( xReturn == queueERRONEOUS_UNBLOCK ); return xReturn; }
signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ) { signed portBASE_TYPE xReturn = pdTRUE; xTimeOutType xTimeOut; signed portCHAR *pcOriginalReadPosition; do { /* If there are no messages in the queue we may have to block. */ if( xTicksToWait > ( portTickType ) 0 ) { vTaskSuspendAll(); prvLockQueue( pxQueue ); if( xReturn == pdTRUE ) { /* This is the first time through - we need to capture the time while the scheduler is locked to ensure we attempt to block at least once. */ vTaskSetTimeOutState( &xTimeOut ); } if( prvIsQueueEmpty( pxQueue ) ) { /* Need to call xTaskCheckForTimeout again as time could have passed since it was last called if this is not the first time around this loop. */ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) { traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); #if ( configUSE_MUTEXES == 1 ) { if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) { portENTER_CRITICAL(); vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder ); portEXIT_CRITICAL(); } } #endif vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); prvUnlockQueue( pxQueue ); if( !xTaskResumeAll() ) { taskYIELD(); } } else { prvUnlockQueue( pxQueue ); ( void ) xTaskResumeAll(); } } else { prvUnlockQueue( pxQueue ); ( void ) xTaskResumeAll(); } } /* The two tasks are blocked on the queue, the low priority task is polling/running. */ /* An interrupt occurs here - which unblocks the HP tasks, but they do not run. */ taskENTER_CRITICAL(); { /* Because the interrupt occurred the LP task manages to grab the data as the other two tasks are not yet running. */ if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) { /* Remember our read position in case we are just peeking. */ pcOriginalReadPosition = pxQueue->pcReadFrom; prvCopyDataFromQueue( pxQueue, pvBuffer ); if( xJustPeeking == pdFALSE ) { traceQUEUE_RECEIVE( pxQueue ); /* We are actually removing data. */ --( pxQueue->uxMessagesWaiting ); #if ( configUSE_MUTEXES == 1 ) { if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) { /* Record the information required to implement priority inheritance should it become necessary. */ pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle(); } } #endif if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) { if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE ) { taskYIELD(); } } } else { traceQUEUE_PEEK( pxQueue ); /* We are not removing the data, so reset our read pointer. */ pxQueue->pcReadFrom = pcOriginalReadPosition; /* The data is being left in the queue, so see if there are any other tasks waiting for the data. */ if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) ) { /* Tasks that are removed from the event list will get added to the pending ready list as the scheduler is still suspended. */ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) { /* The task waiting has a higher priority than this task. */ taskYIELD(); } } } xReturn = pdPASS; } else { xReturn = errQUEUE_EMPTY; } } taskEXIT_CRITICAL(); if( xReturn == errQUEUE_EMPTY ) { if( xTicksToWait > ( portTickType ) 0 ) { if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) { xReturn = queueERRONEOUS_UNBLOCK; } else { traceQUEUE_RECEIVE_FAILED( pxQueue ); } } else { traceQUEUE_RECEIVE_FAILED( pxQueue ); } } } while( xReturn == queueERRONEOUS_UNBLOCK ); return xReturn; }
signed portBASE_TYPE xQueueReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait ) { signed portBASE_TYPE xReturn = pdTRUE; xTimeOutType xTimeOut; /* This function is very similar to xQueueSend(). See comments within xQueueSend() for a more detailed explanation. Make sure other tasks do not access the queue. */ vTaskSuspendAll(); /* Capture the current time status for future reference. */ vTaskSetTimeOutState( &xTimeOut ); /* Make sure interrupts do not access the queue. */ prvLockQueue( pxQueue ); do { /* If there are no messages in the queue we may have to block. */ if( prvIsQueueEmpty( pxQueue ) ) { /* There are no messages in the queue, do we want to block or just leave with nothing? */ if( xTicksToWait > ( portTickType ) 0 ) { vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); taskENTER_CRITICAL(); { prvUnlockQueue( pxQueue ); if( !xTaskResumeAll() ) { taskYIELD(); } if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 ) { /* We unblocked but the queue is empty. We probably timed out. */ xReturn = errQUEUE_EMPTY; } vTaskSuspendAll(); prvLockQueue( pxQueue ); } taskEXIT_CRITICAL(); } } if( xReturn != errQUEUE_EMPTY ) { taskENTER_CRITICAL(); { if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) { pxQueue->pcReadFrom += pxQueue->uxItemSize; if( pxQueue->pcReadFrom >= pxQueue->pcTail ) { pxQueue->pcReadFrom = pxQueue->pcHead; } --( pxQueue->uxMessagesWaiting ); if(pvBuffer != (void*)0UL) { memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); } /* Increment the lock count so prvUnlockQueue knows to check for tasks waiting for space to become available on the queue. */ ++( pxQueue->xRxLock ); xReturn = pdPASS; } else { xReturn = errQUEUE_EMPTY; } } taskEXIT_CRITICAL(); } if( xReturn == errQUEUE_EMPTY ) { if( xTicksToWait > 0 ) { if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) { xReturn = queueERRONEOUS_UNBLOCK; } } } } while( xReturn == queueERRONEOUS_UNBLOCK ); /* We no longer require exclusive access to the queue. */ prvUnlockQueue( pxQueue ); xTaskResumeAll(); return xReturn; }