Add first version of alternative API.

This commit is contained in:
Richard Barry 2007-12-02 18:37:43 +00:00
parent b6d2b739f3
commit 8603259d40
17 changed files with 2308 additions and 120 deletions

View file

@ -112,12 +112,16 @@
#error Missing definition: configUSE_16_BIT_TICKS should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
#endif
#ifndef configUSE_MUTEXES
#define configUSE_MUTEXES 0
#endif
#ifndef configUSE_COUNTING_SEMAPHORES
#define configUSE_COUNTING_SEMAPHORES 0
#endif
#ifndef configUSE_MUTEXES
#define configUSE_MUTEXES 0
#ifndef configUSE_ALTERNATIVE_API
#define configUSE_ALTERNATIVE_API 0
#endif
#if ( configUSE_MUTEXES == 1 )

View file

@ -1159,6 +1159,30 @@ signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void
*/
signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, const void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken );
/*
* xQueueAltGenericSend() is a light weight version of xQueueGenericSend().
* Likewise xQueueAltGenericReceive() is a light weight version of
* xQueueGenericReceive().
*
* The source code that implements the light weight (fast) API is much
* simpler because it executes everything from within a critical section.
* This is the approach taken by many other RTOSes, but FreeRTOS.org has the
* fully featured API as an alternative. The fully featured API has more
* complex code that takes longer to execute, but makes much less use of
* critical sections. Therefore the light weight API sacrifices interrupt
* responsiveness to gain execution speed, whereas the fully featured API
* sacrifices execution speed to ensure better interrupt responsiveness.
*/
signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition );
signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, const void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking );
/*
* The light weight versions of the fully featured macros.
*/
#define xQueueAltSendToFront( xQueue, pvItemToQueue, xTicksToWait ) xQueueAltGenericSend( xQueue, pvItemToQueue, xTicksToWait, queueSEND_TO_FRONT )
#define xQueueAltSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueAltGenericSend( xQueue, pvItemToQueue, xTicksToWait, queueSEND_TO_BACK )
#define xQueueAltReceive( xQueue, pvBuffer, xTicksToWait ) xQueueAltGenericReceive( xQueue, pvBuffer, xTicksToWait, pdFALSE )
#define xQueueAltPeek( xQueue, pvBuffer, xTicksToWait ) xQueueAltGenericReceive( xQueue, pvBuffer, xTicksToWait, pdTRUE )
/*
* The functions defined above are for passing data to and from tasks. The

View file

@ -154,7 +154,8 @@ typedef xQueueHandle xSemaphoreHandle;
* \defgroup xSemaphoreTake xSemaphoreTake
* \ingroup Semaphores
*/
#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueReceive( ( xQueueHandle ) xSemaphore, NULL, xBlockTime )
#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueGenericReceive( ( xQueueHandle ) xSemaphore, NULL, xBlockTime, pdFALSE )
#define xSemaphoreAltTake( xSemaphore, xBlockTime ) xQueueAltGenericReceive( ( xQueueHandle ) xSemaphore, NULL, xBlockTime, pdFALSE )
/**
* semphr. h
@ -213,7 +214,8 @@ typedef xQueueHandle xSemaphoreHandle;
* \defgroup xSemaphoreGive xSemaphoreGive
* \ingroup Semaphores
*/
#define xSemaphoreGive( xSemaphore ) xQueueGenericSend( ( xQueueHandle ) xSemaphore, NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )
#define xSemaphoreGive( xSemaphore ) xQueueGenericSend( ( xQueueHandle ) xSemaphore, NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )
#define xSemaphoreAltGive( xSemaphore ) xQueueAltGenericSend( ( xQueueHandle ) xSemaphore, NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )
/**
* semphr. h

View file

@ -77,6 +77,11 @@ is being used. */
/* Trap routine used by taskYIELD() to manually cause a context switch. */
static void __interrupt __far prvYieldProcessor( void );
/* The timer initialisation functions leave interrupts enabled,
which is not what we want. This ISR is installed temporarily in case
the timer fires before we get a change to disable interrupts again. */
static void __interrupt __far prvDummyISR( void );
/*-----------------------------------------------------------*/
/* See header file for description. */
portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
@ -162,6 +167,15 @@ portBASE_TYPE xPortStartScheduler( void )
}
/*-----------------------------------------------------------*/
static void __interrupt __far prvDummyISR( void )
{
/* The timer initialisation functions leave interrupts enabled,
which is not what we want. This ISR is installed temporarily in case
the timer fires before we get a change to disable interrupts again. */
outport( portEIO_REGISTER, portCLEAR_INTERRUPT );
}
/*-----------------------------------------------------------*/
/* The ISR used depends on whether the preemptive or cooperative scheduler
is being used. */
#if( configUSE_PREEMPTION == 1 )
@ -204,15 +218,23 @@ void vPortEndScheduler( void )
static void prvSetupTimerInterrupt( void )
{
const unsigned portSHORT usTimerACompare = portTIMER_COMPARE, usTimerAMode = portENABLE_TIMER_AND_INTERRUPT;
const unsigned portSHORT usT2_IRQ = 0x13;
/* Configure the timer, the dummy handler is used here as the init
function leaves interrupts enabled. */
t2_init( usTimerAMode, usTimerACompare, prvDummyISR );
/* Disable interrupts again before installing the real handlers. */
portDISABLE_INTERRUPTS();
#if( configUSE_PREEMPTION == 1 )
/* Tick service routine used by the scheduler when preemptive scheduling is
being used. */
t2_init( usTimerAMode, usTimerACompare, prvPreemptiveTick );
setvect( usT2_IRQ, prvPreemptiveTick );
#else
/* Tick service routine used by the scheduler when cooperative scheduling is
being used. */
t2_init( usTimerAMode, usTimerACompare, prvNonPreemptiveTick );
setvect( usT2_IRQ, prvNonPreemptiveTick );
#endif
}

