Optimisations - being checked in for backup - not yet complete.

This commit is contained in:
Richard Barry 2009-03-11 10:53:45 +00:00
parent dae13395ed
commit aaeb4790de

View file

@ -442,26 +442,54 @@ size_t xQueueSizeInBytes;
signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )
{ {
signed portBASE_TYPE xReturn = pdTRUE; signed portBASE_TYPE xEntryTimeSet = pdFALSE;
xTimeOutType xTimeOut; xTimeOutType xTimeOut;
do for( ;; )
{ {
/* If xTicksToWait is zero then we are not going to block even taskENTER_CRITICAL();
if there is no room in the queue to post. */
if( xTicksToWait > ( portTickType ) 0 )
{ {
/* Is there room on the queue now? To be running we must be
the highest priority task wanting to access the queue. */
if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
{
traceQUEUE_SEND( pxQueue );
prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
/* If there was a task waiting for data to arrive on the
queue then unblock it now. */
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )
{
/* The unblocked task has a priority higher than
our own so yield immediately. */
taskYIELD();
}
}
taskEXIT_CRITICAL();
return pdPASS;
}
else
{
if( xTicksToWait == ( portTickType ) 0 )
{
taskEXIT_CRITICAL();
return errQUEUE_FULL;
}
else if( xEntryTimeSet == pdFALSE )
{
vTaskSetTimeOutState( &xTimeOut );
xEntryTimeSet = pdTRUE;
}
}
}
taskEXIT_CRITICAL();
vTaskSuspendAll(); vTaskSuspendAll();
prvLockQueue( pxQueue ); 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( prvIsQueueFull( pxQueue ) ) if( prvIsQueueFull( pxQueue ) )
{ {
/* Need to call xTaskCheckForTimeout again as time could /* Need to call xTaskCheckForTimeout again as time could
@ -493,21 +521,27 @@ xTimeOutType xTimeOut;
{ {
prvUnlockQueue( pxQueue ); prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll(); ( void ) xTaskResumeAll();
return errQUEUE_FULL;
} }
} }
else else
{ {
/* The queue was not full so we can just unlock the
scheduler and queue again before carrying on. */
prvUnlockQueue( pxQueue ); prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll(); ( void ) xTaskResumeAll();
} }
} }
}
/*-----------------------------------------------------------*/
/* Higher priority tasks and interrupts can execute during #if configUSE_ALTERNATIVE_API == 1
this time and could possible refill the queue - even if we
unblocked because space became available. */
signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )
{
signed portBASE_TYPE xEntryTimeSet = pdFALSE;
xTimeOutType xTimeOut;
for( ;; )
{
taskENTER_CRITICAL(); taskENTER_CRITICAL();
{ {
/* Is there room on the queue now? To be running we must be /* Is there room on the queue now? To be running we must be
@ -516,7 +550,6 @@ xTimeOutType xTimeOut;
{ {
traceQUEUE_SEND( pxQueue ); traceQUEUE_SEND( pxQueue );
prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
xReturn = pdPASS;
/* If there was a task waiting for data to arrive on the /* If there was a task waiting for data to arrive on the
queue then unblock it now. */ queue then unblock it now. */
@ -529,74 +562,28 @@ xTimeOutType xTimeOut;
taskYIELD(); taskYIELD();
} }
} }
taskEXIT_CRITICAL();
return pdPASS;
} }
else else
{ {
/* Setting xReturn to errQUEUE_FULL will force its timeout if( xTicksToWait == ( portTickType ) 0 )
to be re-evaluated. This is necessary in case interrupts {
and higher priority tasks accessed the queue between this taskEXIT_CRITICAL();
task being unblocked and subsequently attempting to write return errQUEUE_FULL;
to the queue. */ }
xReturn = errQUEUE_FULL; else if( xEntryTimeSet == pdFALSE )
{
vTaskSetTimeOutState( &xTimeOut );
xEntryTimeSet = pdTRUE;
}
} }
} }
taskEXIT_CRITICAL(); taskEXIT_CRITICAL();
if( xReturn == errQUEUE_FULL ) taskENTER_CRITICAL();
{ {
if( xTicksToWait > ( portTickType ) 0 )
{
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
{
xReturn = queueERRONEOUS_UNBLOCK;
}
else
{
traceQUEUE_SEND_FAILED( pxQueue );
}
}
else
{
traceQUEUE_SEND_FAILED( pxQueue );
}
}
}
while( xReturn == queueERRONEOUS_UNBLOCK );
return xReturn;
}
/*-----------------------------------------------------------*/
#if configUSE_ALTERNATIVE_API == 1
signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )
{
signed portBASE_TYPE xReturn = pdPASS;
xTimeOutType xTimeOut;
/* 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 xTicksToWait is zero then we are not going to block even
if there is no room in the queue to post. */
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( prvIsQueueFull( pxQueue ) ) if( prvIsQueueFull( pxQueue ) )
{ {
/* Need to call xTaskCheckForTimeout again as time could /* Need to call xTaskCheckForTimeout again as time could
@ -606,76 +593,17 @@ xTimeOutType xTimeOut;
{ {
traceBLOCKING_ON_QUEUE_SEND( pxQueue ); traceBLOCKING_ON_QUEUE_SEND( pxQueue );
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait ); vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
/* This will exit the critical section, then re-enter when
the task next runs. */
taskYIELD(); taskYIELD();
} }
}
}
portEXIT_CRITICAL();
}
/* Higher priority tasks and interrupts can execute during
this time and could possible refill the queue - even if we
unblocked because space became available. */
taskENTER_CRITICAL();
{
/* Is there room on the queue now? To be running we must be
the highest priority task wanting to access the queue. */
if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
{
traceQUEUE_SEND( pxQueue );
prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
xReturn = pdPASS;
/* If there was a task waiting for data to arrive on the
queue then unblock it now. */
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )
{
/* The unblocked task has a priority higher than
our own so yield immediately. */
taskYIELD();
}
}
}
else else
{ {
/* Setting xReturn to errQUEUE_FULL will force its timeout taskEXIT_CRITICAL();
to be re-evaluated. This is necessary in case interrupts return errQUEUE_FULL;
and higher priority tasks accessed the queue between this }
task being unblocked and subsequently attempting to write
to the queue. */
xReturn = errQUEUE_FULL;
} }
} }
taskEXIT_CRITICAL(); taskEXIT_CRITICAL();
if( xReturn == errQUEUE_FULL )
{
if( xTicksToWait > ( portTickType ) 0 )
{
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
{
xReturn = queueERRONEOUS_UNBLOCK;
} }
else
{
traceQUEUE_SEND_FAILED( pxQueue );
}
}
else
{
traceQUEUE_SEND_FAILED( pxQueue );
}
}
}
while( xReturn == queueERRONEOUS_UNBLOCK );
return xReturn;
} }
#endif /* configUSE_ALTERNATIVE_API */ #endif /* configUSE_ALTERNATIVE_API */
@ -685,58 +613,12 @@ xTimeOutType xTimeOut;
signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ) signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )
{ {
signed portBASE_TYPE xReturn = pdTRUE; signed portBASE_TYPE xEntryTimeSet = pdFALSE;
xTimeOutType xTimeOut; xTimeOutType xTimeOut;
signed portCHAR *pcOriginalReadPosition; signed portCHAR *pcOriginalReadPosition;
/* The source code that implements the alternative (Alt) API is for( ;; )
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(); taskENTER_CRITICAL();
{ {
if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
@ -788,43 +670,66 @@ xTimeOutType xTimeOut;
the pending ready list as the scheduler is still suspended. */ the pending ready list as the scheduler is still suspended. */
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{ {
/* The task waiting has a higher priority that this task. */ /* The task waiting has a higher priority than this task. */
taskYIELD(); taskYIELD();
} }
} }
} }
xReturn = pdPASS; taskEXIT_CRITICAL();
return pdPASS;
} }
else else
{ {
xReturn = errQUEUE_EMPTY; if( xTicksToWait == ( portTickType ) 0 )
{
taskEXIT_CRITICAL();
return errQUEUE_EMPTY;
}
else if( xEntryTimeSet == pdFALSE )
{
vTaskSetTimeOutState( &xTimeOut );
xEntryTimeSet = pdTRUE;
}
} }
} }
taskEXIT_CRITICAL(); taskEXIT_CRITICAL();
if( xReturn == errQUEUE_EMPTY ) taskENTER_CRITICAL();
{ {
if( xTicksToWait > ( portTickType ) 0 ) 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 ) if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
{ {
xReturn = queueERRONEOUS_UNBLOCK; traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
}
else
{
traceQUEUE_RECEIVE_FAILED( pxQueue );
}
}
else
{
traceQUEUE_RECEIVE_FAILED( pxQueue );
}
}
} while( xReturn == queueERRONEOUS_UNBLOCK );
return xReturn; #if ( configUSE_MUTEXES == 1 )
{
if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
{
portENTER_CRITICAL();
vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );
portEXIT_CRITICAL();
}
}
#endif
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
taskYIELD();
}
else
{
taskEXIT_CRITICAL();
return errQUEUE_EMPTY;
}
}
}
taskEXIT_CRITICAL();
}
} }
@ -886,66 +791,12 @@ unsigned portBASE_TYPE uxSavedInterruptStatus;
signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ) signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )
{ {
signed portBASE_TYPE xReturn = pdTRUE; signed portBASE_TYPE xEntryTimeSet = pdFALSE;
xTimeOutType xTimeOut; xTimeOutType xTimeOut;
signed portCHAR *pcOriginalReadPosition; signed portCHAR *pcOriginalReadPosition;
do for( ;; )
{ {
/* 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();
}
}
taskENTER_CRITICAL(); taskENTER_CRITICAL();
{ {
if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
@ -1004,37 +855,68 @@ signed portCHAR *pcOriginalReadPosition;
} }
xReturn = pdPASS; taskEXIT_CRITICAL();
return pdPASS;
} }
else else
{ {
xReturn = errQUEUE_EMPTY; if( xTicksToWait == ( portTickType ) 0 )
{
taskEXIT_CRITICAL();
return errQUEUE_EMPTY;
}
else if( xEntryTimeSet == pdFALSE )
{
vTaskSetTimeOutState( &xTimeOut );
xEntryTimeSet = pdTRUE;
}
} }
} }
taskEXIT_CRITICAL(); taskEXIT_CRITICAL();
if( xReturn == errQUEUE_EMPTY ) vTaskSuspendAll();
{ prvLockQueue( pxQueue );
if( xTicksToWait > ( portTickType ) 0 )
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 ) if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
{ {
xReturn = queueERRONEOUS_UNBLOCK; traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
}
else #if ( configUSE_MUTEXES == 1 )
{ {
traceQUEUE_RECEIVE_FAILED( pxQueue ); 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 else
{ {
traceQUEUE_RECEIVE_FAILED( pxQueue ); prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll();
return errQUEUE_EMPTY;
}
}
else
{
prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll();
} }
} }
} while( xReturn == queueERRONEOUS_UNBLOCK );
return xReturn;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/