2 FreeRTOS.org V4.8.0 - 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
27 ***************************************************************************
\r
29 * SAVE TIME AND MONEY! We can port FreeRTOS.org to your own hardware, *
\r
30 * and even write all or part of your application on your behalf. *
\r
31 * See http://www.OpenRTOS.com for details of the services we provide to *
\r
32 * expedite your project. *
\r
34 ***************************************************************************
\r
35 ***************************************************************************
\r
37 Please ensure to read the configuration and relevant port sections of the
\r
38 online documentation.
\r
40 http://www.FreeRTOS.org - Documentation, latest information, license and
\r
43 http://www.SafeRTOS.com - A version that is certified for use in safety
\r
46 http://www.OpenRTOS.com - Commercial support, development, porting,
\r
47 licensing and training services.
\r
52 #include "FreeRTOS.h"
\r
54 #include "croutine.h"
\r
56 /*-----------------------------------------------------------
\r
57 * PUBLIC LIST API documented in list.h
\r
58 *----------------------------------------------------------*/
\r
60 /* Constants used with the cRxLock and cTxLock structure members. */
\r
61 #define queueUNLOCKED ( ( signed portBASE_TYPE ) -1 )
\r
62 #define queueERRONEOUS_UNBLOCK ( -1 )
\r
64 /* For internal use only. */
\r
65 #define queueSEND_TO_BACK ( 0 )
\r
66 #define queueSEND_TO_FRONT ( 1 )
\r
68 /* Effectively make a union out of the xQUEUE structure. */
\r
69 #define pxMutexHolder pcTail
\r
70 #define uxQueueType pcHead
\r
71 #define uxRecursiveCallCount pcReadFrom
\r
72 #define queueQUEUE_IS_MUTEX NULL
\r
74 /* Semaphores do not actually store or copy data, so have an items size of
\r
76 #define queueSEMAPHORE_QUEUE_ITEM_LENGTH ( 0 )
\r
77 #define queueDONT_BLOCK ( ( portTickType ) 0 )
\r
78 #define queueMUTEX_GIVE_BLOCK_TIME ( ( portTickType ) 0 )
\r
80 * Definition of the queue used by the scheduler.
\r
81 * Items are queued by copy, not reference.
\r
83 typedef struct QueueDefinition
\r
85 signed portCHAR *pcHead; /*< Points to the beginning of the queue storage area. */
\r
86 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
88 signed portCHAR *pcWriteTo; /*< Points to the free next place in the storage area. */
\r
89 signed portCHAR *pcReadFrom; /*< Points to the last place that a queued item was read from. */
\r
91 xList xTasksWaitingToSend; /*< List of tasks that are blocked waiting to post onto this queue. Stored in priority order. */
\r
92 xList xTasksWaitingToReceive; /*< List of tasks that are blocked waiting to read from this queue. Stored in priority order. */
\r
94 volatile unsigned portBASE_TYPE uxMessagesWaiting;/*< The number of items currently in the queue. */
\r
95 unsigned portBASE_TYPE uxLength; /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */
\r
96 unsigned portBASE_TYPE uxItemSize; /*< The size of each items that the queue will hold. */
\r
98 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
99 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
101 /*-----------------------------------------------------------*/
\r
104 * Inside this file xQueueHandle is a pointer to a xQUEUE structure.
\r
105 * To keep the definition private the API header file defines it as a
\r
108 typedef xQUEUE * xQueueHandle;
\r
111 * Prototypes for public functions are included here so we don't have to
\r
112 * include the API header file (as it defines xQueueHandle differently). These
\r
113 * functions are documented in the API header file.
\r
115 xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize );
\r
116 signed portBASE_TYPE xQueueGenericSend( xQueueHandle xQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition );
\r
117 unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle pxQueue );
\r
118 void vQueueDelete( xQueueHandle xQueue );
\r
119 signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken, portBASE_TYPE xCopyPosition );
\r
120 signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, const void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking );
\r
121 signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, const void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken );
\r
122 xQueueHandle xQueueCreateMutex( void );
\r
123 xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount );
\r
124 portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle xMutex, portTickType xBlockTime );
\r
125 portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle xMutex );
\r
126 signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition );
\r
127 signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, const void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking );
\r
128 portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue );
\r
129 portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue );
\r
130 unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue );
\r
133 #if configUSE_CO_ROUTINES == 1
\r
134 signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken );
\r
135 signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );
\r
136 signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait );
\r
137 signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait );
\r
141 * Unlocks a queue locked by a call to prvLockQueue. Locking a queue does not
\r
142 * prevent an ISR from adding or removing items to the queue, but does prevent
\r
143 * an ISR from removing tasks from the queue event lists. If an ISR finds a
\r
144 * queue is locked it will instead increment the appropriate queue lock count
\r
145 * to indicate that a task may require unblocking. When the queue in unlocked
\r
146 * these lock counts are inspected, and the appropriate action taken.
\r
148 static void prvUnlockQueue( xQueueHandle pxQueue );
\r
151 * Uses a critical section to determine if there is any data in a queue.
\r
153 * @return pdTRUE if the queue contains no items, otherwise pdFALSE.
\r
155 static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue );
\r
158 * Uses a critical section to determine if there is any space in a queue.
\r
160 * @return pdTRUE if there is no space, otherwise pdFALSE;
\r
162 static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue );
\r
165 * Copies an item into the queue, either at the front of the queue or the
\r
166 * back of the queue.
\r
168 static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition );
\r
171 * Copies an item out of a queue.
\r
173 static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer );
\r
174 /*-----------------------------------------------------------*/
\r
177 * Macro to mark a queue as locked. Locking a queue prevents an ISR from
\r
178 * accessing the queue event lists.
\r
180 #define prvLockQueue( pxQueue ) \
\r
182 taskENTER_CRITICAL(); \
\r
183 ++( pxQueue->xRxLock ); \
\r
184 ++( pxQueue->xTxLock ); \
\r
185 taskEXIT_CRITICAL(); \
\r
187 /*-----------------------------------------------------------*/
\r
190 /*-----------------------------------------------------------
\r
191 * PUBLIC QUEUE MANAGEMENT API documented in queue.h
\r
192 *----------------------------------------------------------*/
\r
194 xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize )
\r
196 xQUEUE *pxNewQueue;
\r
197 size_t xQueueSizeInBytes;
\r
199 /* Allocate the new queue structure. */
\r
200 if( uxQueueLength > ( unsigned portBASE_TYPE ) 0 )
\r
202 pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );
\r
203 if( pxNewQueue != NULL )
\r
205 /* Create the list of pointers to queue items. The queue is one byte
\r
206 longer than asked for to make wrap checking easier/faster. */
\r
207 xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ) + ( size_t ) 1;
\r
209 pxNewQueue->pcHead = ( signed portCHAR * ) pvPortMalloc( xQueueSizeInBytes );
\r
210 if( pxNewQueue->pcHead != NULL )
\r
212 /* Initialise the queue members as described above where the
\r
213 queue type is defined. */
\r
214 pxNewQueue->pcTail = pxNewQueue->pcHead + ( uxQueueLength * uxItemSize );
\r
215 pxNewQueue->uxMessagesWaiting = 0;
\r
216 pxNewQueue->pcWriteTo = pxNewQueue->pcHead;
\r
217 pxNewQueue->pcReadFrom = pxNewQueue->pcHead + ( ( uxQueueLength - 1 ) * uxItemSize );
\r
218 pxNewQueue->uxLength = uxQueueLength;
\r
219 pxNewQueue->uxItemSize = uxItemSize;
\r
220 pxNewQueue->xRxLock = queueUNLOCKED;
\r
221 pxNewQueue->xTxLock = queueUNLOCKED;
\r
223 /* Likewise ensure the event queues start with the correct state. */
\r
224 vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );
\r
225 vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );
\r
227 traceQUEUE_CREATE( pxNewQueue );
\r
233 traceQUEUE_CREATE_FAILED();
\r
234 vPortFree( pxNewQueue );
\r
239 /* Will only reach here if we could not allocate enough memory or no memory
\r
243 /*-----------------------------------------------------------*/
\r
245 #if ( configUSE_MUTEXES == 1 )
\r
247 xQueueHandle xQueueCreateMutex( void )
\r
249 xQUEUE *pxNewQueue;
\r
251 /* Allocate the new queue structure. */
\r
252 pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );
\r
253 if( pxNewQueue != NULL )
\r
255 /* Information required for priority inheritance. */
\r
256 pxNewQueue->pxMutexHolder = NULL;
\r
257 pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX;
\r
259 /* Queues used as a mutex no data is actually copied into or out
\r
261 pxNewQueue->pcWriteTo = NULL;
\r
262 pxNewQueue->pcReadFrom = NULL;
\r
264 /* Each mutex has a length of 1 (like a binary semaphore) and
\r
265 an item size of 0 as nothing is actually copied into or out
\r
267 pxNewQueue->uxMessagesWaiting = 0;
\r
268 pxNewQueue->uxLength = 1;
\r
269 pxNewQueue->uxItemSize = 0;
\r
270 pxNewQueue->xRxLock = queueUNLOCKED;
\r
271 pxNewQueue->xTxLock = queueUNLOCKED;
\r
273 /* Ensure the event queues start with the correct state. */
\r
274 vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );
\r
275 vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );
\r
277 /* Start with the semaphore in the expected state. */
\r
278 xQueueGenericSend( pxNewQueue, NULL, 0, queueSEND_TO_BACK );
\r
280 traceCREATE_MUTEX( pxNewQueue );
\r
284 traceCREATE_MUTEX_FAILED();
\r
290 #endif /* configUSE_MUTEXES */
\r
291 /*-----------------------------------------------------------*/
\r
293 #if configUSE_RECURSIVE_MUTEXES == 1
\r
295 portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle pxMutex )
\r
297 portBASE_TYPE xReturn;
\r
299 /* If this is the task that holds the mutex then pxMutexHolder will not
\r
300 change outside of this task. If this task does not hold the mutex then
\r
301 pxMutexHolder can never coincidentally equal the tasks handle, and as
\r
302 this is the only condition we are interested in it does not matter if
\r
303 pxMutexHolder is accessed simultaneously by another task. Therefore no
\r
304 mutual exclusion is required to test the pxMutexHolder variable. */
\r
305 if( pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle() )
\r
307 /* uxRecursiveCallCount cannot be zero if pxMutexHolder is equal to
\r
308 the task handle, therefore no underflow check is required. Also,
\r
309 uxRecursiveCallCount is only modified by the mutex holder, and as
\r
310 there can only be one, no mutual exclusion is required to modify the
\r
311 uxRecursiveCallCount member. */
\r
312 ( pxMutex->uxRecursiveCallCount )--;
\r
314 /* Have we unwound the call count? */
\r
315 if( pxMutex->uxRecursiveCallCount == 0 )
\r
317 /* Return the mutex. This will automatically unblock any other
\r
318 task that might be waiting to access the mutex. */
\r
319 xQueueGenericSend( pxMutex, NULL, queueMUTEX_GIVE_BLOCK_TIME, queueSEND_TO_BACK );
\r
324 traceGIVE_MUTEX_RECURSIVE( pxMutex );
\r
328 /* We cannot give the mutex because we are not the holder. */
\r
331 traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex );
\r
337 #endif /* configUSE_RECURSIVE_MUTEXES */
\r
338 /*-----------------------------------------------------------*/
\r
340 #if configUSE_RECURSIVE_MUTEXES == 1
\r
342 portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle pxMutex, portTickType xBlockTime )
\r
344 portBASE_TYPE xReturn;
\r
346 /* Comments regarding mutual exclusion as per those within
\r
347 xQueueGiveMutexRecursive(). */
\r
349 if( pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle() )
\r
351 ( pxMutex->uxRecursiveCallCount )++;
\r
356 xReturn = xQueueGenericReceive( pxMutex, NULL, xBlockTime, pdFALSE );
\r
358 /* pdPASS will only be returned if we successfully obtained the mutex,
\r
359 we may have blocked to reach here. */
\r
360 if( xReturn == pdPASS )
\r
362 ( pxMutex->uxRecursiveCallCount )++;
\r
366 traceTAKE_MUTEX_RECURSIVE( pxMutex );
\r
371 #endif /* configUSE_RECURSIVE_MUTEXES */
\r
372 /*-----------------------------------------------------------*/
\r
374 #if configUSE_COUNTING_SEMAPHORES == 1
\r
376 xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount )
\r
378 xQueueHandle pxHandle;
\r
380 pxHandle = xQueueCreate( ( unsigned portBASE_TYPE ) uxCountValue, queueSEMAPHORE_QUEUE_ITEM_LENGTH );
\r
382 if( pxHandle != NULL )
\r
384 pxHandle->uxMessagesWaiting = uxInitialCount;
\r
386 traceCREATE_COUNTING_SEMAPHORE();
\r
390 traceCREATE_COUNTING_SEMAPHORE_FAILED();
\r
396 #endif /* configUSE_COUNTING_SEMAPHORES */
\r
397 /*-----------------------------------------------------------*/
\r
399 signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )
\r
401 signed portBASE_TYPE xReturn = pdTRUE;
\r
402 xTimeOutType xTimeOut;
\r
406 /* If xTicksToWait is zero then we are not going to block even
\r
407 if there is no room in the queue to post. */
\r
408 if( xTicksToWait > ( portTickType ) 0 )
\r
411 prvLockQueue( pxQueue );
\r
413 if( xReturn == pdTRUE )
\r
415 /* This is the first time through - we need to capture the
\r
416 time while the scheduler is locked to ensure we attempt to
\r
417 block at least once. */
\r
418 vTaskSetTimeOutState( &xTimeOut );
\r
421 if( prvIsQueueFull( pxQueue ) )
\r
423 /* Need to call xTaskCheckForTimeout again as time could
\r
424 have passed since it was last called if this is not the
\r
425 first time around this loop. */
\r
426 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
\r
428 traceBLOCKING_ON_QUEUE_SEND( pxQueue );
\r
429 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
\r
431 /* Unlocking the queue means queue events can effect the
\r
432 event list. It is possible that interrupts occurring now
\r
433 remove this task from the event list again - but as the
\r
434 scheduler is suspended the task will go onto the pending
\r
435 ready last instead of the actual ready list. */
\r
436 prvUnlockQueue( pxQueue );
\r
438 /* Resuming the scheduler will move tasks from the pending
\r
439 ready list into the ready list - so it is feasible that this
\r
440 task is already in a ready list before it yields - in which
\r
441 case the yield will not cause a context switch unless there
\r
442 is also a higher priority task in the pending ready list. */
\r
443 if( !xTaskResumeAll() )
\r
450 prvUnlockQueue( pxQueue );
\r
451 ( void ) xTaskResumeAll();
\r
456 /* The queue was not full so we can just unlock the
\r
457 scheduler and queue again before carrying on. */
\r
458 prvUnlockQueue( pxQueue );
\r
459 ( void ) xTaskResumeAll();
\r
463 /* Higher priority tasks and interrupts can execute during
\r
464 this time and could possible refill the queue - even if we
\r
465 unblocked because space became available. */
\r
467 taskENTER_CRITICAL();
\r
469 /* Is there room on the queue now? To be running we must be
\r
470 the highest priority task wanting to access the queue. */
\r
471 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
\r
473 traceQUEUE_SEND( pxQueue );
\r
474 prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
\r
477 /* If there was a task waiting for data to arrive on the
\r
478 queue then unblock it now. */
\r
479 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
\r
481 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )
\r
483 /* The unblocked task has a priority higher than
\r
484 our own so yield immediately. */
\r
491 /* Setting xReturn to errQUEUE_FULL will force its timeout
\r
492 to be re-evaluated. This is necessary in case interrupts
\r
493 and higher priority tasks accessed the queue between this
\r
494 task being unblocked and subsequently attempting to write
\r
496 xReturn = errQUEUE_FULL;
\r
499 taskEXIT_CRITICAL();
\r
501 if( xReturn == errQUEUE_FULL )
\r
503 if( xTicksToWait > ( portTickType ) 0 )
\r
505 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
\r
507 xReturn = queueERRONEOUS_UNBLOCK;
\r
511 traceQUEUE_SEND_FAILED( pxQueue );
\r
516 traceQUEUE_SEND_FAILED( pxQueue );
\r
520 while( xReturn == queueERRONEOUS_UNBLOCK );
\r
524 /*-----------------------------------------------------------*/
\r
526 #if configUSE_ALTERNATIVE_API == 1
\r
528 signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )
\r
530 signed portBASE_TYPE xReturn = pdPASS;
\r
531 xTimeOutType xTimeOut;
\r
533 /* The source code that implements the alternative (Alt) API is
\r
534 simpler because it makes more use of critical sections. This is
\r
535 the approach taken by many other RTOSes, but FreeRTOS.org has the
\r
536 preferred fully featured API too. The fully featured API has more
\r
537 complex code that takes longer to execute, but makes less use of
\r
538 critical sections. */
\r
542 /* If xTicksToWait is zero then we are not going to block even
\r
543 if there is no room in the queue to post. */
\r
544 if( xTicksToWait > ( portTickType ) 0 )
\r
546 portENTER_CRITICAL();
\r
548 if( xReturn == pdPASS )
\r
550 /* This is the first time through - capture the time
\r
551 inside the critical section to ensure we attempt to
\r
552 block at least once. */
\r
553 vTaskSetTimeOutState( &xTimeOut );
\r
556 if( prvIsQueueFull( pxQueue ) )
\r
558 /* Need to call xTaskCheckForTimeout again as time could
\r
559 have passed since it was last called if this is not the
\r
560 first time around this loop. */
\r
561 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
\r
563 traceBLOCKING_ON_QUEUE_SEND( pxQueue );
\r
564 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
\r
566 /* This will exit the critical section, then re-enter when
\r
567 the task next runs. */
\r
572 portEXIT_CRITICAL();
\r
575 /* Higher priority tasks and interrupts can execute during
\r
576 this time and could possible refill the queue - even if we
\r
577 unblocked because space became available. */
\r
579 taskENTER_CRITICAL();
\r
581 /* Is there room on the queue now? To be running we must be
\r
582 the highest priority task wanting to access the queue. */
\r
583 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
\r
585 traceQUEUE_SEND( pxQueue );
\r
586 prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
\r
589 /* If there was a task waiting for data to arrive on the
\r
590 queue then unblock it now. */
\r
591 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
\r
593 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )
\r
595 /* The unblocked task has a priority higher than
\r
596 our own so yield immediately. */
\r
603 /* Setting xReturn to errQUEUE_FULL will force its timeout
\r
604 to be re-evaluated. This is necessary in case interrupts
\r
605 and higher priority tasks accessed the queue between this
\r
606 task being unblocked and subsequently attempting to write
\r
608 xReturn = errQUEUE_FULL;
\r
611 taskEXIT_CRITICAL();
\r
613 if( xReturn == errQUEUE_FULL )
\r
615 if( xTicksToWait > ( portTickType ) 0 )
\r
617 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
\r
619 xReturn = queueERRONEOUS_UNBLOCK;
\r
623 traceQUEUE_SEND_FAILED( pxQueue );
\r
628 traceQUEUE_SEND_FAILED( pxQueue );
\r
632 while( xReturn == queueERRONEOUS_UNBLOCK );
\r
637 #endif /* configUSE_ALTERNATIVE_API */
\r
638 /*-----------------------------------------------------------*/
\r
640 #if configUSE_ALTERNATIVE_API == 1
\r
642 signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, const void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )
\r
644 signed portBASE_TYPE xReturn = pdTRUE;
\r
645 xTimeOutType xTimeOut;
\r
646 signed portCHAR *pcOriginalReadPosition;
\r
648 /* The source code that implements the alternative (Alt) API is
\r
649 simpler because it makes more use of critical sections. This is
\r
650 the approach taken by many other RTOSes, but FreeRTOS.org has the
\r
651 preferred fully featured API too. The fully featured API has more
\r
652 complex code that takes longer to execute, but makes less use of
\r
653 critical sections. */
\r
657 /* If there are no messages in the queue we may have to block. */
\r
658 if( xTicksToWait > ( portTickType ) 0 )
\r
660 portENTER_CRITICAL();
\r
662 if( xReturn == pdPASS )
\r
664 /* This is the first time through - capture the time
\r
665 inside the critical section to ensure we attempt to
\r
666 block at least once. */
\r
667 vTaskSetTimeOutState( &xTimeOut );
\r
670 if( prvIsQueueEmpty( pxQueue ) )
\r
672 /* Need to call xTaskCheckForTimeout again as time could
\r
673 have passed since it was last called if this is not the
\r
674 first time around this loop. */
\r
675 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
\r
677 traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
\r
679 #if ( configUSE_MUTEXES == 1 )
\r
681 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
\r
683 portENTER_CRITICAL();
\r
684 vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );
\r
685 portEXIT_CRITICAL();
\r
690 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
\r
695 portEXIT_CRITICAL();
\r
698 taskENTER_CRITICAL();
\r
700 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
\r
702 /* Remember our read position in case we are just peeking. */
\r
703 pcOriginalReadPosition = pxQueue->pcReadFrom;
\r
705 prvCopyDataFromQueue( pxQueue, pvBuffer );
\r
707 if( xJustPeeking == pdFALSE )
\r
709 traceQUEUE_RECEIVE( pxQueue );
\r
711 /* We are actually removing data. */
\r
712 --( pxQueue->uxMessagesWaiting );
\r
714 #if ( configUSE_MUTEXES == 1 )
\r
716 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
\r
718 /* Record the information required to implement
\r
719 priority inheritance should it become necessary. */
\r
720 pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();
\r
725 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
\r
727 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )
\r
735 traceQUEUE_PEEK( pxQueue );
\r
737 /* We are not removing the data, so reset our read
\r
739 pxQueue->pcReadFrom = pcOriginalReadPosition;
\r
741 /* The data is being left in the queue, so see if there are
\r
742 any other tasks waiting for the data. */
\r
743 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
\r
745 /* Tasks that are removed from the event list will get added to
\r
746 the pending ready list as the scheduler is still suspended. */
\r
747 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
\r
749 /* The task waiting has a higher priority that this task. */
\r
760 xReturn = errQUEUE_EMPTY;
\r
763 taskEXIT_CRITICAL();
\r
765 if( xReturn == errQUEUE_EMPTY )
\r
767 if( xTicksToWait > ( portTickType ) 0 )
\r
769 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
\r
771 xReturn = queueERRONEOUS_UNBLOCK;
\r
775 traceQUEUE_RECEIVE_FAILED( pxQueue );
\r
780 traceQUEUE_RECEIVE_FAILED( pxQueue );
\r
783 } while( xReturn == queueERRONEOUS_UNBLOCK );
\r
789 #endif /* configUSE_ALTERNATIVE_API */
\r
790 /*-----------------------------------------------------------*/
\r
792 signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken, portBASE_TYPE xCopyPosition )
\r
794 /* Similar to xQueueGenericSend, except we don't block if there is no room
\r
795 in the queue. Also we don't directly wake a task that was blocked on a
\r
796 queue read, instead we return a flag to say whether a context switch is
\r
797 required or not (i.e. has a task with a higher priority than us been woken
\r
799 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
\r
801 traceQUEUE_SEND_FROM_ISR( pxQueue );
\r
803 prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
\r
805 /* If the queue is locked we do not alter the event list. This will
\r
806 be done when the queue is unlocked later. */
\r
807 if( pxQueue->xTxLock == queueUNLOCKED )
\r
809 /* We only want to wake one task per ISR, so check that a task has
\r
810 not already been woken. */
\r
811 if( !xTaskPreviouslyWoken )
\r
813 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
\r
815 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
\r
817 /* The task waiting has a higher priority so record that a
\r
818 context switch is required. */
\r
826 /* Increment the lock count so the task that unlocks the queue
\r
827 knows that data was posted while it was locked. */
\r
828 ++( pxQueue->xTxLock );
\r
833 traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue );
\r
836 return xTaskPreviouslyWoken;
\r
838 /*-----------------------------------------------------------*/
\r
840 signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, const void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )
\r
842 signed portBASE_TYPE xReturn = pdTRUE;
\r
843 xTimeOutType xTimeOut;
\r
844 signed portCHAR *pcOriginalReadPosition;
\r
848 /* If there are no messages in the queue we may have to block. */
\r
849 if( xTicksToWait > ( portTickType ) 0 )
\r
852 prvLockQueue( pxQueue );
\r
854 if( xReturn == pdTRUE )
\r
856 /* This is the first time through - we need to capture the
\r
857 time while the scheduler is locked to ensure we attempt to
\r
858 block at least once. */
\r
859 vTaskSetTimeOutState( &xTimeOut );
\r
862 if( prvIsQueueEmpty( pxQueue ) )
\r
864 /* Need to call xTaskCheckForTimeout again as time could
\r
865 have passed since it was last called if this is not the
\r
866 first time around this loop. */
\r
867 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
\r
869 traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
\r
871 #if ( configUSE_MUTEXES == 1 )
\r
873 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
\r
875 portENTER_CRITICAL();
\r
876 vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );
\r
877 portEXIT_CRITICAL();
\r
882 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
\r
883 prvUnlockQueue( pxQueue );
\r
884 if( !xTaskResumeAll() )
\r
891 prvUnlockQueue( pxQueue );
\r
892 ( void ) xTaskResumeAll();
\r
897 prvUnlockQueue( pxQueue );
\r
898 ( void ) xTaskResumeAll();
\r
902 taskENTER_CRITICAL();
\r
904 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
\r
906 /* Remember our read position in case we are just peeking. */
\r
907 pcOriginalReadPosition = pxQueue->pcReadFrom;
\r
909 prvCopyDataFromQueue( pxQueue, pvBuffer );
\r
911 if( xJustPeeking == pdFALSE )
\r
913 traceQUEUE_RECEIVE( pxQueue );
\r
915 /* We are actually removing data. */
\r
916 --( pxQueue->uxMessagesWaiting );
\r
918 #if ( configUSE_MUTEXES == 1 )
\r
920 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
\r
922 /* Record the information required to implement
\r
923 priority inheritance should it become necessary. */
\r
924 pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();
\r
929 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
\r
931 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )
\r
939 traceQUEUE_PEEK( pxQueue );
\r
941 /* We are not removing the data, so reset our read
\r
943 pxQueue->pcReadFrom = pcOriginalReadPosition;
\r
945 /* The data is being left in the queue, so see if there are
\r
946 any other tasks waiting for the data. */
\r
947 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
\r
949 /* Tasks that are removed from the event list will get added to
\r
950 the pending ready list as the scheduler is still suspended. */
\r
951 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
\r
953 /* The task waiting has a higher priority that this task. */
\r
964 xReturn = errQUEUE_EMPTY;
\r
967 taskEXIT_CRITICAL();
\r
969 if( xReturn == errQUEUE_EMPTY )
\r
971 if( xTicksToWait > 0 )
\r
973 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
\r
975 xReturn = queueERRONEOUS_UNBLOCK;
\r
979 traceQUEUE_RECEIVE_FAILED( pxQueue );
\r
984 traceQUEUE_RECEIVE_FAILED( pxQueue );
\r
987 } while( xReturn == queueERRONEOUS_UNBLOCK );
\r
991 /*-----------------------------------------------------------*/
\r
993 signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, const void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken )
\r
995 signed portBASE_TYPE xReturn;
\r
997 /* We cannot block from an ISR, so check there is data available. */
\r
998 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
\r
1000 traceQUEUE_RECEIVE_FROM_ISR( pxQueue );
\r
1002 prvCopyDataFromQueue( pxQueue, pvBuffer );
\r
1003 --( pxQueue->uxMessagesWaiting );
\r
1005 /* If the queue is locked we will not modify the event list. Instead
\r
1006 we update the lock count so the task that unlocks the queue will know
\r
1007 that an ISR has removed data while the queue was locked. */
\r
1008 if( pxQueue->xRxLock == queueUNLOCKED )
\r
1010 /* We only want to wake one task per ISR, so check that a task has
\r
1011 not already been woken. */
\r
1012 if( !( *pxTaskWoken ) )
\r
1014 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
\r
1016 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
\r
1018 /* The task waiting has a higher priority than us so
\r
1019 force a context switch. */
\r
1020 *pxTaskWoken = pdTRUE;
\r
1027 /* Increment the lock count so the task that unlocks the queue
\r
1028 knows that data was removed while it was locked. */
\r
1029 ++( pxQueue->xRxLock );
\r
1037 traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue );
\r
1042 /*-----------------------------------------------------------*/
\r
1044 unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle pxQueue )
\r
1046 unsigned portBASE_TYPE uxReturn;
\r
1048 taskENTER_CRITICAL();
\r
1049 uxReturn = pxQueue->uxMessagesWaiting;
\r
1050 taskEXIT_CRITICAL();
\r
1054 /*-----------------------------------------------------------*/
\r
1056 unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue )
\r
1058 unsigned portBASE_TYPE uxReturn;
\r
1060 uxReturn = pxQueue->uxMessagesWaiting;
\r
1064 /*-----------------------------------------------------------*/
\r
1066 void vQueueDelete( xQueueHandle pxQueue )
\r
1068 traceQUEUE_DELETE( pxQueue );
\r
1070 vPortFree( pxQueue->pcHead );
\r
1071 vPortFree( pxQueue );
\r
1073 /*-----------------------------------------------------------*/
\r
1075 static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition )
\r
1077 if( pxQueue->uxItemSize == 0 )
\r
1079 #if ( configUSE_MUTEXES == 1 )
\r
1081 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
\r
1083 /* The mutex is no longer being held. */
\r
1084 vTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder );
\r
1085 pxQueue->pxMutexHolder = NULL;
\r
1090 else if( xPosition == queueSEND_TO_BACK )
\r
1092 memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );
\r
1093 pxQueue->pcWriteTo += pxQueue->uxItemSize;
\r
1094 if( pxQueue->pcWriteTo >= pxQueue->pcTail )
\r
1096 pxQueue->pcWriteTo = pxQueue->pcHead;
\r
1101 memcpy( ( void * ) pxQueue->pcReadFrom, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );
\r
1102 pxQueue->pcReadFrom -= pxQueue->uxItemSize;
\r
1103 if( pxQueue->pcReadFrom < pxQueue->pcHead )
\r
1105 pxQueue->pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize );
\r
1109 ++( pxQueue->uxMessagesWaiting );
\r
1111 /*-----------------------------------------------------------*/
\r
1113 static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer )
\r
1115 if( pxQueue->uxQueueType != queueQUEUE_IS_MUTEX )
\r
1117 pxQueue->pcReadFrom += pxQueue->uxItemSize;
\r
1118 if( pxQueue->pcReadFrom >= pxQueue->pcTail )
\r
1120 pxQueue->pcReadFrom = pxQueue->pcHead;
\r
1122 memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
\r
1125 /*-----------------------------------------------------------*/
\r
1127 static void prvUnlockQueue( xQueueHandle pxQueue )
\r
1129 /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */
\r
1131 /* The lock counts contains the number of extra data items placed or
\r
1132 removed from the queue while the queue was locked. When a queue is
\r
1133 locked items can be added or removed, but the event lists cannot be
\r
1135 taskENTER_CRITICAL();
\r
1137 --( pxQueue->xTxLock );
\r
1139 /* See if data was added to the queue while it was locked. */
\r
1140 if( pxQueue->xTxLock > queueUNLOCKED )
\r
1142 pxQueue->xTxLock = queueUNLOCKED;
\r
1144 /* Data was posted while the queue was locked. Are any tasks
\r
1145 blocked waiting for data to become available? */
\r
1146 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
\r
1148 /* Tasks that are removed from the event list will get added to
\r
1149 the pending ready list as the scheduler is still suspended. */
\r
1150 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
\r
1152 /* The task waiting has a higher priority so record that a
\r
1153 context switch is required. */
\r
1154 vTaskMissedYield();
\r
1159 taskEXIT_CRITICAL();
\r
1161 /* Do the same for the Rx lock. */
\r
1162 taskENTER_CRITICAL();
\r
1164 --( pxQueue->xRxLock );
\r
1166 if( pxQueue->xRxLock > queueUNLOCKED )
\r
1168 pxQueue->xRxLock = queueUNLOCKED;
\r
1170 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
\r
1172 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
\r
1174 vTaskMissedYield();
\r
1179 taskEXIT_CRITICAL();
\r
1181 /*-----------------------------------------------------------*/
\r
1183 static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue )
\r
1185 signed portBASE_TYPE xReturn;
\r
1187 taskENTER_CRITICAL();
\r
1188 xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );
\r
1189 taskEXIT_CRITICAL();
\r
1193 /*-----------------------------------------------------------*/
\r
1195 signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue )
\r
1197 signed portBASE_TYPE xReturn;
\r
1199 xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );
\r
1203 /*-----------------------------------------------------------*/
\r
1205 static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue )
\r
1207 signed portBASE_TYPE xReturn;
\r
1209 taskENTER_CRITICAL();
\r
1210 xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );
\r
1211 taskEXIT_CRITICAL();
\r
1215 /*-----------------------------------------------------------*/
\r
1217 signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue )
\r
1219 signed portBASE_TYPE xReturn;
\r
1221 xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );
\r
1225 /*-----------------------------------------------------------*/
\r
1227 #if configUSE_CO_ROUTINES == 1
\r
1228 signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )
\r
1230 signed portBASE_TYPE xReturn;
\r
1232 /* If the queue is already full we may have to block. A critical section
\r
1233 is required to prevent an interrupt removing something from the queue
\r
1234 between the check to see if the queue is full and blocking on the queue. */
\r
1235 portDISABLE_INTERRUPTS();
\r
1237 if( prvIsQueueFull( pxQueue ) )
\r
1239 /* The queue is full - do we want to block or just leave without
\r
1241 if( xTicksToWait > ( portTickType ) 0 )
\r
1243 /* As this is called from a coroutine we cannot block directly, but
\r
1244 return indicating that we need to block. */
\r
1245 vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToSend ) );
\r
1246 portENABLE_INTERRUPTS();
\r
1247 return errQUEUE_BLOCKED;
\r
1251 portENABLE_INTERRUPTS();
\r
1252 return errQUEUE_FULL;
\r
1256 portENABLE_INTERRUPTS();
\r
1260 portDISABLE_INTERRUPTS();
\r
1262 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
\r
1264 /* There is room in the queue, copy the data into the queue. */
\r
1265 prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );
\r
1268 /* Were any co-routines waiting for data to become available? */
\r
1269 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
\r
1271 /* In this instance the co-routine could be placed directly
\r
1272 into the ready list as we are within a critical section.
\r
1273 Instead the same pending ready list mechanism is used as if
\r
1274 the event were caused from within an interrupt. */
\r
1275 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
\r
1277 /* The co-routine waiting has a higher priority so record
\r
1278 that a yield might be appropriate. */
\r
1279 xReturn = errQUEUE_YIELD;
\r
1285 xReturn = errQUEUE_FULL;
\r
1288 portENABLE_INTERRUPTS();
\r
1293 /*-----------------------------------------------------------*/
\r
1295 #if configUSE_CO_ROUTINES == 1
\r
1296 signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait )
\r
1298 signed portBASE_TYPE xReturn;
\r
1300 /* If the queue is already empty we may have to block. A critical section
\r
1301 is required to prevent an interrupt adding something to the queue
\r
1302 between the check to see if the queue is empty and blocking on the queue. */
\r
1303 portDISABLE_INTERRUPTS();
\r
1305 if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 )
\r
1307 /* There are no messages in the queue, do we want to block or just
\r
1308 leave with nothing? */
\r
1309 if( xTicksToWait > ( portTickType ) 0 )
\r
1311 /* As this is a co-routine we cannot block directly, but return
\r
1312 indicating that we need to block. */
\r
1313 vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToReceive ) );
\r
1314 portENABLE_INTERRUPTS();
\r
1315 return errQUEUE_BLOCKED;
\r
1319 portENABLE_INTERRUPTS();
\r
1320 return errQUEUE_FULL;
\r
1324 portENABLE_INTERRUPTS();
\r
1328 portDISABLE_INTERRUPTS();
\r
1330 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
\r
1332 /* Data is available from the queue. */
\r
1333 pxQueue->pcReadFrom += pxQueue->uxItemSize;
\r
1334 if( pxQueue->pcReadFrom >= pxQueue->pcTail )
\r
1336 pxQueue->pcReadFrom = pxQueue->pcHead;
\r
1338 --( pxQueue->uxMessagesWaiting );
\r
1339 memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
\r
1343 /* Were any co-routines waiting for space to become available? */
\r
1344 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
\r
1346 /* In this instance the co-routine could be placed directly
\r
1347 into the ready list as we are within a critical section.
\r
1348 Instead the same pending ready list mechanism is used as if
\r
1349 the event were caused from within an interrupt. */
\r
1350 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
\r
1352 xReturn = errQUEUE_YIELD;
\r
1361 portENABLE_INTERRUPTS();
\r
1366 /*-----------------------------------------------------------*/
\r
1370 #if configUSE_CO_ROUTINES == 1
\r
1371 signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken )
\r
1373 /* Cannot block within an ISR so if there is no space on the queue then
\r
1374 exit without doing anything. */
\r
1375 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
\r
1377 prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );
\r
1379 /* We only want to wake one co-routine per ISR, so check that a
\r
1380 co-routine has not already been woken. */
\r
1381 if( !xCoRoutinePreviouslyWoken )
\r
1383 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
\r
1385 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
\r
1393 return xCoRoutinePreviouslyWoken;
\r
1396 /*-----------------------------------------------------------*/
\r
1398 #if configUSE_CO_ROUTINES == 1
\r
1399 signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxCoRoutineWoken )
\r
1401 signed portBASE_TYPE xReturn;
\r
1403 /* We cannot block from an ISR, so check there is data available. If
\r
1404 not then just leave without doing anything. */
\r
1405 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
\r
1407 /* Copy the data from the queue. */
\r
1408 pxQueue->pcReadFrom += pxQueue->uxItemSize;
\r
1409 if( pxQueue->pcReadFrom >= pxQueue->pcTail )
\r
1411 pxQueue->pcReadFrom = pxQueue->pcHead;
\r
1413 --( pxQueue->uxMessagesWaiting );
\r
1414 memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
\r
1416 if( !( *pxCoRoutineWoken ) )
\r
1418 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
\r
1420 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
\r
1422 *pxCoRoutineWoken = pdTRUE;
\r
1437 /*-----------------------------------------------------------*/
\r