2 FreeRTOS.org V4.7.2 - Copyright (C) 2003-2008 Richard Barry.
\r
4 This file is part of the FreeRTOS.org distribution.
\r
6 FreeRTOS.org is free software; you can redistribute it and/or modify
\r
7 it under the terms of the GNU General Public License as published by
\r
8 the Free Software Foundation; either version 2 of the License, or
\r
9 (at your option) any later version.
\r
11 FreeRTOS.org is distributed in the hope that it will be useful,
\r
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 GNU General Public License for more details.
\r
16 You should have received a copy of the GNU General Public License
\r
17 along with FreeRTOS.org; if not, write to the Free Software
\r
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\r
20 A special exception to the GPL can be applied should you wish to distribute
\r
21 a combined work that includes FreeRTOS.org, without being obliged to provide
\r
22 the source code for any proprietary components. See the licensing section
\r
23 of http://www.FreeRTOS.org for full details of how and when the exception
\r
26 ***************************************************************************
\r
28 Please ensure to read the configuration and relevant port sections of the
\r
29 online documentation.
\r
31 +++ http://www.FreeRTOS.org +++
\r
32 Documentation, latest information, license and contact details.
\r
34 +++ http://www.SafeRTOS.com +++
\r
35 A version that is certified for use in safety critical systems.
\r
37 +++ http://www.OpenRTOS.com +++
\r
38 Commercial support, development, porting, licensing and training services.
\r
40 ***************************************************************************
\r
45 #include "FreeRTOS.h"
\r
47 #include "croutine.h"
\r
49 /*-----------------------------------------------------------
\r
50 * PUBLIC LIST API documented in list.h
\r
51 *----------------------------------------------------------*/
\r
53 /* Constants used with the cRxLock and cTxLock structure members. */
\r
54 #define queueUNLOCKED ( ( signed portBASE_TYPE ) -1 )
\r
55 #define queueERRONEOUS_UNBLOCK ( -1 )
\r
57 /* For internal use only. */
\r
58 #define queueSEND_TO_BACK ( 0 )
\r
59 #define queueSEND_TO_FRONT ( 1 )
\r
61 /* Effectively make a union out of the xQUEUE structure. */
\r
62 #define pxMutexHolder pcTail
\r
63 #define uxQueueType pcHead
\r
64 #define uxRecursiveCallCount pcReadFrom
\r
65 #define queueQUEUE_IS_MUTEX NULL
\r
67 /* Semaphores do not actually store or copy data, so have an items size of
\r
69 #define queueSEMAPHORE_QUEUE_ITEM_LENGTH ( 0 )
\r
70 #define queueDONT_BLOCK ( ( portTickType ) 0 )
\r
71 #define queueMUTEX_GIVE_BLOCK_TIME ( ( portTickType ) 0 )
\r
73 * Definition of the queue used by the scheduler.
\r
74 * Items are queued by copy, not reference.
\r
76 typedef struct QueueDefinition
\r
78 signed portCHAR *pcHead; /*< Points to the beginning of the queue storage area. */
\r
79 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. */
\r
81 signed portCHAR *pcWriteTo; /*< Points to the free next place in the storage area. */
\r
82 signed portCHAR *pcReadFrom; /*< Points to the last place that a queued item was read from. */
\r
84 xList xTasksWaitingToSend; /*< List of tasks that are blocked waiting to post onto this queue. Stored in priority order. */
\r
85 xList xTasksWaitingToReceive; /*< List of tasks that are blocked waiting to read from this queue. Stored in priority order. */
\r
87 volatile unsigned portBASE_TYPE uxMessagesWaiting;/*< The number of items currently in the queue. */
\r
88 unsigned portBASE_TYPE uxLength; /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */
\r
89 unsigned portBASE_TYPE uxItemSize; /*< The size of each items that the queue will hold. */
\r
91 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. */
\r
92 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. */
\r
94 /*-----------------------------------------------------------*/
\r
97 * Inside this file xQueueHandle is a pointer to a xQUEUE structure.
\r
98 * To keep the definition private the API header file defines it as a
\r
101 typedef xQUEUE * xQueueHandle;
\r
104 * Prototypes for public functions are included here so we don't have to
\r
105 * include the API header file (as it defines xQueueHandle differently). These
\r
106 * functions are documented in the API header file.
\r
108 xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize );
\r
109 signed portBASE_TYPE xQueueGenericSend( xQueueHandle xQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition );
\r
110 unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle pxQueue );
\r
111 void vQueueDelete( xQueueHandle xQueue );
\r
112 signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken, portBASE_TYPE xCopyPosition );
\r
113 signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, const void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking );
\r
114 signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, const void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken );
\r
115 xQueueHandle xQueueCreateMutex( void );
\r
116 xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount );
\r
117 portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle xMutex, portTickType xBlockTime );
\r
118 portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle xMutex );
\r
119 signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition );
\r
120 signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, const void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking );
\r
121 portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue );
\r
122 portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue );
\r
123 unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue );
\r
126 #if configUSE_CO_ROUTINES == 1
\r
127 signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken );
\r
128 signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );
\r
129 signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait );
\r
130 signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait );
\r
134 * Unlocks a queue locked by a call to prvLockQueue. Locking a queue does not
\r
135 * prevent an ISR from adding or removing items to the queue, but does prevent
\r
136 * an ISR from removing tasks from the queue event lists. If an ISR finds a
\r
137 * queue is locked it will instead increment the appropriate queue lock count
\r
138 * to indicate that a task may require unblocking. When the queue in unlocked
\r
139 * these lock counts are inspected, and the appropriate action taken.
\r
141 static void prvUnlockQueue( xQueueHandle pxQueue );
\r
144 * Uses a critical section to determine if there is any data in a queue.
\r
146 * @return pdTRUE if the queue contains no items, otherwise pdFALSE.
\r
148 static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue );
\r
151 * Uses a critical section to determine if there is any space in a queue.
\r
153 * @return pdTRUE if there is no space, otherwise pdFALSE;
\r
155 static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue );
\r
158 * Copies an item into the queue, either at the front of the queue or the
\r
159 * back of the queue.
\r
161 static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition );
\r
164 * Copies an item out of a queue.
\r
166 static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer );
\r
167 /*-----------------------------------------------------------*/
\r
170 * Macro to mark a queue as locked. Locking a queue prevents an ISR from
\r
171 * accessing the queue event lists.
\r
173 #define prvLockQueue( pxQueue ) \
\r
175 taskENTER_CRITICAL(); \
\r
176 ++( pxQueue->xRxLock ); \
\r
177 ++( pxQueue->xTxLock ); \
\r
178 taskEXIT_CRITICAL(); \
\r
180 /*-----------------------------------------------------------*/
\r
183 /*-----------------------------------------------------------
\r
184 * PUBLIC QUEUE MANAGEMENT API documented in queue.h
\r
185 *----------------------------------------------------------*/
\r
187 xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize )
\r
189 xQUEUE *pxNewQueue;
\r
190 size_t xQueueSizeInBytes;
\r
192 /* Allocate the new queue structure. */
\r
193 if( uxQueueLength > ( unsigned portBASE_TYPE ) 0 )
\r
195 pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );
\r
196 if( pxNewQueue != NULL )
\r
198 /* Create the list of pointers to queue items. The queue is one byte
\r
199 longer than asked for to make wrap checking easier/faster. */
\r
200 xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ) + ( size_t ) 1;
\r
202 pxNewQueue->pcHead = ( signed portCHAR * ) pvPortMalloc( xQueueSizeInBytes );
\r
203 if( pxNewQueue->pcHead != NULL )
\r
205 /* Initialise the queue members as described above where the
\r
206 queue type is defined. */
\r
207 pxNewQueue->pcTail = pxNewQueue->pcHead + ( uxQueueLength * uxItemSize );
\r
208 pxNewQueue->uxMessagesWaiting = 0;
\r
209 pxNewQueue->pcWriteTo = pxNewQueue->pcHead;
\r
210 pxNewQueue->pcReadFrom = pxNewQueue->pcHead + ( ( uxQueueLength - 1 ) * uxItemSize );
\r
211 pxNewQueue->uxLength = uxQueueLength;
\r
212 pxNewQueue->uxItemSize = uxItemSize;
\r
213 pxNewQueue->xRxLock = queueUNLOCKED;
\r
214 pxNewQueue->xTxLock = queueUNLOCKED;
\r
216 /* Likewise ensure the event queues start with the correct state. */
\r
217 vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );
\r
218 vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );
\r
220 traceQUEUE_CREATE( pxNewQueue );
\r
226 traceQUEUE_CREATE_FAILED();
\r
227 vPortFree( pxNewQueue );
\r
232 /* Will only reach here if we could not allocate enough memory or no memory
\r
236 /*-----------------------------------------------------------*/
\r
238 #if ( configUSE_MUTEXES == 1 )
\r
240 xQueueHandle xQueueCreateMutex( void )
\r
242 xQUEUE *pxNewQueue;
\r
244 /* Allocate the new queue structure. */
\r
245 pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );
\r
246 if( pxNewQueue != NULL )
\r
248 /* Information required for priority inheritance. */
\r
249 pxNewQueue->pxMutexHolder = NULL;
\r
250 pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX;
\r
252 /* Queues used as a mutex no data is actually copied into or out
\r
254 pxNewQueue->pcWriteTo = NULL;
\r
255 pxNewQueue->pcReadFrom = NULL;
\r
257 /* Each mutex has a length of 1 (like a binary semaphore) and
\r
258 an item size of 0 as nothing is actually copied into or out
\r
260 pxNewQueue->uxMessagesWaiting = 0;
\r
261 pxNewQueue->uxLength = 1;
\r
262 pxNewQueue->uxItemSize = 0;
\r
263 pxNewQueue->xRxLock = queueUNLOCKED;
\r
264 pxNewQueue->xTxLock = queueUNLOCKED;
\r
266 /* Ensure the event queues start with the correct state. */
\r
267 vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );
\r
268 vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );
\r
270 /* Start with the semaphore in the expected state. */
\r
271 xQueueGenericSend( pxNewQueue, NULL, 0, queueSEND_TO_BACK );
\r
273 traceCREATE_MUTEX( pxNewQueue );
\r
277 traceCREATE_MUTEX_FAILED();
\r
283 #endif /* configUSE_MUTEXES */
\r
284 /*-----------------------------------------------------------*/
\r
286 #if configUSE_RECURSIVE_MUTEXES == 1
\r
288 portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle pxMutex )
\r
290 portBASE_TYPE xReturn;
\r
292 /* If this is the task that holds the mutex then pxMutexHolder will not
\r
293 change outside of this task. If this task does not hold the mutex then
\r
294 pxMutexHolder can never coincidentally equal the tasks handle, and as
\r
295 this is the only condition we are interested in it does not matter if
\r
296 pxMutexHolder is accessed simultaneously by another task. Therefore no
\r
297 mutual exclusion is required to test the pxMutexHolder variable. */
\r
298 if( pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle() )
\r
300 /* uxRecursiveCallCount cannot be zero if pxMutexHolder is equal to
\r
301 the task handle, therefore no underflow check is required. Also,
\r
302 uxRecursiveCallCount is only modified by the mutex holder, and as
\r
303 there can only be one, no mutual exclusion is required to modify the
\r
304 uxRecursiveCallCount member. */
\r
305 ( pxMutex->uxRecursiveCallCount )--;
\r
307 /* Have we unwound the call count? */
\r
308 if( pxMutex->uxRecursiveCallCount == 0 )
\r
310 /* Return the mutex. This will automatically unblock any other
\r
311 task that might be waiting to access the mutex. */
\r
312 xQueueGenericSend( pxMutex, NULL, queueMUTEX_GIVE_BLOCK_TIME, queueSEND_TO_BACK );
\r
317 traceGIVE_MUTEX_RECURSIVE( pxMutex );
\r
321 /* We cannot give the mutex because we are not the holder. */
\r
324 traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex );
\r
330 #endif /* configUSE_RECURSIVE_MUTEXES */
\r
331 /*-----------------------------------------------------------*/
\r
333 #if configUSE_RECURSIVE_MUTEXES == 1
\r
335 portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle pxMutex, portTickType xBlockTime )
\r
337 portBASE_TYPE xReturn;
\r
339 /* Comments regarding mutual exclusion as per those within
\r
340 xQueueGiveMutexRecursive(). */
\r
342 if( pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle() )
\r
344 ( pxMutex->uxRecursiveCallCount )++;
\r
349 xReturn = xQueueGenericReceive( pxMutex, NULL, xBlockTime, pdFALSE );
\r
351 /* pdPASS will only be returned if we successfully obtained the mutex,
\r
352 we may have blocked to reach here. */
\r
353 if( xReturn == pdPASS )
\r
355 ( pxMutex->uxRecursiveCallCount )++;
\r
359 traceTAKE_MUTEX_RECURSIVE( pxMutex );
\r
364 #endif /* configUSE_RECURSIVE_MUTEXES */
\r
365 /*-----------------------------------------------------------*/
\r
367 #if configUSE_COUNTING_SEMAPHORES == 1
\r
369 xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount )
\r
371 xQueueHandle pxHandle;
\r
373 pxHandle = xQueueCreate( ( unsigned portBASE_TYPE ) uxCountValue, queueSEMAPHORE_QUEUE_ITEM_LENGTH );
\r
375 if( pxHandle != NULL )
\r
377 pxHandle->uxMessagesWaiting = uxInitialCount;
\r
379 traceCREATE_COUNTING_SEMAPHORE();
\r
383 traceCREATE_COUNTING_SEMAPHORE_FAILED();
\r
389 #endif /* configUSE_COUNTING_SEMAPHORES */
\r
390 /*-----------------------------------------------------------*/
\r
392 signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )
\r
394 signed portBASE_TYPE xReturn = pdTRUE;
\r
395 xTimeOutType xTimeOut;
\r
399 /* If xTicksToWait is zero then we are not going to block even
\r
400 if there is no room in the queue to post. */
\r
401 if( xTicksToWait > ( portTickType ) 0 )
\r
404 prvLockQueue( pxQueue );
\r
406 if( xReturn == pdTRUE )
\r
408 /* This is the first time through - we need to capture the
\r
409 time while the scheduler is locked to ensure we attempt to
\r
410 block at least once. */
\r
411 vTaskSetTimeOutState( &xTimeOut );
\r
414 if( prvIsQueueFull( pxQueue ) )
\r
416 /* Need to call xTaskCheckForTimeout again as time could
\r
417 have passed since it was last called if this is not the
\r
418 first time around this loop. */
\r
419 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
\r
421 traceBLOCKING_ON_QUEUE_SEND( pxQueue );
\r
422 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
\r
424 /* Unlocking the queue means queue events can effect the
\r
425 event list. It is possible that interrupts occurring now
\r
426 remove this task from the event list again - but as the
\r
427 scheduler is suspended the task will go onto the pending
\r
428 ready last instead of the actual ready list. */
\r
429 prvUnlockQueue( pxQueue );
\r
431 /* Resuming the scheduler will move tasks from the pending
\r
432 ready list into the ready list - so it is feasible that this
\r
433 task is already in a ready list before it yields - in which
\r
434 case the yield will not cause a context switch unless there
\r
435 is also a higher priority task in the pending ready list. */
\r
436 if( !xTaskResumeAll() )
\r
443 prvUnlockQueue( pxQueue );
\r
444 ( void ) xTaskResumeAll();
\r
449 /* The queue was not full so we can just unlock the
\r
450 scheduler and queue again before carrying on. */
\r
451 prvUnlockQueue( pxQueue );
\r
452 ( void ) xTaskResumeAll();
\r
456 /* Higher priority tasks and interrupts can execute during
\r
457 this time and could possible refill the queue - even if we
\r
458 unblocked because space became available. */
\r
460 taskENTER_CRITICAL();
\r
462 /* Is there room on the queue now? To be running we must be
\r
463 the highest priority task wanting to access the queue. */
\r
464 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
\r
466 traceQUEUE_SEND( pxQueue );
\r
467 prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
\r
470 /* If there was a task waiting for data to arrive on the
\r
471 queue then unblock it now. */
\r
472 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
\r
474 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )
\r
476 /* The unblocked task has a priority higher than
\r
477 our own so yield immediately. */
\r
484 /* Setting xReturn to errQUEUE_FULL will force its timeout
\r
485 to be re-evaluated. This is necessary in case interrupts
\r
486 and higher priority tasks accessed the queue between this
\r
487 task being unblocked and subsequently attempting to write
\r
489 xReturn = errQUEUE_FULL;
\r
492 taskEXIT_CRITICAL();
\r
494 if( xReturn == errQUEUE_FULL )
\r
496 if( xTicksToWait > 0 )
\r
498 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
\r
500 xReturn = queueERRONEOUS_UNBLOCK;
\r
504 traceQUEUE_SEND_FAILED( pxQueue );
\r
509 traceQUEUE_SEND_FAILED( pxQueue );
\r
513 while( xReturn == queueERRONEOUS_UNBLOCK );
\r
517 /*-----------------------------------------------------------*/
\r
519 #if configUSE_ALTERNATIVE_API == 1
\r
521 signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )
\r
523 signed portBASE_TYPE xReturn = pdPASS;
\r
524 xTimeOutType xTimeOut;
\r
526 /* The source code that implements the alternative (Alt) API is
\r
527 simpler because it makes more use of critical sections. This is
\r
528 the approach taken by many other RTOSes, but FreeRTOS.org has the
\r
529 preferred fully featured API too. The fully featured API has more
\r
530 complex code that takes longer to execute, but makes less use of
\r
531 critical sections. */
\r
535 /* If xTicksToWait is zero then we are not going to block even
\r
536 if there is no room in the queue to post. */
\r
537 if( xTicksToWait > ( portTickType ) 0 )
\r
539 portENTER_CRITICAL();
\r
541 if( xReturn == pdPASS )
\r
543 /* This is the first time through - capture the time
\r
544 inside the critical section to ensure we attempt to
\r
545 block at least once. */
\r
546 vTaskSetTimeOutState( &xTimeOut );
\r
549 if( prvIsQueueFull( pxQueue ) )
\r
551 /* Need to call xTaskCheckForTimeout again as time could
\r
552 have passed since it was last called if this is not the
\r
553 first time around this loop. */
\r
554 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
\r
556 traceBLOCKING_ON_QUEUE_SEND( pxQueue );
\r
557 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
\r
559 /* This will exit the critical section, then re-enter when
\r
560 the task next runs. */
\r
565 portEXIT_CRITICAL();
\r
568 /* Higher priority tasks and interrupts can execute during
\r
569 this time and could possible refill the queue - even if we
\r
570 unblocked because space became available. */
\r
572 taskENTER_CRITICAL();
\r
574 /* Is there room on the queue now? To be running we must be
\r
575 the highest priority task wanting to access the queue. */
\r
576 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
\r
578 traceQUEUE_SEND( pxQueue );
\r
579 prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
\r
582 /* If there was a task waiting for data to arrive on the
\r
583 queue then unblock it now. */
\r
584 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
\r
586 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )
\r
588 /* The unblocked task has a priority higher than
\r
589 our own so yield immediately. */
\r
596 /* Setting xReturn to errQUEUE_FULL will force its timeout
\r
597 to be re-evaluated. This is necessary in case interrupts
\r
598 and higher priority tasks accessed the queue between this
\r
599 task being unblocked and subsequently attempting to write
\r
601 xReturn = errQUEUE_FULL;
\r
604 taskEXIT_CRITICAL();
\r
606 if( xReturn == errQUEUE_FULL )
\r
608 if( xTicksToWait > 0 )
\r
610 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
\r
612 xReturn = queueERRONEOUS_UNBLOCK;
\r
616 traceQUEUE_SEND_FAILED( pxQueue );
\r
621 traceQUEUE_SEND_FAILED( pxQueue );
\r
625 while( xReturn == queueERRONEOUS_UNBLOCK );
\r
630 #endif /* configUSE_ALTERNATIVE_API */
\r
631 /*-----------------------------------------------------------*/
\r
633 #if configUSE_ALTERNATIVE_API == 1
\r
635 signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, const void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )
\r
637 signed portBASE_TYPE xReturn = pdTRUE;
\r
638 xTimeOutType xTimeOut;
\r
639 signed portCHAR *pcOriginalReadPosition;
\r
641 /* The source code that implements the alternative (Alt) API is
\r
642 simpler because it makes more use of critical sections. This is
\r
643 the approach taken by many other RTOSes, but FreeRTOS.org has the
\r
644 preferred fully featured API too. The fully featured API has more
\r
645 complex code that takes longer to execute, but makes less use of
\r
646 critical sections. */
\r
650 /* If there are no messages in the queue we may have to block. */
\r
651 if( xTicksToWait > ( portTickType ) 0 )
\r
653 portENTER_CRITICAL();
\r
655 if( xReturn == pdPASS )
\r
657 /* This is the first time through - capture the time
\r
658 inside the critical section to ensure we attempt to
\r
659 block at least once. */
\r
660 vTaskSetTimeOutState( &xTimeOut );
\r
663 if( prvIsQueueEmpty( pxQueue ) )
\r
665 /* Need to call xTaskCheckForTimeout again as time could
\r
666 have passed since it was last called if this is not the
\r
667 first time around this loop. */
\r
668 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
\r
670 traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
\r
672 #if ( configUSE_MUTEXES == 1 )
\r
674 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
\r
676 portENTER_CRITICAL();
\r
677 vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );
\r
678 portEXIT_CRITICAL();
\r
683 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
\r
688 portEXIT_CRITICAL();
\r
691 taskENTER_CRITICAL();
\r
693 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
\r
695 /* Remember our read position in case we are just peeking. */
\r
696 pcOriginalReadPosition = pxQueue->pcReadFrom;
\r
698 prvCopyDataFromQueue( pxQueue, pvBuffer );
\r
700 if( xJustPeeking == pdFALSE )
\r
702 traceQUEUE_RECEIVE( pxQueue );
\r
704 /* We are actually removing data. */
\r
705 --( pxQueue->uxMessagesWaiting );
\r
707 #if ( configUSE_MUTEXES == 1 )
\r
709 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
\r
711 /* Record the information required to implement
\r
712 priority inheritance should it become necessary. */
\r
713 pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();
\r
718 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
\r
720 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )
\r
728 traceQUEUE_PEEK( pxQueue );
\r
730 /* We are not removing the data, so reset our read
\r
732 pxQueue->pcReadFrom = pcOriginalReadPosition;
\r
734 /* The data is being left in the queue, so see if there are
\r
735 any other tasks waiting for the data. */
\r
736 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
\r
738 /* Tasks that are removed from the event list will get added to
\r
739 the pending ready list as the scheduler is still suspended. */
\r
740 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
\r
742 /* The task waiting has a higher priority that this task. */
\r
753 xReturn = errQUEUE_EMPTY;
\r
756 taskEXIT_CRITICAL();
\r
758 if( xReturn == errQUEUE_EMPTY )
\r
760 if( xTicksToWait > 0 )
\r
762 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
\r
764 xReturn = queueERRONEOUS_UNBLOCK;
\r
768 traceQUEUE_RECEIVE_FAILED( pxQueue );
\r
773 traceQUEUE_RECEIVE_FAILED( pxQueue );
\r
776 } while( xReturn == queueERRONEOUS_UNBLOCK );
\r
782 #endif /* configUSE_ALTERNATIVE_API */
\r
783 /*-----------------------------------------------------------*/
\r
785 signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken, portBASE_TYPE xCopyPosition )
\r
787 /* Similar to xQueueGenericSend, except we don't block if there is no room
\r
788 in the queue. Also we don't directly wake a task that was blocked on a
\r
789 queue read, instead we return a flag to say whether a context switch is
\r
790 required or not (i.e. has a task with a higher priority than us been woken
\r
792 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
\r
794 traceQUEUE_SEND_FROM_ISR( pxQueue );
\r
796 prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
\r
798 /* If the queue is locked we do not alter the event list. This will
\r
799 be done when the queue is unlocked later. */
\r
800 if( pxQueue->xTxLock == queueUNLOCKED )
\r
802 /* We only want to wake one task per ISR, so check that a task has
\r
803 not already been woken. */
\r
804 if( !xTaskPreviouslyWoken )
\r
806 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
\r
808 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
\r
810 /* The task waiting has a higher priority so record that a
\r
811 context switch is required. */
\r
819 /* Increment the lock count so the task that unlocks the queue
\r
820 knows that data was posted while it was locked. */
\r
821 ++( pxQueue->xTxLock );
\r
826 traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue );
\r
829 return xTaskPreviouslyWoken;
\r
831 /*-----------------------------------------------------------*/
\r
833 signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, const void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )
\r
835 signed portBASE_TYPE xReturn = pdTRUE;
\r
836 xTimeOutType xTimeOut;
\r
837 signed portCHAR *pcOriginalReadPosition;
\r
841 /* If there are no messages in the queue we may have to block. */
\r
842 if( xTicksToWait > ( portTickType ) 0 )
\r
845 prvLockQueue( pxQueue );
\r
847 if( xReturn == pdTRUE )
\r
849 /* This is the first time through - we need to capture the
\r
850 time while the scheduler is locked to ensure we attempt to
\r
851 block at least once. */
\r
852 vTaskSetTimeOutState( &xTimeOut );
\r
855 if( prvIsQueueEmpty( pxQueue ) )
\r
857 /* Need to call xTaskCheckForTimeout again as time could
\r
858 have passed since it was last called if this is not the
\r
859 first time around this loop. */
\r
860 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
\r
862 traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
\r
864 #if ( configUSE_MUTEXES == 1 )
\r
866 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
\r
868 portENTER_CRITICAL();
\r
869 vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );
\r
870 portEXIT_CRITICAL();
\r
875 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
\r
876 prvUnlockQueue( pxQueue );
\r
877 if( !xTaskResumeAll() )
\r
884 prvUnlockQueue( pxQueue );
\r
885 ( void ) xTaskResumeAll();
\r
890 prvUnlockQueue( pxQueue );
\r
891 ( void ) xTaskResumeAll();
\r
895 taskENTER_CRITICAL();
\r
897 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
\r
899 /* Remember our read position in case we are just peeking. */
\r
900 pcOriginalReadPosition = pxQueue->pcReadFrom;
\r
902 prvCopyDataFromQueue( pxQueue, pvBuffer );
\r
904 if( xJustPeeking == pdFALSE )
\r
906 traceQUEUE_RECEIVE( pxQueue );
\r
908 /* We are actually removing data. */
\r
909 --( pxQueue->uxMessagesWaiting );
\r
911 #if ( configUSE_MUTEXES == 1 )
\r
913 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
\r
915 /* Record the information required to implement
\r
916 priority inheritance should it become necessary. */
\r
917 pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();
\r
922 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
\r
924 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )
\r
932 traceQUEUE_PEEK( pxQueue );
\r
934 /* We are not removing the data, so reset our read
\r
936 pxQueue->pcReadFrom = pcOriginalReadPosition;
\r
938 /* The data is being left in the queue, so see if there are
\r
939 any other tasks waiting for the data. */
\r
940 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
\r
942 /* Tasks that are removed from the event list will get added to
\r
943 the pending ready list as the scheduler is still suspended. */
\r
944 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
\r
946 /* The task waiting has a higher priority that this task. */
\r
957 xReturn = errQUEUE_EMPTY;
\r
960 taskEXIT_CRITICAL();
\r
962 if( xReturn == errQUEUE_EMPTY )
\r
964 if( xTicksToWait > 0 )
\r
966 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
\r
968 xReturn = queueERRONEOUS_UNBLOCK;
\r
972 traceQUEUE_RECEIVE_FAILED( pxQueue );
\r
977 traceQUEUE_RECEIVE_FAILED( pxQueue );
\r
980 } while( xReturn == queueERRONEOUS_UNBLOCK );
\r
984 /*-----------------------------------------------------------*/
\r
986 signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, const void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken )
\r
988 signed portBASE_TYPE xReturn;
\r
990 /* We cannot block from an ISR, so check there is data available. */
\r
991 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
\r
993 traceQUEUE_RECEIVE_FROM_ISR( pxQueue );
\r
995 prvCopyDataFromQueue( pxQueue, pvBuffer );
\r
996 --( pxQueue->uxMessagesWaiting );
\r
998 /* If the queue is locked we will not modify the event list. Instead
\r
999 we update the lock count so the task that unlocks the queue will know
\r
1000 that an ISR has removed data while the queue was locked. */
\r
1001 if( pxQueue->xRxLock == queueUNLOCKED )
\r
1003 /* We only want to wake one task per ISR, so check that a task has
\r
1004 not already been woken. */
\r
1005 if( !( *pxTaskWoken ) )
\r
1007 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
\r
1009 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
\r
1011 /* The task waiting has a higher priority than us so
\r
1012 force a context switch. */
\r
1013 *pxTaskWoken = pdTRUE;
\r
1020 /* Increment the lock count so the task that unlocks the queue
\r
1021 knows that data was removed while it was locked. */
\r
1022 ++( pxQueue->xRxLock );
\r
1030 traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue );
\r
1035 /*-----------------------------------------------------------*/
\r
1037 unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle pxQueue )
\r
1039 unsigned portBASE_TYPE uxReturn;
\r
1041 taskENTER_CRITICAL();
\r
1042 uxReturn = pxQueue->uxMessagesWaiting;
\r
1043 taskEXIT_CRITICAL();
\r
1047 /*-----------------------------------------------------------*/
\r
1049 unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue )
\r
1051 unsigned portBASE_TYPE uxReturn;
\r
1053 uxReturn = pxQueue->uxMessagesWaiting;
\r
1057 /*-----------------------------------------------------------*/
\r
1059 void vQueueDelete( xQueueHandle pxQueue )
\r
1061 traceQUEUE_DELETE( pxQueue );
\r
1063 vPortFree( pxQueue->pcHead );
\r
1064 vPortFree( pxQueue );
\r
1066 /*-----------------------------------------------------------*/
\r
1068 static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition )
\r
1070 if( pxQueue->uxItemSize == 0 )
\r
1072 #if ( configUSE_MUTEXES == 1 )
\r
1074 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
\r
1076 /* The mutex is no longer being held. */
\r
1077 vTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder );
\r
1078 pxQueue->pxMutexHolder = NULL;
\r
1083 else if( xPosition == queueSEND_TO_BACK )
\r
1085 memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );
\r
1086 pxQueue->pcWriteTo += pxQueue->uxItemSize;
\r
1087 if( pxQueue->pcWriteTo >= pxQueue->pcTail )
\r
1089 pxQueue->pcWriteTo = pxQueue->pcHead;
\r
1094 memcpy( ( void * ) pxQueue->pcReadFrom, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );
\r
1095 pxQueue->pcReadFrom -= pxQueue->uxItemSize;
\r
1096 if( pxQueue->pcReadFrom < pxQueue->pcHead )
\r
1098 pxQueue->pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize );
\r
1102 ++( pxQueue->uxMessagesWaiting );
\r
1104 /*-----------------------------------------------------------*/
\r
1106 static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer )
\r
1108 if( pxQueue->uxQueueType != queueQUEUE_IS_MUTEX )
\r
1110 pxQueue->pcReadFrom += pxQueue->uxItemSize;
\r
1111 if( pxQueue->pcReadFrom >= pxQueue->pcTail )
\r
1113 pxQueue->pcReadFrom = pxQueue->pcHead;
\r
1115 memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
\r
1118 /*-----------------------------------------------------------*/
\r
1120 static void prvUnlockQueue( xQueueHandle pxQueue )
\r
1122 /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */
\r
1124 /* The lock counts contains the number of extra data items placed or
\r
1125 removed from the queue while the queue was locked. When a queue is
\r
1126 locked items can be added or removed, but the event lists cannot be
\r
1128 taskENTER_CRITICAL();
\r
1130 --( pxQueue->xTxLock );
\r
1132 /* See if data was added to the queue while it was locked. */
\r
1133 if( pxQueue->xTxLock > queueUNLOCKED )
\r
1135 pxQueue->xTxLock = queueUNLOCKED;
\r
1137 /* Data was posted while the queue was locked. Are any tasks
\r
1138 blocked waiting for data to become available? */
\r
1139 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
\r
1141 /* Tasks that are removed from the event list will get added to
\r
1142 the pending ready list as the scheduler is still suspended. */
\r
1143 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
\r
1145 /* The task waiting has a higher priority so record that a
\r
1146 context switch is required. */
\r
1147 vTaskMissedYield();
\r
1152 taskEXIT_CRITICAL();
\r
1154 /* Do the same for the Rx lock. */
\r
1155 taskENTER_CRITICAL();
\r
1157 --( pxQueue->xRxLock );
\r
1159 if( pxQueue->xRxLock > queueUNLOCKED )
\r
1161 pxQueue->xRxLock = queueUNLOCKED;
\r
1163 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
\r
1165 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
\r
1167 vTaskMissedYield();
\r
1172 taskEXIT_CRITICAL();
\r
1174 /*-----------------------------------------------------------*/
\r
1176 static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue )
\r
1178 signed portBASE_TYPE xReturn;
\r
1180 taskENTER_CRITICAL();
\r
1181 xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );
\r
1182 taskEXIT_CRITICAL();
\r
1186 /*-----------------------------------------------------------*/
\r
1188 signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue )
\r
1190 signed portBASE_TYPE xReturn;
\r
1192 xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );
\r
1196 /*-----------------------------------------------------------*/
\r
1198 static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue )
\r
1200 signed portBASE_TYPE xReturn;
\r
1202 taskENTER_CRITICAL();
\r
1203 xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );
\r
1204 taskEXIT_CRITICAL();
\r
1208 /*-----------------------------------------------------------*/
\r
1210 signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue )
\r
1212 signed portBASE_TYPE xReturn;
\r
1214 xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );
\r
1218 /*-----------------------------------------------------------*/
\r
1220 #if configUSE_CO_ROUTINES == 1
\r
1221 signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )
\r
1223 signed portBASE_TYPE xReturn;
\r
1225 /* If the queue is already full we may have to block. A critical section
\r
1226 is required to prevent an interrupt removing something from the queue
\r
1227 between the check to see if the queue is full and blocking on the queue. */
\r
1228 portDISABLE_INTERRUPTS();
\r
1230 if( prvIsQueueFull( pxQueue ) )
\r
1232 /* The queue is full - do we want to block or just leave without
\r
1234 if( xTicksToWait > ( portTickType ) 0 )
\r
1236 /* As this is called from a coroutine we cannot block directly, but
\r
1237 return indicating that we need to block. */
\r
1238 vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToSend ) );
\r
1239 portENABLE_INTERRUPTS();
\r
1240 return errQUEUE_BLOCKED;
\r
1244 portENABLE_INTERRUPTS();
\r
1245 return errQUEUE_FULL;
\r
1249 portENABLE_INTERRUPTS();
\r
1253 portDISABLE_INTERRUPTS();
\r
1255 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
\r
1257 /* There is room in the queue, copy the data into the queue. */
\r
1258 prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );
\r
1261 /* Were any co-routines waiting for data to become available? */
\r
1262 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
\r
1264 /* In this instance the co-routine could be placed directly
\r
1265 into the ready list as we are within a critical section.
\r
1266 Instead the same pending ready list mechanism is used as if
\r
1267 the event were caused from within an interrupt. */
\r
1268 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
\r
1270 /* The co-routine waiting has a higher priority so record
\r
1271 that a yield might be appropriate. */
\r
1272 xReturn = errQUEUE_YIELD;
\r
1278 xReturn = errQUEUE_FULL;
\r
1281 portENABLE_INTERRUPTS();
\r
1286 /*-----------------------------------------------------------*/
\r
1288 #if configUSE_CO_ROUTINES == 1
\r
1289 signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait )
\r
1291 signed portBASE_TYPE xReturn;
\r
1293 /* If the queue is already empty we may have to block. A critical section
\r
1294 is required to prevent an interrupt adding something to the queue
\r
1295 between the check to see if the queue is empty and blocking on the queue. */
\r
1296 portDISABLE_INTERRUPTS();
\r
1298 if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 )
\r
1300 /* There are no messages in the queue, do we want to block or just
\r
1301 leave with nothing? */
\r
1302 if( xTicksToWait > ( portTickType ) 0 )
\r
1304 /* As this is a co-routine we cannot block directly, but return
\r
1305 indicating that we need to block. */
\r
1306 vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToReceive ) );
\r
1307 portENABLE_INTERRUPTS();
\r
1308 return errQUEUE_BLOCKED;
\r
1312 portENABLE_INTERRUPTS();
\r
1313 return errQUEUE_FULL;
\r
1317 portENABLE_INTERRUPTS();
\r
1321 portDISABLE_INTERRUPTS();
\r
1323 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
\r
1325 /* Data is available from the queue. */
\r
1326 pxQueue->pcReadFrom += pxQueue->uxItemSize;
\r
1327 if( pxQueue->pcReadFrom >= pxQueue->pcTail )
\r
1329 pxQueue->pcReadFrom = pxQueue->pcHead;
\r
1331 --( pxQueue->uxMessagesWaiting );
\r
1332 memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
\r
1336 /* Were any co-routines waiting for space to become available? */
\r
1337 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
\r
1339 /* In this instance the co-routine could be placed directly
\r
1340 into the ready list as we are within a critical section.
\r
1341 Instead the same pending ready list mechanism is used as if
\r
1342 the event were caused from within an interrupt. */
\r
1343 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
\r
1345 xReturn = errQUEUE_YIELD;
\r
1354 portENABLE_INTERRUPTS();
\r
1359 /*-----------------------------------------------------------*/
\r
1363 #if configUSE_CO_ROUTINES == 1
\r
1364 signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken )
\r
1366 /* Cannot block within an ISR so if there is no space on the queue then
\r
1367 exit without doing anything. */
\r
1368 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
\r
1370 prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );
\r
1372 /* We only want to wake one co-routine per ISR, so check that a
\r
1373 co-routine has not already been woken. */
\r
1374 if( !xCoRoutinePreviouslyWoken )
\r
1376 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
\r
1378 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
\r
1386 return xCoRoutinePreviouslyWoken;
\r
1389 /*-----------------------------------------------------------*/
\r
1391 #if configUSE_CO_ROUTINES == 1
\r
1392 signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxCoRoutineWoken )
\r
1394 signed portBASE_TYPE xReturn;
\r
1396 /* We cannot block from an ISR, so check there is data available. If
\r
1397 not then just leave without doing anything. */
\r
1398 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
\r
1400 /* Copy the data from the queue. */
\r
1401 pxQueue->pcReadFrom += pxQueue->uxItemSize;
\r
1402 if( pxQueue->pcReadFrom >= pxQueue->pcTail )
\r
1404 pxQueue->pcReadFrom = pxQueue->pcHead;
\r
1406 --( pxQueue->uxMessagesWaiting );
\r
1407 memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
\r
1409 if( !( *pxCoRoutineWoken ) )
\r
1411 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
\r
1413 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
\r
1415 *pxCoRoutineWoken = pdTRUE;
\r
1430 /*-----------------------------------------------------------*/
\r