View file

@ -77,7 +77,7 @@ typedef struct QueueDefinition
xList xTasksWaitingToSend; /*< List of tasks that are blocked waiting to post onto this queue. Stored in priority order. */
xList xTasksWaitingToReceive; /*< List of tasks that are blocked waiting to read from this queue. Stored in priority order. */
unsigned portBASE_TYPE uxMessagesWaiting;/*< The number of items currently in the queue. */
volatile unsigned portBASE_TYPE uxMessagesWaiting;/*< The number of items currently in the queue. */
unsigned portBASE_TYPE uxLength; /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */
unsigned portBASE_TYPE uxItemSize; /*< The size of each items that the queue will hold. */
@ -107,6 +107,8 @@ signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, const void * co
signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, const void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken );
xQueueHandle xQueueCreateMutex( void );
xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount );
signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition );
signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, const void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking );
#if configUSE_CO_ROUTINES == 1
signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken );
@ -455,6 +457,202 @@ xTimeOutType xTimeOut;
}
/*-----------------------------------------------------------*/
#if configUSE_ALTERNATIVE_API == 1
signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )
{
signed portBASE_TYPE xReturn;
xTimeOutType xTimeOut;
/* The source code that implements the light weight (fast) API is much
simpler because it executes everything from within a critical section.
This is the approach taken by many other RTOSes, but FreeRTOS.org has the
fully featured API as an alternative. The fully featured API has more
complex code that takes longer to execute, but makes much less use of
critical sections. Therefore the light weight API sacrifices interrupt
responsiveness to gain execution speed, whereas the fully featured API
sacrifices execution speed to ensure better interrupt responsiveness. */
taskENTER_CRITICAL();
{
/* Capture the current time status for future reference. */
vTaskSetTimeOutState( &xTimeOut );
/* If the queue is already full we may have to block. */
do
{
if( pxQueue->uxMessagesWaiting == pxQueue->uxLength )
{
/* The queue is full - do we want to block or just leave without
posting? */
if( xTicksToWait > ( portTickType ) 0 )
{
/* We are going to place ourselves on the xTasksWaitingToSend
event list, and will get woken should the delay expire, or
space become available on the queue. */
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
/* Force a context switch now as we are blocked. We can do
this from within a critical section as the task we are
switching to has its own context. When we return here (i.e.
we unblock) we will leave the critical section as normal. */
taskYIELD();
}
}
if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
{
/* There is room in the queue, copy the data into the queue. */
prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
xReturn = pdPASS;
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
/* The task waiting has a higher priority. */
taskYIELD();
}
}
}
else
{
xReturn = errQUEUE_FULL;
if( xTicksToWait > 0 )
{
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
{
/* Another task must have accessed the queue between
this task unblocking and actually executing. */
xReturn = queueERRONEOUS_UNBLOCK;
}
}
else
{
}
}
}
while( xReturn == queueERRONEOUS_UNBLOCK );
}
taskEXIT_CRITICAL();
return xReturn;
}
#endif /* configUSE_ALTERNATIVE_API */
/*-----------------------------------------------------------*/
#if configUSE_ALTERNATIVE_API == 1
signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, const void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )
{
signed portBASE_TYPE xReturn = pdTRUE;
xTimeOutType xTimeOut;
signed portCHAR *pcOriginalReadPosition;
/* The source code that implements the light weight (fast) API is much
simpler because it executes everything from within a critical section.
This is the approach taken by many other RTOSes, but FreeRTOS.org has the
fully featured API as an alternative. The fully featured API has more
complex code that takes longer to execute, but makes much less use of
critical sections. Therefore the light weight API sacrifices interrupt
responsiveness to gain execution speed, whereas the fully featured API
sacrifices execution speed to ensure better interrupt responsiveness. */
taskENTER_CRITICAL();
{
/* Capture the current time status for future reference. */
vTaskSetTimeOutState( &xTimeOut );
do
{
/* If there are no messages in the queue we may have to block. */
if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 )
{
/* There are no messages in the queue, do we want to block or just
leave with nothing? */
if( xTicksToWait > ( portTickType ) 0 )
{
#if ( configUSE_MUTEXES == 1 )
{
if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
{
vTaskPriorityInherit( ( void * const ) pxQueue->pxMutexHolder );
}
}
#endif
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
taskYIELD();
}
}
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 )
{
/* 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 ) ) )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{
/* The task waiting has a higher priority. */
taskYIELD();
}
}
}
else
{
/* We are not removing the data, so reset our read
pointer. */
pxQueue->pcReadFrom = pcOriginalReadPosition;
}
xReturn = pdPASS;
}
else
{
xReturn = errQUEUE_EMPTY;
if( xTicksToWait > 0 )
{
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
{
xReturn = queueERRONEOUS_UNBLOCK;
}
}
}
} while( xReturn == queueERRONEOUS_UNBLOCK );
}
taskEXIT_CRITICAL();
return xReturn;
}
#endif /* configUSE_ALTERNATIVE_API */
/*-----------------------------------------------------------*/
signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken, portBASE_TYPE xCopyPosition )
{
/* Similar to xQueueGenericSend, except we don't block if there is no room