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
122 #if configUSE_CO_ROUTINES == 1
\r
123 signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken );
\r
124 signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );
\r
125 signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait );
\r
126 signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait );
\r
130 * Unlocks a queue locked by a call to prvLockQueue. Locking a queue does not
\r
131 * prevent an ISR from adding or removing items to the queue, but does prevent
\r
132 * an ISR from removing tasks from the queue event lists. If an ISR finds a
\r
133 * queue is locked it will instead increment the appropriate queue lock count
\r
134 * to indicate that a task may require unblocking. When the queue in unlocked
\r
135 * these lock counts are inspected, and the appropriate action taken.
\r
137 static void prvUnlockQueue( xQueueHandle pxQueue );
\r
140 * Uses a critical section to determine if there is any data in a queue.
\r
142 * @return pdTRUE if the queue contains no items, otherwise pdFALSE.
\r
144 static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue );
\r
147 * Uses a critical section to determine if there is any space in a queue.
\r
149 * @return pdTRUE if there is no space, otherwise pdFALSE;
\r
151 static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue );
\r
154 * Copies an item into the queue, either at the front of the queue or the
\r
155 * back of the queue.
\r
157 static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition );
\r
160 * Copies an item out of a queue.
\r
162 static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer );
\r
163 /*-----------------------------------------------------------*/
\r
166 * Macro to mark a queue as locked. Locking a queue prevents an ISR from
\r
167 * accessing the queue event lists.
\r
169 #define prvLockQueue( pxQueue ) \
\r
171 taskENTER_CRITICAL(); \
\r
172 ++( pxQueue->xRxLock ); \
\r
173 ++( pxQueue->xTxLock ); \
\r
174 taskEXIT_CRITICAL(); \
\r
176 /*-----------------------------------------------------------*/
\r
179 /*-----------------------------------------------------------
\r
180 * PUBLIC QUEUE MANAGEMENT API documented in queue.h
\r
181 *----------------------------------------------------------*/
\r
183 xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize )
\r
185 xQUEUE *pxNewQueue;
\r
186 size_t xQueueSizeInBytes;
\r
188 /* Allocate the new queue structure. */
\r
189 if( uxQueueLength > ( unsigned portBASE_TYPE ) 0 )
\r
191 pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );
\r
192 if( pxNewQueue != NULL )
\r
194 /* Create the list of pointers to queue items. The queue is one byte
\r
195 longer than asked for to make wrap checking easier/faster. */
\r
196 xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ) + ( size_t ) 1;
\r
198 pxNewQueue->pcHead = ( signed portCHAR * ) pvPortMalloc( xQueueSizeInBytes );
\r
199 if( pxNewQueue->pcHead != NULL )
\r
201 /* Initialise the queue members as described above where the
\r
202 queue type is defined. */
\r
203 pxNewQueue->pcTail = pxNewQueue->pcHead + ( uxQueueLength * uxItemSize );
\r
204 pxNewQueue->uxMessagesWaiting = 0;
\r
205 pxNewQueue->pcWriteTo = pxNewQueue->pcHead;
\r
206 pxNewQueue->pcReadFrom = pxNewQueue->pcHead + ( ( uxQueueLength - 1 ) * uxItemSize );
\r
207 pxNewQueue->uxLength = uxQueueLength;
\r
208 pxNewQueue->uxItemSize = uxItemSize;
\r
209 pxNewQueue->xRxLock = queueUNLOCKED;
\r
210 pxNewQueue->xTxLock = queueUNLOCKED;
\r
212 /* Likewise ensure the event queues start with the correct state. */
\r
213 vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );
\r
214 vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );
\r
216 traceQUEUE_CREATE( pxNewQueue );
\r
222 traceQUEUE_CREATE_FAILED();
\r
223 vPortFree( pxNewQueue );
\r
228 /* Will only reach here if we could not allocate enough memory or no memory
\r
232 /*-----------------------------------------------------------*/
\r
234 #if ( configUSE_MUTEXES == 1 )
\r
236 xQueueHandle xQueueCreateMutex( void )
\r
238 xQUEUE *pxNewQueue;
\r
240 /* Allocate the new queue structure. */
\r
241 pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );
\r
242 if( pxNewQueue != NULL )
\r
244 /* Information required for priority inheritance. */
\r
245 pxNewQueue->pxMutexHolder = NULL;
\r
246 pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX;
\r
248 /* Queues used as a mutex no data is actually copied into or out
\r
250 pxNewQueue->pcWriteTo = NULL;
\r
251 pxNewQueue->pcReadFrom = NULL;
\r
253 /* Each mutex has a length of 1 (like a binary semaphore) and
\r
254 an item size of 0 as nothing is actually copied into or out
\r
256 pxNewQueue->uxMessagesWaiting = 0;
\r
257 pxNewQueue->uxLength = 1;
\r
258 pxNewQueue->uxItemSize = 0;
\r
259 pxNewQueue->xRxLock = queueUNLOCKED;
\r
260 pxNewQueue->xTxLock = queueUNLOCKED;
\r
262 /* Ensure the event queues start with the correct state. */
\r
263 vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );
\r
264 vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );
\r
266 /* Start with the semaphore in the expected state. */
\r
267 xQueueGenericSend( pxNewQueue, NULL, 0, queueSEND_TO_BACK );
\r
269 traceCREATE_MUTEX( pxNewQueue );
\r
273 traceCREATE_MUTEX_FAILED();
\r
279 #endif /* configUSE_MUTEXES */
\r
280 /*-----------------------------------------------------------*/
\r
282 #if configUSE_RECURSIVE_MUTEXES == 1
\r
284 portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle pxMutex )
\r
286 portBASE_TYPE xReturn;
\r
288 /* If this is the task that holds the mutex then pxMutexHolder will not
\r
289 change outside of this task. If this task does not hold the mutex then
\r
290 pxMutexHolder can never coincidentally equal the tasks handle, and as
\r
291 this is the only condition we are interested in it does not matter if
\r
292 pxMutexHolder is accessed simultaneously by another task. Therefore no
\r
293 mutual exclusion is required to test the pxMutexHolder variable. */
\r
294 if( pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle() )
\r
296 /* uxRecursiveCallCount cannot be zero if pxMutexHolder is equal to
\r
297 the task handle, therefore no underflow check is required. Also,
\r
298 uxRecursiveCallCount is only modified by the mutex holder, and as
\r
299 there can only be one, no mutual exclusion is required to modify the
\r
300 uxRecursiveCallCount member. */
\r
301 ( pxMutex->uxRecursiveCallCount )--;
\r
303 /* Have we unwound the call count? */
\r
304 if( pxMutex->uxRecursiveCallCount == 0 )
\r
306 /* Return the mutex. This will automatically unblock any other
\r
307 task that might be waiting to access the mutex. */
\r
308 xQueueGenericSend( pxMutex, NULL, queueMUTEX_GIVE_BLOCK_TIME, queueSEND_TO_BACK );
\r
313 traceGIVE_MUTEX_RECURSIVE( pxMutex );
\r
317 /* We cannot give the mutex because we are not the holder. */
\r
320 traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex );
\r
326 #endif /* configUSE_RECURSIVE_MUTEXES */
\r
327 /*-----------------------------------------------------------*/
\r
329 #if configUSE_RECURSIVE_MUTEXES == 1
\r
331 portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle pxMutex, portTickType xBlockTime )
\r
333 portBASE_TYPE xReturn;
\r
335 /* Comments regarding mutual exclusion as per those within
\r
336 xQueueGiveMutexRecursive(). */
\r
338 if( pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle() )
\r
340 ( pxMutex->uxRecursiveCallCount )++;
\r
345 xReturn = xQueueGenericReceive( pxMutex, NULL, xBlockTime, pdFALSE );
\r
347 /* pdPASS will only be returned if we successfully obtained the mutex,
\r
348 we may have blocked to reach here. */
\r
349 if( xReturn == pdPASS )
\r
351 ( pxMutex->uxRecursiveCallCount )++;
\r
355 traceTAKE_MUTEX_RECURSIVE( pxMutex );
\r
360 #endif /* configUSE_RECURSIVE_MUTEXES */
\r
361 /*-----------------------------------------------------------*/
\r
363 #if configUSE_COUNTING_SEMAPHORES == 1
\r
365 xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount )
\r
367 xQueueHandle pxHandle;
\r
369 pxHandle = xQueueCreate( ( unsigned portBASE_TYPE ) uxCountValue, queueSEMAPHORE_QUEUE_ITEM_LENGTH );
\r
371 if( pxHandle != NULL )
\r
373 pxHandle->uxMessagesWaiting = uxInitialCount;
\r
375 traceCREATE_COUNTING_SEMAPHORE();
\r
379 traceCREATE_COUNTING_SEMAPHORE_FAILED();
\r
385 #endif /* configUSE_COUNTING_SEMAPHORES */
\r
386 /*-----------------------------------------------------------*/
\r
388 signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )
\r
390 signed portBASE_TYPE xReturn = pdPASS;
\r
391 xTimeOutType xTimeOut;
\r
393 /* Make sure other tasks do not access the queue. */
\r
396 /* Capture the current time status for future reference. */
\r
397 vTaskSetTimeOutState( &xTimeOut );
\r
399 /* It is important that this is the only thread/ISR that modifies the
\r
400 ready or delayed lists until xTaskResumeAll() is called. Places where
\r
401 the ready/delayed lists are modified include:
\r
403 + vTaskDelay() - Nothing can call vTaskDelay as the scheduler is
\r
404 suspended, vTaskDelay() cannot be called from an ISR.
\r
405 + vTaskPrioritySet() - Has a critical section around the access.
\r
406 + vTaskSwitchContext() - This will not get executed while the scheduler
\r
408 + prvCheckDelayedTasks() - This will not get executed while the
\r
409 scheduler is suspended.
\r
410 + xTaskCreate() - Has a critical section around the access.
\r
411 + vTaskResume() - Has a critical section around the access.
\r
412 + xTaskResumeAll() - Has a critical section around the access.
\r
413 + xTaskRemoveFromEventList - Checks to see if the scheduler is
\r
414 suspended. If so then the TCB being removed from the event is
\r
415 removed from the event and added to the xPendingReadyList.
\r
418 /* Make sure interrupts do not access the queue event list. */
\r
419 prvLockQueue( pxQueue );
\r
421 /* It is important that interrupts to not access the event list of the
\r
422 queue being modified here. Places where the event list is modified
\r
425 + xQueueGenericSendFromISR(). This checks the lock on the queue to see
\r
426 if it has access. If the queue is locked then the Tx lock count is
\r
427 incremented to signify that a task waiting for data can be made ready
\r
428 once the queue lock is removed. If the queue is not locked then
\r
429 a task can be moved from the event list, but will not be removed
\r
430 from the delayed list or placed in the ready list until the scheduler
\r
433 + xQueueReceiveFromISR(). As per xQueueGenericSendFromISR().
\r
436 /* If the queue is already full we may have to block. */
\r
439 if( prvIsQueueFull( pxQueue ) )
\r
441 /* The queue is full - do we want to block or just leave without
\r
443 if( xTicksToWait > ( portTickType ) 0 )
\r
445 /* We are going to place ourselves on the xTasksWaitingToSend event
\r
446 list, and will get woken should the delay expire, or space become
\r
447 available on the queue.
\r
449 As detailed above we do not require mutual exclusion on the event
\r
450 list as nothing else can modify it or the ready lists while we
\r
451 have the scheduler suspended and queue locked.
\r
453 It is possible that an ISR has removed data from the queue since we
\r
454 checked if any was available. If this is the case then the data
\r
455 will have been copied from the queue, and the queue variables
\r
456 updated, but the event list will not yet have been checked to see if
\r
457 anything is waiting as the queue is locked. */
\r
458 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
\r
460 /* Force a context switch now as we are blocked. We can do
\r
461 this from within a critical section as the task we are
\r
462 switching to has its own context. When we return here (i.e. we
\r
463 unblock) we will leave the critical section as normal.
\r
465 It is possible that an ISR has caused an event on an unrelated and
\r
466 unlocked queue. If this was the case then the event list for that
\r
467 queue will have been updated but the ready lists left unchanged -
\r
468 instead the readied task will have been added to the pending ready
\r
470 taskENTER_CRITICAL();
\r
472 traceBLOCKING_ON_QUEUE_SEND( pxQueue );
\r
474 /* We can safely unlock the queue and scheduler here as
\r
475 interrupts are disabled. We must not yield with anything
\r
476 locked, but we can yield from within a critical section.
\r
478 Tasks that have been placed on the pending ready list cannot
\r
479 be tasks that are waiting for events on this queue. See
\r
480 in comment xTaskRemoveFromEventList(). */
\r
481 prvUnlockQueue( pxQueue );
\r
483 /* Resuming the scheduler may cause a yield. If so then there
\r
484 is no point yielding again here. */
\r
485 if( !xTaskResumeAll() )
\r
490 /* We want to check to see if the queue is still full
\r
491 before leaving the critical section. This is to prevent
\r
492 this task placing an item into the queue due to an
\r
493 interrupt making space on the queue between critical
\r
494 sections (when there might be a higher priority task
\r
495 blocked on the queue that cannot run yet because the
\r
496 scheduler gets suspended). */
\r
497 if( pxQueue->uxMessagesWaiting == pxQueue->uxLength )
\r
499 /* We unblocked but there is no space in the queue,
\r
500 we probably timed out. */
\r
501 xReturn = errQUEUE_FULL;
\r
504 /* Before leaving the critical section we have to ensure
\r
505 exclusive access again. */
\r
507 prvLockQueue( pxQueue );
\r
509 taskEXIT_CRITICAL();
\r
513 /* If xReturn is errQUEUE_FULL then we unblocked when the queue
\r
514 was still full. Don't check it again now as it is possible that
\r
515 an interrupt has removed an item from the queue since we left the
\r
516 critical section and we don't want to write to the queue in case
\r
517 there is a task of higher priority blocked waiting for space to
\r
518 be available on the queue. If this is the case the higher priority
\r
519 task will execute when the scheduler is unsupended. */
\r
520 if( xReturn != errQUEUE_FULL )
\r
522 /* When we are here it is possible that we unblocked as space became
\r
523 available on the queue. It is also possible that an ISR posted to the
\r
524 queue since we left the critical section, so it may be that again there
\r
525 is no space. This would only happen if a task and ISR post onto the
\r
527 taskENTER_CRITICAL();
\r
529 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
\r
531 traceQUEUE_SEND( pxQueue );
\r
533 /* There is room in the queue, copy the data into the queue. */
\r
534 prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
\r
537 /* Update the TxLock count so prvUnlockQueue knows to check for
\r
538 tasks waiting for data to become available in the queue. */
\r
539 ++( pxQueue->xTxLock );
\r
543 xReturn = errQUEUE_FULL;
\r
546 taskEXIT_CRITICAL();
\r
549 if( xReturn == errQUEUE_FULL )
\r
551 if( xTicksToWait > 0 )
\r
553 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
\r
555 xReturn = queueERRONEOUS_UNBLOCK;
\r
559 traceQUEUE_SEND_FAILED( pxQueue );
\r
564 traceQUEUE_SEND_FAILED( pxQueue );
\r
568 while( xReturn == queueERRONEOUS_UNBLOCK );
\r
570 prvUnlockQueue( pxQueue );
\r
575 /*-----------------------------------------------------------*/
\r
577 #if configUSE_ALTERNATIVE_API == 1
\r
579 signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )
\r
581 signed portBASE_TYPE xReturn;
\r
582 xTimeOutType xTimeOut;
\r
584 /* The source code that implements the alternative (Alt) API is much
\r
585 simpler because it executes everything from within a critical section.
\r
586 This is the approach taken by many other RTOSes, but FreeRTOS.org has the
\r
587 preferred fully featured API too. The fully featured API has more
\r
588 complex code that takes longer to execute, but makes much less use of
\r
589 critical sections. Therefore the alternative API sacrifices interrupt
\r
590 responsiveness to gain execution speed, whereas the fully featured API
\r
591 sacrifices execution speed to ensure better interrupt responsiveness. */
\r
593 taskENTER_CRITICAL();
\r
595 /* Capture the current time status for future reference. */
\r
596 vTaskSetTimeOutState( &xTimeOut );
\r
598 /* If the queue is already full we may have to block. */
\r
601 if( pxQueue->uxMessagesWaiting == pxQueue->uxLength )
\r
603 /* The queue is full - do we want to block or just leave without
\r
605 if( xTicksToWait > ( portTickType ) 0 )
\r
607 traceBLOCKING_ON_QUEUE_SEND( pxQueue );
\r
609 /* We are going to place ourselves on the xTasksWaitingToSend
\r
610 event list, and will get woken should the delay expire, or
\r
611 space become available on the queue. */
\r
612 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
\r
614 /* Force a context switch now as we are blocked. We can do
\r
615 this from within a critical section as the task we are
\r
616 switching to has its own context. When we return here (i.e.
\r
617 we unblock) we will leave the critical section as normal. */
\r
622 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
\r
624 traceQUEUE_SEND( pxQueue );
\r
626 /* There is room in the queue, copy the data into the queue. */
\r
627 prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
\r
630 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
\r
632 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
\r
634 /* The task waiting has a higher priority. */
\r
641 xReturn = errQUEUE_FULL;
\r
643 if( xTicksToWait > 0 )
\r
645 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
\r
647 /* Another task must have accessed the queue between
\r
648 this task unblocking and actually executing. */
\r
649 xReturn = queueERRONEOUS_UNBLOCK;
\r
653 traceQUEUE_SEND_FAILED( pxQueue );
\r
658 traceQUEUE_SEND_FAILED( pxQueue );
\r
662 while( xReturn == queueERRONEOUS_UNBLOCK );
\r
664 taskEXIT_CRITICAL();
\r
669 #endif /* configUSE_ALTERNATIVE_API */
\r
670 /*-----------------------------------------------------------*/
\r
672 #if configUSE_ALTERNATIVE_API == 1
\r
674 signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, const void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )
\r
676 signed portBASE_TYPE xReturn = pdTRUE;
\r
677 xTimeOutType xTimeOut;
\r
678 signed portCHAR *pcOriginalReadPosition;
\r
680 /* The source code that implements the alternative (Alt) API is much
\r
681 simpler because it executes everything from within a critical section.
\r
682 This is the approach taken by many other RTOSes, but FreeRTOS.org has the
\r
683 preferred fully featured API too. The fully featured API has more
\r
684 complex code that takes longer to execute, but makes much less use of
\r
685 critical sections. Therefore the alternative API sacrifices interrupt
\r
686 responsiveness to gain execution speed, whereas the fully featured API
\r
687 sacrifices execution speed to ensure better interrupt responsiveness. */
\r
689 taskENTER_CRITICAL();
\r
691 /* Capture the current time status for future reference. */
\r
692 vTaskSetTimeOutState( &xTimeOut );
\r
696 /* If there are no messages in the queue we may have to block. */
\r
697 if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 )
\r
699 /* There are no messages in the queue, do we want to block or just
\r
700 leave with nothing? */
\r
701 if( xTicksToWait > ( portTickType ) 0 )
\r
703 traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
\r
705 #if ( configUSE_MUTEXES == 1 )
\r
707 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
\r
709 vTaskPriorityInherit( ( void * const ) pxQueue->pxMutexHolder );
\r
714 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
\r
719 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
\r
721 /* Remember our read position in case we are just peeking. */
\r
722 pcOriginalReadPosition = pxQueue->pcReadFrom;
\r
724 prvCopyDataFromQueue( pxQueue, pvBuffer );
\r
726 if( xJustPeeking == pdFALSE )
\r
728 traceQUEUE_RECEIVE( pxQueue );
\r
730 /* We are actually removing data. */
\r
731 --( pxQueue->uxMessagesWaiting );
\r
733 #if ( configUSE_MUTEXES == 1 )
\r
735 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
\r
737 /* Record the information required to implement
\r
738 priority inheritance should it become necessary. */
\r
739 pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();
\r
744 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
\r
746 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
\r
748 /* The task waiting has a higher priority. */
\r
755 traceQUEUE_PEEK( pxQueue );
\r
757 /* We are not removing the data, so reset our read
\r
759 pxQueue->pcReadFrom = pcOriginalReadPosition;
\r
766 xReturn = errQUEUE_EMPTY;
\r
768 if( xTicksToWait > 0 )
\r
770 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
\r
772 xReturn = queueERRONEOUS_UNBLOCK;
\r
776 traceQUEUE_RECEIVE_FAILED( pxQueue );
\r
781 traceQUEUE_RECEIVE_FAILED( pxQueue );
\r
785 } while( xReturn == queueERRONEOUS_UNBLOCK );
\r
787 taskEXIT_CRITICAL();
\r
792 #endif /* configUSE_ALTERNATIVE_API */
\r
793 /*-----------------------------------------------------------*/
\r
795 signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken, portBASE_TYPE xCopyPosition )
\r
797 /* Similar to xQueueGenericSend, except we don't block if there is no room
\r
798 in the queue. Also we don't directly wake a task that was blocked on a
\r
799 queue read, instead we return a flag to say whether a context switch is
\r
800 required or not (i.e. has a task with a higher priority than us been woken
\r
802 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
\r
804 traceQUEUE_SEND_FROM_ISR( pxQueue );
\r
806 prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
\r
808 /* If the queue is locked we do not alter the event list. This will
\r
809 be done when the queue is unlocked later. */
\r
810 if( pxQueue->xTxLock == queueUNLOCKED )
\r
812 /* We only want to wake one task per ISR, so check that a task has
\r
813 not already been woken. */
\r
814 if( !xTaskPreviouslyWoken )
\r
816 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
\r
818 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
\r
820 /* The task waiting has a higher priority so record that a
\r
821 context switch is required. */
\r
829 /* Increment the lock count so the task that unlocks the queue
\r
830 knows that data was posted while it was locked. */
\r
831 ++( pxQueue->xTxLock );
\r
836 traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue );
\r
839 return xTaskPreviouslyWoken;
\r
841 /*-----------------------------------------------------------*/
\r
843 signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, const void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )
\r
845 signed portBASE_TYPE xReturn = pdTRUE;
\r
846 xTimeOutType xTimeOut;
\r
847 signed portCHAR *pcOriginalReadPosition;
\r
849 /* This function is very similar to xQueueGenericSend(). See comments
\r
850 within xQueueGenericSend() for a more detailed explanation.
\r
852 Make sure other tasks do not access the queue. */
\r
855 /* Capture the current time status for future reference. */
\r
856 vTaskSetTimeOutState( &xTimeOut );
\r
858 /* Make sure interrupts do not access the queue. */
\r
859 prvLockQueue( pxQueue );
\r
863 /* If there are no messages in the queue we may have to block. */
\r
864 if( prvIsQueueEmpty( pxQueue ) )
\r
866 /* There are no messages in the queue, do we want to block or just
\r
867 leave with nothing? */
\r
868 if( xTicksToWait > ( portTickType ) 0 )
\r
870 traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
\r
872 #if ( configUSE_MUTEXES == 1 )
\r
874 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
\r
876 portENTER_CRITICAL();
\r
877 vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );
\r
878 portEXIT_CRITICAL();
\r
883 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
\r
884 taskENTER_CRITICAL();
\r
886 prvUnlockQueue( pxQueue );
\r
887 if( !xTaskResumeAll() )
\r
892 if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 )
\r
894 /* We unblocked but the queue is empty. We probably
\r
896 xReturn = errQUEUE_EMPTY;
\r
900 prvLockQueue( pxQueue );
\r
902 taskEXIT_CRITICAL();
\r
906 if( xReturn != errQUEUE_EMPTY )
\r
908 taskENTER_CRITICAL();
\r
910 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
\r
912 /* Remember our read position in case we are just peeking. */
\r
913 pcOriginalReadPosition = pxQueue->pcReadFrom;
\r
915 prvCopyDataFromQueue( pxQueue, pvBuffer );
\r
917 if( xJustPeeking == pdFALSE )
\r
919 traceQUEUE_RECEIVE( pxQueue );
\r
921 /* We are actually removing data. */
\r
922 --( pxQueue->uxMessagesWaiting );
\r
924 /* Increment the lock count so prvUnlockQueue knows to check for
\r
925 tasks waiting for space to become available on the queue. */
\r
926 ++( pxQueue->xRxLock );
\r
928 #if ( configUSE_MUTEXES == 1 )
\r
930 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
\r
932 /* Record the information required to implement
\r
933 priority inheritance should it become necessary. */
\r
934 pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();
\r
941 traceQUEUE_PEEK( pxQueue );
\r
943 /* We are not removing the data, so reset our read
\r
945 pxQueue->pcReadFrom = pcOriginalReadPosition;
\r
947 /* The data is being left in the queue, so increment the
\r
948 lock count so prvUnlockQueue knows to check for other
\r
949 tasks waiting for the data to be available. */
\r
950 ++( pxQueue->xTxLock );
\r
957 xReturn = errQUEUE_EMPTY;
\r
960 taskEXIT_CRITICAL();
\r
963 if( xReturn == errQUEUE_EMPTY )
\r
965 if( xTicksToWait > 0 )
\r
967 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
\r
969 xReturn = queueERRONEOUS_UNBLOCK;
\r
973 traceQUEUE_RECEIVE_FAILED( pxQueue );
\r
978 traceQUEUE_RECEIVE_FAILED( pxQueue );
\r
981 } while( xReturn == queueERRONEOUS_UNBLOCK );
\r
983 /* We no longer require exclusive access to the queue. */
\r
984 prvUnlockQueue( pxQueue );
\r
989 /*-----------------------------------------------------------*/
\r
991 signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, const void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken )
\r
993 signed portBASE_TYPE xReturn;
\r
995 /* We cannot block from an ISR, so check there is data available. */
\r
996 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
\r
998 traceQUEUE_RECEIVE_FROM_ISR( pxQueue );
\r
1000 prvCopyDataFromQueue( pxQueue, pvBuffer );
\r
1001 --( pxQueue->uxMessagesWaiting );
\r
1003 /* If the queue is locked we will not modify the event list. Instead
\r
1004 we update the lock count so the task that unlocks the queue will know
\r
1005 that an ISR has removed data while the queue was locked. */
\r
1006 if( pxQueue->xRxLock == queueUNLOCKED )
\r
1008 /* We only want to wake one task per ISR, so check that a task has
\r
1009 not already been woken. */
\r
1010 if( !( *pxTaskWoken ) )
\r
1012 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
\r
1014 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
\r
1016 /* The task waiting has a higher priority than us so
\r
1017 force a context switch. */
\r
1018 *pxTaskWoken = pdTRUE;
\r
1025 /* Increment the lock count so the task that unlocks the queue
\r
1026 knows that data was removed while it was locked. */
\r
1027 ++( pxQueue->xRxLock );
\r
1035 traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue );
\r
1040 /*-----------------------------------------------------------*/
\r
1042 unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle pxQueue )
\r
1044 unsigned portBASE_TYPE uxReturn;
\r
1046 taskENTER_CRITICAL();
\r
1047 uxReturn = pxQueue->uxMessagesWaiting;
\r
1048 taskEXIT_CRITICAL();
\r
1052 /*-----------------------------------------------------------*/
\r
1054 void vQueueDelete( xQueueHandle pxQueue )
\r
1056 traceQUEUE_DELETE( pxQueue );
\r
1058 vPortFree( pxQueue->pcHead );
\r
1059 vPortFree( pxQueue );
\r
1061 /*-----------------------------------------------------------*/
\r
1063 static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition )
\r
1065 if( pxQueue->uxItemSize == 0 )
\r
1067 #if ( configUSE_MUTEXES == 1 )
\r
1069 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
\r
1071 /* The mutex is no longer being held. */
\r
1072 vTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder );
\r
1073 pxQueue->pxMutexHolder = NULL;
\r
1078 else if( xPosition == queueSEND_TO_BACK )
\r
1080 memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );
\r
1081 pxQueue->pcWriteTo += pxQueue->uxItemSize;
\r
1082 if( pxQueue->pcWriteTo >= pxQueue->pcTail )
\r
1084 pxQueue->pcWriteTo = pxQueue->pcHead;
\r
1089 memcpy( ( void * ) pxQueue->pcReadFrom, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );
\r
1090 pxQueue->pcReadFrom -= pxQueue->uxItemSize;
\r
1091 if( pxQueue->pcReadFrom < pxQueue->pcHead )
\r
1093 pxQueue->pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize );
\r
1097 ++( pxQueue->uxMessagesWaiting );
\r
1099 /*-----------------------------------------------------------*/
\r
1101 static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer )
\r
1103 if( pxQueue->uxQueueType != queueQUEUE_IS_MUTEX )
\r
1105 pxQueue->pcReadFrom += pxQueue->uxItemSize;
\r
1106 if( pxQueue->pcReadFrom >= pxQueue->pcTail )
\r
1108 pxQueue->pcReadFrom = pxQueue->pcHead;
\r
1110 memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
\r
1113 /*-----------------------------------------------------------*/
\r
1115 static void prvUnlockQueue( xQueueHandle pxQueue )
\r
1117 /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */
\r
1119 /* The lock counts contains the number of extra data items placed or
\r
1120 removed from the queue while the queue was locked. When a queue is
\r
1121 locked items can be added or removed, but the event lists cannot be
\r
1123 taskENTER_CRITICAL();
\r
1125 --( pxQueue->xTxLock );
\r
1127 /* See if data was added to the queue while it was locked. */
\r
1128 if( pxQueue->xTxLock > queueUNLOCKED )
\r
1130 pxQueue->xTxLock = queueUNLOCKED;
\r
1132 /* Data was posted while the queue was locked. Are any tasks
\r
1133 blocked waiting for data to become available? */
\r
1134 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
\r
1136 /* Tasks that are removed from the event list will get added to
\r
1137 the pending ready list as the scheduler is still suspended. */
\r
1138 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
\r
1140 /* The task waiting has a higher priority so record that a
\r
1141 context switch is required. */
\r
1142 vTaskMissedYield();
\r
1147 taskEXIT_CRITICAL();
\r
1149 /* Do the same for the Rx lock. */
\r
1150 taskENTER_CRITICAL();
\r
1152 --( pxQueue->xRxLock );
\r
1154 if( pxQueue->xRxLock > queueUNLOCKED )
\r
1156 pxQueue->xRxLock = queueUNLOCKED;
\r
1158 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
\r
1160 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
\r
1162 vTaskMissedYield();
\r
1167 taskEXIT_CRITICAL();
\r
1169 /*-----------------------------------------------------------*/
\r
1171 static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue )
\r
1173 signed portBASE_TYPE xReturn;
\r
1175 taskENTER_CRITICAL();
\r
1176 xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );
\r
1177 taskEXIT_CRITICAL();
\r
1181 /*-----------------------------------------------------------*/
\r
1183 static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue )
\r
1185 signed portBASE_TYPE xReturn;
\r
1187 taskENTER_CRITICAL();
\r
1188 xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );
\r
1189 taskEXIT_CRITICAL();
\r
1193 /*-----------------------------------------------------------*/
\r
1195 #if configUSE_CO_ROUTINES == 1
\r
1196 signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )
\r
1198 signed portBASE_TYPE xReturn;
\r
1200 /* If the queue is already full we may have to block. A critical section
\r
1201 is required to prevent an interrupt removing something from the queue
\r
1202 between the check to see if the queue is full and blocking on the queue. */
\r
1203 portDISABLE_INTERRUPTS();
\r
1205 if( prvIsQueueFull( pxQueue ) )
\r
1207 /* The queue is full - do we want to block or just leave without
\r
1209 if( xTicksToWait > ( portTickType ) 0 )
\r
1211 /* As this is called from a coroutine we cannot block directly, but
\r
1212 return indicating that we need to block. */
\r
1213 vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToSend ) );
\r
1214 portENABLE_INTERRUPTS();
\r
1215 return errQUEUE_BLOCKED;
\r
1219 portENABLE_INTERRUPTS();
\r
1220 return errQUEUE_FULL;
\r
1224 portENABLE_INTERRUPTS();
\r
1228 portDISABLE_INTERRUPTS();
\r
1230 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
\r
1232 /* There is room in the queue, copy the data into the queue. */
\r
1233 prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );
\r
1236 /* Were any co-routines waiting for data to become available? */
\r
1237 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
\r
1239 /* In this instance the co-routine could be placed directly
\r
1240 into the ready list as we are within a critical section.
\r
1241 Instead the same pending ready list mechanism is used as if
\r
1242 the event were caused from within an interrupt. */
\r
1243 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
\r
1245 /* The co-routine waiting has a higher priority so record
\r
1246 that a yield might be appropriate. */
\r
1247 xReturn = errQUEUE_YIELD;
\r
1253 xReturn = errQUEUE_FULL;
\r
1256 portENABLE_INTERRUPTS();
\r
1261 /*-----------------------------------------------------------*/
\r
1263 #if configUSE_CO_ROUTINES == 1
\r
1264 signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait )
\r
1266 signed portBASE_TYPE xReturn;
\r
1268 /* If the queue is already empty we may have to block. A critical section
\r
1269 is required to prevent an interrupt adding something to the queue
\r
1270 between the check to see if the queue is empty and blocking on the queue. */
\r
1271 portDISABLE_INTERRUPTS();
\r
1273 if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 )
\r
1275 /* There are no messages in the queue, do we want to block or just
\r
1276 leave with nothing? */
\r
1277 if( xTicksToWait > ( portTickType ) 0 )
\r
1279 /* As this is a co-routine we cannot block directly, but return
\r
1280 indicating that we need to block. */
\r
1281 vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToReceive ) );
\r
1282 portENABLE_INTERRUPTS();
\r
1283 return errQUEUE_BLOCKED;
\r
1287 portENABLE_INTERRUPTS();
\r
1288 return errQUEUE_FULL;
\r
1292 portENABLE_INTERRUPTS();
\r
1296 portDISABLE_INTERRUPTS();
\r
1298 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
\r
1300 /* Data is available from the queue. */
\r
1301 pxQueue->pcReadFrom += pxQueue->uxItemSize;
\r
1302 if( pxQueue->pcReadFrom >= pxQueue->pcTail )
\r
1304 pxQueue->pcReadFrom = pxQueue->pcHead;
\r
1306 --( pxQueue->uxMessagesWaiting );
\r
1307 memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
\r
1311 /* Were any co-routines waiting for space to become available? */
\r
1312 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
\r
1314 /* In this instance the co-routine could be placed directly
\r
1315 into the ready list as we are within a critical section.
\r
1316 Instead the same pending ready list mechanism is used as if
\r
1317 the event were caused from within an interrupt. */
\r
1318 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
\r
1320 xReturn = errQUEUE_YIELD;
\r
1329 portENABLE_INTERRUPTS();
\r
1334 /*-----------------------------------------------------------*/
\r
1338 #if configUSE_CO_ROUTINES == 1
\r
1339 signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken )
\r
1341 /* Cannot block within an ISR so if there is no space on the queue then
\r
1342 exit without doing anything. */
\r
1343 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
\r
1345 prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );
\r
1347 /* We only want to wake one co-routine per ISR, so check that a
\r
1348 co-routine has not already been woken. */
\r
1349 if( !xCoRoutinePreviouslyWoken )
\r
1351 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
\r
1353 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
\r
1361 return xCoRoutinePreviouslyWoken;
\r
1364 /*-----------------------------------------------------------*/
\r
1366 #if configUSE_CO_ROUTINES == 1
\r
1367 signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxCoRoutineWoken )
\r
1369 signed portBASE_TYPE xReturn;
\r
1371 /* We cannot block from an ISR, so check there is data available. If
\r
1372 not then just leave without doing anything. */
\r
1373 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
\r
1375 /* Copy the data from the queue. */
\r
1376 pxQueue->pcReadFrom += pxQueue->uxItemSize;
\r
1377 if( pxQueue->pcReadFrom >= pxQueue->pcTail )
\r
1379 pxQueue->pcReadFrom = pxQueue->pcHead;
\r
1381 --( pxQueue->uxMessagesWaiting );
\r
1382 memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
\r
1384 if( !( *pxCoRoutineWoken ) )
\r
1386 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
\r
1388 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
\r
1390 *pxCoRoutineWoken = pdTRUE;
\r
1405 /*-----------------------------------------------------------*/
\r