?? queue.c
字號:
/*
FreeRTOS.org V4.1.1 - Copyright (C) 2003-2006 Richard Barry.
This file is part of the FreeRTOS.org distribution.
FreeRTOS.org is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
FreeRTOS.org is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with FreeRTOS.org; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes FreeRTOS.org, without being obliged to provide
the source code for any proprietary components. See the licensing section
of http://www.FreeRTOS.org for full details of how and when the exception
can be applied.
***************************************************************************
See http://www.FreeRTOS.org for documentation, latest information, license
and contact details. Please ensure to read the configuration and relevant
port sections of the online documentation.
***************************************************************************
*/
/*
Changes from V1.01
+ More use of 8bit data types.
+ Function name prefixes changed where the data type returned has changed.
Changed from V2.0.0
+ Added the queue locking mechanism and make more use of the scheduler
suspension feature to minimise the time interrupts have to be disabled
when accessing a queue.
Changed from V2.2.0
+ Explicit use of 'signed' qualifier on portCHAR types added.
Changes from V3.0.0
+ API changes as described on the FreeRTOS.org WEB site.
Changes from V3.2.3
+ Added the queue functions that can be used from co-routines.
Changes from V4.0.5
+ Added a loop within xQueueSend() and xQueueReceive() to prevent the
functions exiting when a block time remains and the function has
not completed.
*/
#include <stdlib.h>
#include <string.h>
#include "FreeRTOS.h"
#include "task.h"
#include "croutine.h"
/*-----------------------------------------------------------
* PUBLIC LIST API documented in list.h
*----------------------------------------------------------*/
/* Constants used with the cRxLock and cTxLock structure members. */
#define queueUNLOCKED ( ( signed portBASE_TYPE ) -1 )
#define queueERRONEOUS_UNBLOCK ( -1 )
/*
* Definition of the queue used by the scheduler.
* Items are queued by copy, not reference.
*/
typedef struct QueueDefinition
{
signed portCHAR *pcHead; /*< Points to the beginning of the queue storage area. */
signed portCHAR *pcTail; /*< Points to the byte at the end of the queue storage area. Once more byte is allocated than necessary to store the queue items, this is used as a marker. */
signed portCHAR *pcWriteTo; /*< Points to the free next place in the storage area. */
signed portCHAR *pcReadFrom; /*< Points to the last place that a queued item was read from. */
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. */
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. */
signed portBASE_TYPE xRxLock; /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */
signed portBASE_TYPE xTxLock; /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */
} xQUEUE;
/*-----------------------------------------------------------*/
/*
* 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.
*/
typedef xQUEUE * xQueueHandle;
/*
* Prototypes for public functions are included here so we don't have to
* include the API header file (as it defines xQueueHandle differently). These
* functions are documented in the API header file.
*/
xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize );
signed portBASE_TYPE xQueueSend( xQueueHandle xQueue, const void * pvItemToQueue, portTickType xTicksToWait );
unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle pxQueue );
void vQueueDelete( xQueueHandle xQueue );
signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken );
signed portBASE_TYPE xQueueReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait );
signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );
#if configUSE_CO_ROUTINES == 1
signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken );
signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );
signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait );
signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait );
#endif
/*
* Unlocks a queue locked by a call to prvLockQueue. Locking a queue does not
* prevent an ISR from adding or removing items to the queue, but does prevent
* an ISR from removing tasks from the queue event lists. If an ISR finds a
* queue is locked it will instead increment the appropriate queue lock count
* to indicate that a task may require unblocking. When the queue in unlocked
* these lock counts are inspected, and the appropriate action taken.
*/
static void prvUnlockQueue( xQueueHandle pxQueue );
/*
* Uses a critical section to determine if there is any data in a queue.
*
* @return pdTRUE if the queue contains no items, otherwise pdFALSE.
*/
static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue );
/*
* Uses a critical section to determine if there is any space in a queue.
*
* @return pdTRUE if there is no space, otherwise pdFALSE;
*/
static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue );
/*
* Macro that copies an item into the queue. This is done by copying the item
* byte for byte, not by reference. Updates the queue state to ensure it's
* integrity after the copy.
*/
#define prvCopyQueueData( pxQueue, pvItemToQueue ) \
{ \
memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize ); \
++( pxQueue->uxMessagesWaiting ); \
pxQueue->pcWriteTo += pxQueue->uxItemSize; \
if( pxQueue->pcWriteTo >= pxQueue->pcTail ) \
{ \
pxQueue->pcWriteTo = pxQueue->pcHead; \
} \
}
/*-----------------------------------------------------------*/
/*
* Macro to mark a queue as locked. Locking a queue prevents an ISR from
* accessing the queue event lists.
*/
#define prvLockQueue( pxQueue ) \
{ \
taskENTER_CRITICAL(); \
++( pxQueue->xRxLock ); \
++( pxQueue->xTxLock ); \
taskEXIT_CRITICAL(); \
}
/*-----------------------------------------------------------*/
/*-----------------------------------------------------------
* PUBLIC QUEUE MANAGEMENT API documented in queue.h
*----------------------------------------------------------*/
xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize )
{
xQUEUE *pxNewQueue;
size_t xQueueSizeInBytes;
/* Allocate the new queue structure. */
if( uxQueueLength > ( unsigned portBASE_TYPE ) 0 )
{
pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );
if( pxNewQueue != NULL )
{
/* Create the list of pointers to queue items. The queue is one byte
longer than asked for to make wrap checking easier/faster. */
xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ) + ( size_t ) 1;
pxNewQueue->pcHead = ( signed portCHAR * ) pvPortMalloc( xQueueSizeInBytes );
if( pxNewQueue->pcHead != NULL )
{
/* Initialise the queue members as described above where the
queue type is defined. */
pxNewQueue->pcTail = pxNewQueue->pcHead + ( uxQueueLength * uxItemSize );
pxNewQueue->uxMessagesWaiting = 0;
pxNewQueue->pcWriteTo = pxNewQueue->pcHead;
pxNewQueue->pcReadFrom = pxNewQueue->pcHead + ( ( uxQueueLength - 1 ) * uxItemSize );
pxNewQueue->uxLength = uxQueueLength;
pxNewQueue->uxItemSize = uxItemSize;
pxNewQueue->xRxLock = queueUNLOCKED;
pxNewQueue->xTxLock = queueUNLOCKED;
/* Likewise ensure the event queues start with the correct state. */
vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );
vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );
return pxNewQueue;
}
else
{
vPortFree( pxNewQueue );
}
}
}
/* Will only reach here if we could not allocate enough memory or no memory
was required. */
return NULL;
}
/*-----------------------------------------------------------*/
signed portBASE_TYPE xQueueSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )
{
signed portBASE_TYPE xReturn;
xTimeOutType xTimeOut;
/* Make sure other tasks do not access the queue. */
vTaskSuspendAll();
/* Capture the current time status for future reference. */
vTaskSetTimeOutState( &xTimeOut );
/* It is important that this is the only thread/ISR that modifies the
ready or delayed lists until xTaskResumeAll() is called. Places where
the ready/delayed lists are modified include:
+ vTaskDelay() - Nothing can call vTaskDelay as the scheduler is
suspended, vTaskDelay() cannot be called from an ISR.
+ vTaskPrioritySet() - Has a critical section around the access.
+ vTaskSwitchContext() - This will not get executed while the scheduler
is suspended.
+ prvCheckDelayedTasks() - This will not get executed while the
scheduler is suspended.
+ xTaskCreate() - Has a critical section around the access.
+ vTaskResume() - Has a critical section around the access.
+ xTaskResumeAll() - Has a critical section around the access.
+ xTaskRemoveFromEventList - Checks to see if the scheduler is
suspended. If so then the TCB being removed from the event is
removed from the event and added to the xPendingReadyList.
*/
/* Make sure interrupts do not access the queue event list. */
prvLockQueue( pxQueue );
/* It is important that interrupts to not access the event list of the
queue being modified here. Places where the event list is modified
include:
+ xQueueSendFromISR(). This checks the lock on the queue to see if
it has access. If the queue is locked then the Tx lock count is
incremented to signify that a task waiting for data can be made ready
once the queue lock is removed. If the queue is not locked then
a task can be moved from the event list, but will not be removed
from the delayed list or placed in the ready list until the scheduler
is unlocked.
+ xQueueReceiveFromISR(). As per xQueueSendFromISR().
*/
/* If the queue is already full we may have to block. */
do
{
if( prvIsQueueFull( pxQueue ) )
{
/* 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
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -