]> git.sur5r.net Git - freertos/blob - Source/queue.c
Small mods, and update file headers.
[freertos] / Source / queue.c
1 /*\r
2         FreeRTOS.org V4.8.0 - Copyright (C) 2003-2008 Richard Barry.\r
3 \r
4         This file is part of the FreeRTOS.org distribution.\r
5 \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
10 \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
15 \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
19 \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
24         can be applied.\r
25 \r
26     ***************************************************************************\r
27     ***************************************************************************\r
28     *                                                                         *\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
33     *                                                                         *\r
34     ***************************************************************************\r
35     ***************************************************************************\r
36 \r
37         Please ensure to read the configuration and relevant port sections of the\r
38         online documentation.\r
39 \r
40         http://www.FreeRTOS.org - Documentation, latest information, license and \r
41         contact details.\r
42 \r
43         http://www.SafeRTOS.com - A version that is certified for use in safety \r
44         critical systems.\r
45 \r
46         http://www.OpenRTOS.com - Commercial support, development, porting, \r
47         licensing and training services.\r
48 */\r
49 \r
50 #include <stdlib.h>\r
51 #include <string.h>\r
52 #include "FreeRTOS.h"\r
53 #include "task.h"\r
54 #include "croutine.h"\r
55 \r
56 /*-----------------------------------------------------------\r
57  * PUBLIC LIST API documented in list.h\r
58  *----------------------------------------------------------*/\r
59 \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
63 \r
64 /* For internal use only. */\r
65 #define queueSEND_TO_BACK       ( 0 )\r
66 #define queueSEND_TO_FRONT      ( 1 )\r
67 \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
73 \r
74 /* Semaphores do not actually store or copy data, so have an items size of\r
75 zero. */\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
79 /*\r
80  * Definition of the queue used by the scheduler.\r
81  * Items are queued by copy, not reference.\r
82  */\r
83 typedef struct QueueDefinition\r
84 {\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
87 \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
90 \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
93 \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
97 \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
100 } xQUEUE;\r
101 /*-----------------------------------------------------------*/\r
102 \r
103 /*\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
106  * pointer to void.\r
107  */\r
108 typedef xQUEUE * xQueueHandle;\r
109 \r
110 /*\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
114  */\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
131 \r
132 \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
138 #endif\r
139 \r
140 /*\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
147  */\r
148 static void prvUnlockQueue( xQueueHandle pxQueue );\r
149 \r
150 /*\r
151  * Uses a critical section to determine if there is any data in a queue.\r
152  *\r
153  * @return pdTRUE if the queue contains no items, otherwise pdFALSE.\r
154  */\r
155 static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue );\r
156 \r
157 /*\r
158  * Uses a critical section to determine if there is any space in a queue.\r
159  *\r
160  * @return pdTRUE if there is no space, otherwise pdFALSE;\r
161  */\r
162 static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue );\r
163 \r
164 /*\r
165  * Copies an item into the queue, either at the front of the queue or the\r
166  * back of the queue.\r
167  */\r
168 static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition );\r
169 \r
170 /*\r
171  * Copies an item out of a queue.\r
172  */\r
173 static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer );\r
174 /*-----------------------------------------------------------*/\r
175 \r
176 /*\r
177  * Macro to mark a queue as locked.  Locking a queue prevents an ISR from\r
178  * accessing the queue event lists.\r
179  */\r
180 #define prvLockQueue( pxQueue )                 \\r
181 {                                                                               \\r
182         taskENTER_CRITICAL();                           \\r
183                 ++( pxQueue->xRxLock );                 \\r
184                 ++( pxQueue->xTxLock );                 \\r
185         taskEXIT_CRITICAL();                            \\r
186 }\r
187 /*-----------------------------------------------------------*/\r
188 \r
189 \r
190 /*-----------------------------------------------------------\r
191  * PUBLIC QUEUE MANAGEMENT API documented in queue.h\r
192  *----------------------------------------------------------*/\r
193 \r
194 xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize )\r
195 {\r
196 xQUEUE *pxNewQueue;\r
197 size_t xQueueSizeInBytes;\r
198 \r
199         /* Allocate the new queue structure. */\r
200         if( uxQueueLength > ( unsigned portBASE_TYPE ) 0 )\r
201         {\r
202                 pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );\r
203                 if( pxNewQueue != NULL )\r
204                 {\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
208 \r
209                         pxNewQueue->pcHead = ( signed portCHAR * ) pvPortMalloc( xQueueSizeInBytes );\r
210                         if( pxNewQueue->pcHead != NULL )\r
211                         {\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
222 \r
223                                 /* Likewise ensure the event queues start with the correct state. */\r
224                                 vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );\r
225                                 vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );\r
226 \r
227                                 traceQUEUE_CREATE( pxNewQueue );\r
228 \r
229                                 return  pxNewQueue;\r
230                         }\r
231                         else\r
232                         {\r
233                                 traceQUEUE_CREATE_FAILED();\r
234                                 vPortFree( pxNewQueue );\r
235                         }\r
236                 }\r
237         }\r
238 \r
239         /* Will only reach here if we could not allocate enough memory or no memory\r
240         was required. */\r
241         return NULL;\r
242 }\r
243 /*-----------------------------------------------------------*/\r
244 \r
245 #if ( configUSE_MUTEXES == 1 )\r
246 \r
247         xQueueHandle xQueueCreateMutex( void )\r
248         {\r
249         xQUEUE *pxNewQueue;\r
250         \r
251                 /* Allocate the new queue structure. */\r
252                 pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );\r
253                 if( pxNewQueue != NULL )\r
254                 {\r
255                         /* Information required for priority inheritance. */\r
256                         pxNewQueue->pxMutexHolder = NULL;\r
257                         pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX;\r
258         \r
259                         /* Queues used as a mutex no data is actually copied into or out\r
260                         of the queue. */\r
261                         pxNewQueue->pcWriteTo = NULL;\r
262                         pxNewQueue->pcReadFrom = NULL;\r
263                         \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
266                         of the mutex. */\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
272         \r
273                         /* Ensure the event queues start with the correct state. */\r
274                         vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );\r
275                         vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );\r
276 \r
277                         /* Start with the semaphore in the expected state. */\r
278                         xQueueGenericSend( pxNewQueue, NULL, 0, queueSEND_TO_BACK );\r
279 \r
280                         traceCREATE_MUTEX( pxNewQueue );\r
281                 }\r
282                 else\r
283                 {\r
284                         traceCREATE_MUTEX_FAILED();\r
285                 }\r
286         \r
287                 return pxNewQueue;\r
288         }\r
289 \r
290 #endif /* configUSE_MUTEXES */\r
291 /*-----------------------------------------------------------*/\r
292 \r
293 #if configUSE_RECURSIVE_MUTEXES == 1\r
294 \r
295         portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle pxMutex )\r
296         {\r
297         portBASE_TYPE xReturn;\r
298 \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
306                 {\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
313 \r
314                         /* Have we unwound the call count? */\r
315                         if( pxMutex->uxRecursiveCallCount == 0 )\r
316                         {\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
320                         }\r
321 \r
322                         xReturn = pdPASS;\r
323 \r
324                         traceGIVE_MUTEX_RECURSIVE( pxMutex );\r
325                 }\r
326                 else\r
327                 {\r
328                         /* We cannot give the mutex because we are not the holder. */\r
329                         xReturn = pdFAIL;\r
330 \r
331                         traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex );\r
332                 }\r
333 \r
334                 return xReturn;\r
335         }\r
336 \r
337 #endif /* configUSE_RECURSIVE_MUTEXES */\r
338 /*-----------------------------------------------------------*/\r
339 \r
340 #if configUSE_RECURSIVE_MUTEXES == 1\r
341 \r
342         portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle pxMutex, portTickType xBlockTime )\r
343         {\r
344         portBASE_TYPE xReturn;\r
345 \r
346                 /* Comments regarding mutual exclusion as per those within\r
347                 xQueueGiveMutexRecursive(). */\r
348 \r
349                 if( pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle() )\r
350                 {\r
351                         ( pxMutex->uxRecursiveCallCount )++;\r
352                         xReturn = pdPASS;\r
353                 }\r
354                 else\r
355                 {\r
356             xReturn = xQueueGenericReceive( pxMutex, NULL, xBlockTime, pdFALSE );\r
357 \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
361                         {\r
362                                 ( pxMutex->uxRecursiveCallCount )++;\r
363                         }\r
364                 }\r
365 \r
366                 traceTAKE_MUTEX_RECURSIVE( pxMutex );\r
367 \r
368                 return xReturn;\r
369         }\r
370 \r
371 #endif /* configUSE_RECURSIVE_MUTEXES */\r
372 /*-----------------------------------------------------------*/\r
373 \r
374 #if configUSE_COUNTING_SEMAPHORES == 1\r
375 \r
376         xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount )\r
377         {\r
378         xQueueHandle pxHandle;\r
379         \r
380                 pxHandle = xQueueCreate( ( unsigned portBASE_TYPE ) uxCountValue, queueSEMAPHORE_QUEUE_ITEM_LENGTH );\r
381 \r
382                 if( pxHandle != NULL )\r
383                 {\r
384                         pxHandle->uxMessagesWaiting = uxInitialCount;\r
385 \r
386                         traceCREATE_COUNTING_SEMAPHORE();\r
387                 }\r
388                 else\r
389                 {\r
390                         traceCREATE_COUNTING_SEMAPHORE_FAILED();\r
391                 }\r
392 \r
393                 return pxHandle;\r
394         }\r
395 \r
396 #endif /* configUSE_COUNTING_SEMAPHORES */\r
397 /*-----------------------------------------------------------*/\r
398 \r
399 signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )\r
400 {\r
401 signed portBASE_TYPE xReturn = pdTRUE;\r
402 xTimeOutType xTimeOut;\r
403 \r
404         do\r
405         {\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
409                 {\r
410                         vTaskSuspendAll();\r
411                         prvLockQueue( pxQueue );\r
412 \r
413                         if( xReturn == pdTRUE )\r
414                         {\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
419                         }\r
420 \r
421                         if( prvIsQueueFull( pxQueue ) )\r
422                         {\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
427                                 {\r
428                                         traceBLOCKING_ON_QUEUE_SEND( pxQueue );\r
429                                         vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );\r
430                                                 \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
437                                                 \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
444                                         {\r
445                                                 taskYIELD();\r
446                                         }\r
447                                 }\r
448                                 else\r
449                                 {\r
450                                         prvUnlockQueue( pxQueue );\r
451                                         ( void ) xTaskResumeAll();\r
452                                 }\r
453                         }\r
454                         else\r
455                         {\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
460                         }\r
461                 }\r
462                         \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
466                 \r
467                 taskENTER_CRITICAL();\r
468                 {\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
472                         {\r
473                                 traceQUEUE_SEND( pxQueue );\r
474                                 prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );\r
475                                 xReturn = pdPASS;\r
476                                         \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
480                                 {\r
481                                         if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )\r
482                                         {\r
483                                             /* The unblocked task has a priority higher than\r
484                                             our own so yield immediately. */\r
485                                             taskYIELD();\r
486                                         }\r
487                                 }\r
488                         }\r
489                         else\r
490                         {\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
495                                 to the queue. */\r
496                                 xReturn = errQUEUE_FULL;\r
497                         }\r
498                 }\r
499                 taskEXIT_CRITICAL();\r
500 \r
501                 if( xReturn == errQUEUE_FULL )\r
502                 {\r
503                         if( xTicksToWait > ( portTickType ) 0 )\r
504                         {\r
505                                 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
506                                 {\r
507                                         xReturn = queueERRONEOUS_UNBLOCK;\r
508                                 }\r
509                                 else\r
510                                 {\r
511                                         traceQUEUE_SEND_FAILED( pxQueue );\r
512                                 }\r
513                         }\r
514                         else\r
515                         {\r
516                                 traceQUEUE_SEND_FAILED( pxQueue );\r
517                         }\r
518                 }\r
519         }\r
520         while( xReturn == queueERRONEOUS_UNBLOCK );\r
521 \r
522         return xReturn;\r
523 }\r
524 /*-----------------------------------------------------------*/\r
525 \r
526 #if configUSE_ALTERNATIVE_API == 1\r
527 \r
528         signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )\r
529         {\r
530         signed portBASE_TYPE xReturn = pdPASS;\r
531         xTimeOutType xTimeOut;\r
532 \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
539 \r
540                 do\r
541                 {\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
545                         {\r
546                                 portENTER_CRITICAL();\r
547                                 {\r
548                                         if( xReturn == pdPASS )\r
549                                         {\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
554                                         }\r
555                                         \r
556                                         if( prvIsQueueFull( pxQueue ) )\r
557                                         {\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
562                                                 {\r
563                                                         traceBLOCKING_ON_QUEUE_SEND( pxQueue );\r
564                                                         vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );\r
565 \r
566                                                         /* This will exit the critical section, then re-enter when\r
567                                                         the task next runs. */\r
568                                                         taskYIELD();\r
569                                                 }\r
570                                         }\r
571                                 }\r
572                                 portEXIT_CRITICAL();\r
573                         }\r
574                                 \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
578                         \r
579                         taskENTER_CRITICAL();\r
580                         {\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
584                                 {\r
585                                         traceQUEUE_SEND( pxQueue );\r
586                                         prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );\r
587                                         xReturn = pdPASS;\r
588                                                 \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
592                                         {\r
593                                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )\r
594                                                 {\r
595                                                         /* The unblocked task has a priority higher than\r
596                                                         our own so yield immediately. */\r
597                                                         taskYIELD();\r
598                                                 }\r
599                                         }\r
600                                 }\r
601                                 else\r
602                                 {\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
607                                         to the queue. */\r
608                                         xReturn = errQUEUE_FULL;\r
609                                 }\r
610                         }\r
611                         taskEXIT_CRITICAL();\r
612 \r
613                         if( xReturn == errQUEUE_FULL )\r
614                         {\r
615                                 if( xTicksToWait > ( portTickType ) 0 )\r
616                                 {\r
617                                         if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
618                                         {\r
619                                                 xReturn = queueERRONEOUS_UNBLOCK;\r
620                                         }\r
621                                         else\r
622                                         {\r
623                                                 traceQUEUE_SEND_FAILED( pxQueue );\r
624                                         }\r
625                                 }\r
626                                 else\r
627                                 {\r
628                                         traceQUEUE_SEND_FAILED( pxQueue );\r
629                                 }\r
630                         }\r
631                 }\r
632                 while( xReturn == queueERRONEOUS_UNBLOCK );\r
633 \r
634                 return xReturn;\r
635         }\r
636 \r
637 #endif /* configUSE_ALTERNATIVE_API */\r
638 /*-----------------------------------------------------------*/\r
639 \r
640 #if configUSE_ALTERNATIVE_API == 1\r
641 \r
642         signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, const void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )\r
643         {\r
644         signed portBASE_TYPE xReturn = pdTRUE;\r
645         xTimeOutType xTimeOut;\r
646         signed portCHAR *pcOriginalReadPosition;\r
647 \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
654 \r
655                 do\r
656                 {\r
657                         /* If there are no messages in the queue we may have to block. */\r
658                         if( xTicksToWait > ( portTickType ) 0 )\r
659                         {\r
660                                 portENTER_CRITICAL();\r
661                                 {\r
662                                         if( xReturn == pdPASS )\r
663                                         {\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
668                                         }\r
669                                         \r
670                                         if( prvIsQueueEmpty( pxQueue ) )\r
671                                         {\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
676                                                 {\r
677                                                         traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );\r
678 \r
679                                                         #if ( configUSE_MUTEXES == 1 )\r
680                                                         {\r
681                                                                 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
682                                                                 {\r
683                                                                         portENTER_CRITICAL();\r
684                                                                                 vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );\r
685                                                                         portEXIT_CRITICAL();\r
686                                                                 }\r
687                                                         }\r
688                                                         #endif\r
689 \r
690                                                         vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );\r
691                                                         taskYIELD();\r
692                                                 }\r
693                                         }\r
694                                 }\r
695                                 portEXIT_CRITICAL();\r
696                         }\r
697                 \r
698                         taskENTER_CRITICAL();\r
699                         {\r
700                                 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
701                                 {\r
702                                         /* Remember our read position in case we are just peeking. */\r
703                                         pcOriginalReadPosition = pxQueue->pcReadFrom;\r
704 \r
705                                         prvCopyDataFromQueue( pxQueue, pvBuffer );\r
706 \r
707                                         if( xJustPeeking == pdFALSE )\r
708                                         {\r
709                                                 traceQUEUE_RECEIVE( pxQueue );\r
710 \r
711                                                 /* We are actually removing data. */\r
712                                                 --( pxQueue->uxMessagesWaiting );\r
713 \r
714                                                 #if ( configUSE_MUTEXES == 1 )\r
715                                                 {\r
716                                                         if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
717                                                         {\r
718                                                                 /* Record the information required to implement\r
719                                                                 priority inheritance should it become necessary. */\r
720                                                                 pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();\r
721                                                         }\r
722                                                 }\r
723                                                 #endif\r
724                                                         \r
725                                                 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )\r
726                                                 {\r
727                                                         if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )\r
728                                                         {\r
729                                                                 taskYIELD();\r
730                                                         }\r
731                                                 }\r
732                                         }\r
733                                         else\r
734                                         {\r
735                                                 traceQUEUE_PEEK( pxQueue );\r
736 \r
737                                                 /* We are not removing the data, so reset our read\r
738                                                 pointer. */\r
739                                                 pxQueue->pcReadFrom = pcOriginalReadPosition;\r
740 \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
744                                                 {\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
748                                                         {\r
749                                                                 /* The task waiting has a higher priority that this task. */\r
750                                                                 taskYIELD();\r
751                                                         }\r
752                                                 }                       \r
753 \r
754                                         }\r
755                                         \r
756                                         xReturn = pdPASS;                                       \r
757                                 }\r
758                                 else\r
759                                 {\r
760                                         xReturn = errQUEUE_EMPTY;\r
761                                 }\r
762                         }\r
763                         taskEXIT_CRITICAL();\r
764 \r
765                         if( xReturn == errQUEUE_EMPTY )\r
766                         {\r
767                                 if( xTicksToWait > ( portTickType ) 0 )\r
768                                 {\r
769                                         if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
770                                         {\r
771                                                 xReturn = queueERRONEOUS_UNBLOCK;\r
772                                         }\r
773                                         else\r
774                                         {\r
775                                                 traceQUEUE_RECEIVE_FAILED( pxQueue );\r
776                                         }\r
777                                 }\r
778                                 else\r
779                                 {\r
780                                         traceQUEUE_RECEIVE_FAILED( pxQueue );\r
781                                 }\r
782                         }\r
783                 } while( xReturn == queueERRONEOUS_UNBLOCK );\r
784 \r
785                 return xReturn;\r
786         }\r
787 \r
788 \r
789 #endif /* configUSE_ALTERNATIVE_API */\r
790 /*-----------------------------------------------------------*/\r
791 \r
792 signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken, portBASE_TYPE xCopyPosition )\r
793 {\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
798         by this post). */\r
799         if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
800         {\r
801                 traceQUEUE_SEND_FROM_ISR( pxQueue );\r
802 \r
803                 prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );\r
804 \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
808                 {\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
812                         {\r
813                                 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
814                                 {\r
815                                         if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
816                                         {\r
817                                                 /* The task waiting has a higher priority so record that a\r
818                                                 context switch is required. */\r
819                                                 return pdTRUE;\r
820                                         }\r
821                                 }\r
822                         }\r
823                 }\r
824                 else\r
825                 {\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
829                 }\r
830         }\r
831         else\r
832         {\r
833                 traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue );\r
834         }\r
835 \r
836         return xTaskPreviouslyWoken;\r
837 }\r
838 /*-----------------------------------------------------------*/\r
839 \r
840 signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, const void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )\r
841 {\r
842 signed portBASE_TYPE xReturn = pdTRUE;\r
843 xTimeOutType xTimeOut;\r
844 signed portCHAR *pcOriginalReadPosition;\r
845 \r
846         do\r
847         {\r
848                 /* If there are no messages in the queue we may have to block. */\r
849                 if( xTicksToWait > ( portTickType ) 0 )\r
850                 {\r
851                         vTaskSuspendAll();\r
852                         prvLockQueue( pxQueue );\r
853 \r
854                         if( xReturn == pdTRUE )\r
855                         {\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
860                         }\r
861 \r
862                         if( prvIsQueueEmpty( pxQueue ) )\r
863                         {\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
868                                 {\r
869                                         traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );\r
870 \r
871                                         #if ( configUSE_MUTEXES == 1 )\r
872                                         {\r
873                                                 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
874                                                 {\r
875                                                         portENTER_CRITICAL();\r
876                                                                 vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );\r
877                                                         portEXIT_CRITICAL();\r
878                                                 }\r
879                                         }\r
880                                         #endif\r
881 \r
882                                         vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );\r
883                                         prvUnlockQueue( pxQueue );\r
884                                         if( !xTaskResumeAll() )\r
885                                         {\r
886                                                 taskYIELD();\r
887                                         }\r
888                                 }\r
889                                 else\r
890                                 {\r
891                                         prvUnlockQueue( pxQueue );\r
892                                         ( void ) xTaskResumeAll();\r
893                                 }\r
894                         }\r
895                         else\r
896                         {\r
897                                 prvUnlockQueue( pxQueue );\r
898                                 ( void ) xTaskResumeAll();\r
899                         }\r
900                 }\r
901         \r
902                 taskENTER_CRITICAL();\r
903                 {\r
904                         if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
905                         {\r
906                                 /* Remember our read position in case we are just peeking. */\r
907                                 pcOriginalReadPosition = pxQueue->pcReadFrom;\r
908 \r
909                                 prvCopyDataFromQueue( pxQueue, pvBuffer );\r
910 \r
911                                 if( xJustPeeking == pdFALSE )\r
912                                 {\r
913                                         traceQUEUE_RECEIVE( pxQueue );\r
914 \r
915                                         /* We are actually removing data. */\r
916                                         --( pxQueue->uxMessagesWaiting );\r
917 \r
918                                         #if ( configUSE_MUTEXES == 1 )\r
919                                         {\r
920                                                 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
921                                                 {\r
922                                                         /* Record the information required to implement\r
923                                                         priority inheritance should it become necessary. */\r
924                                                         pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();\r
925                                                 }\r
926                                         }\r
927                                         #endif\r
928                                                 \r
929                                         if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )\r
930                                         {\r
931                                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )\r
932                                                 {\r
933                                                         taskYIELD();\r
934                                                 }\r
935                                         }\r
936                                 }\r
937                                 else\r
938                                 {\r
939                                         traceQUEUE_PEEK( pxQueue );\r
940 \r
941                                         /* We are not removing the data, so reset our read\r
942                                         pointer. */\r
943                                         pxQueue->pcReadFrom = pcOriginalReadPosition;\r
944 \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
948                                         {\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
952                                                 {\r
953                                                         /* The task waiting has a higher priority that this task. */\r
954                                                         taskYIELD();\r
955                                                 }\r
956                                         }                       \r
957 \r
958                                 }\r
959                                 \r
960                                 xReturn = pdPASS;                                       \r
961                         }\r
962                         else\r
963                         {\r
964                                 xReturn = errQUEUE_EMPTY;\r
965                         }\r
966                 }\r
967                 taskEXIT_CRITICAL();\r
968 \r
969                 if( xReturn == errQUEUE_EMPTY )\r
970                 {\r
971                         if( xTicksToWait > 0 )\r
972                         {\r
973                                 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
974                                 {\r
975                                         xReturn = queueERRONEOUS_UNBLOCK;\r
976                                 }\r
977                                 else\r
978                                 {\r
979                                         traceQUEUE_RECEIVE_FAILED( pxQueue );\r
980                                 }\r
981                         }\r
982                         else\r
983                         {\r
984                                 traceQUEUE_RECEIVE_FAILED( pxQueue );\r
985                         }\r
986                 }\r
987         } while( xReturn == queueERRONEOUS_UNBLOCK );\r
988 \r
989         return xReturn;\r
990 }\r
991 /*-----------------------------------------------------------*/\r
992 \r
993 signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, const void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken )\r
994 {\r
995 signed portBASE_TYPE xReturn;\r
996 \r
997         /* We cannot block from an ISR, so check there is data available. */\r
998         if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
999         {\r
1000                 traceQUEUE_RECEIVE_FROM_ISR( pxQueue );\r
1001 \r
1002                 prvCopyDataFromQueue( pxQueue, pvBuffer );\r
1003                 --( pxQueue->uxMessagesWaiting );\r
1004 \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
1009                 {\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
1013                         {\r
1014                                 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )\r
1015                                 {\r
1016                                         if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
1017                                         {\r
1018                                                 /* The task waiting has a higher priority than us so\r
1019                                                 force a context switch. */\r
1020                                                 *pxTaskWoken = pdTRUE;\r
1021                                         }\r
1022                                 }\r
1023                         }\r
1024                 }\r
1025                 else\r
1026                 {\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
1030                 }\r
1031 \r
1032                 xReturn = pdPASS;\r
1033         }\r
1034         else\r
1035         {\r
1036                 xReturn = pdFAIL;\r
1037                 traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue );\r
1038         }\r
1039 \r
1040         return xReturn;\r
1041 }\r
1042 /*-----------------------------------------------------------*/\r
1043 \r
1044 unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle pxQueue )\r
1045 {\r
1046 unsigned portBASE_TYPE uxReturn;\r
1047 \r
1048         taskENTER_CRITICAL();\r
1049                 uxReturn = pxQueue->uxMessagesWaiting;\r
1050         taskEXIT_CRITICAL();\r
1051 \r
1052         return uxReturn;\r
1053 }\r
1054 /*-----------------------------------------------------------*/\r
1055 \r
1056 unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue )\r
1057 {\r
1058 unsigned portBASE_TYPE uxReturn;\r
1059 \r
1060         uxReturn = pxQueue->uxMessagesWaiting;\r
1061 \r
1062         return uxReturn;\r
1063 }\r
1064 /*-----------------------------------------------------------*/\r
1065 \r
1066 void vQueueDelete( xQueueHandle pxQueue )\r
1067 {\r
1068         traceQUEUE_DELETE( pxQueue );\r
1069 \r
1070         vPortFree( pxQueue->pcHead );\r
1071         vPortFree( pxQueue );\r
1072 }\r
1073 /*-----------------------------------------------------------*/\r
1074 \r
1075 static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition )\r
1076 {\r
1077         if( pxQueue->uxItemSize == 0 )\r
1078         {\r
1079                 #if ( configUSE_MUTEXES == 1 )\r
1080                 {\r
1081                         if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
1082                         {\r
1083                                 /* The mutex is no longer being held. */\r
1084                                 vTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder );\r
1085                 pxQueue->pxMutexHolder = NULL;\r
1086                         }\r
1087                 }\r
1088                 #endif\r
1089         }\r
1090         else if( xPosition == queueSEND_TO_BACK )\r
1091         {\r
1092                 memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );\r
1093                 pxQueue->pcWriteTo += pxQueue->uxItemSize;\r
1094                 if( pxQueue->pcWriteTo >= pxQueue->pcTail )\r
1095                 {\r
1096                         pxQueue->pcWriteTo = pxQueue->pcHead;\r
1097                 }\r
1098         }\r
1099         else\r
1100         {\r
1101                 memcpy( ( void * ) pxQueue->pcReadFrom, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );\r
1102                 pxQueue->pcReadFrom -= pxQueue->uxItemSize;\r
1103                 if( pxQueue->pcReadFrom < pxQueue->pcHead )\r
1104                 {\r
1105                         pxQueue->pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize );\r
1106                 }               \r
1107         }\r
1108 \r
1109         ++( pxQueue->uxMessagesWaiting );\r
1110 }\r
1111 /*-----------------------------------------------------------*/\r
1112 \r
1113 static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer )\r
1114 {\r
1115         if( pxQueue->uxQueueType != queueQUEUE_IS_MUTEX )\r
1116         {\r
1117                 pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
1118                 if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
1119                 {\r
1120                         pxQueue->pcReadFrom = pxQueue->pcHead;\r
1121                 }\r
1122                 memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
1123         }       \r
1124 }\r
1125 /*-----------------------------------------------------------*/\r
1126 \r
1127 static void prvUnlockQueue( xQueueHandle pxQueue )\r
1128 {\r
1129         /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */\r
1130 \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
1134         updated. */\r
1135         taskENTER_CRITICAL();\r
1136         {\r
1137                 --( pxQueue->xTxLock );\r
1138 \r
1139                 /* See if data was added to the queue while it was locked. */\r
1140                 if( pxQueue->xTxLock > queueUNLOCKED )\r
1141                 {\r
1142                         pxQueue->xTxLock = queueUNLOCKED;\r
1143 \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
1147                         {\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
1151                                 {\r
1152                                         /* The task waiting has a higher priority so record that a\r
1153                                         context switch is required. */\r
1154                                         vTaskMissedYield();\r
1155                                 }\r
1156                         }                       \r
1157                 }\r
1158         }\r
1159         taskEXIT_CRITICAL();\r
1160 \r
1161         /* Do the same for the Rx lock. */\r
1162         taskENTER_CRITICAL();\r
1163         {\r
1164                 --( pxQueue->xRxLock );\r
1165 \r
1166                 if( pxQueue->xRxLock > queueUNLOCKED )\r
1167                 {\r
1168                         pxQueue->xRxLock = queueUNLOCKED;\r
1169 \r
1170                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )\r
1171                         {\r
1172                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
1173                                 {\r
1174                                         vTaskMissedYield();\r
1175                                 }\r
1176                         }                       \r
1177                 }\r
1178         }\r
1179         taskEXIT_CRITICAL();\r
1180 }\r
1181 /*-----------------------------------------------------------*/\r
1182 \r
1183 static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue )\r
1184 {\r
1185 signed portBASE_TYPE xReturn;\r
1186 \r
1187         taskENTER_CRITICAL();\r
1188                 xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );\r
1189         taskEXIT_CRITICAL();\r
1190 \r
1191         return xReturn;\r
1192 }\r
1193 /*-----------------------------------------------------------*/\r
1194 \r
1195 signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue )\r
1196 {\r
1197 signed portBASE_TYPE xReturn;\r
1198 \r
1199         xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );\r
1200 \r
1201         return xReturn;\r
1202 }\r
1203 /*-----------------------------------------------------------*/\r
1204 \r
1205 static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue )\r
1206 {\r
1207 signed portBASE_TYPE xReturn;\r
1208 \r
1209         taskENTER_CRITICAL();\r
1210                 xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );\r
1211         taskEXIT_CRITICAL();\r
1212 \r
1213         return xReturn;\r
1214 }\r
1215 /*-----------------------------------------------------------*/\r
1216 \r
1217 signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue )\r
1218 {\r
1219 signed portBASE_TYPE xReturn;\r
1220 \r
1221         xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );\r
1222 \r
1223         return xReturn;\r
1224 }\r
1225 /*-----------------------------------------------------------*/\r
1226 \r
1227 #if configUSE_CO_ROUTINES == 1\r
1228 signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )\r
1229 {\r
1230 signed portBASE_TYPE xReturn;\r
1231                 \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
1236         {\r
1237                 if( prvIsQueueFull( pxQueue ) )\r
1238                 {\r
1239                         /* The queue is full - do we want to block or just leave without\r
1240                         posting? */\r
1241                         if( xTicksToWait > ( portTickType ) 0 )\r
1242                         {\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
1248                         }\r
1249                         else\r
1250                         {\r
1251                                 portENABLE_INTERRUPTS();\r
1252                                 return errQUEUE_FULL;\r
1253                         }\r
1254                 }\r
1255         }\r
1256         portENABLE_INTERRUPTS();\r
1257                 \r
1258         portNOP();\r
1259 \r
1260         portDISABLE_INTERRUPTS();\r
1261         {\r
1262                 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
1263                 {\r
1264                         /* There is room in the queue, copy the data into the queue. */                 \r
1265                         prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );\r
1266                         xReturn = pdPASS;\r
1267 \r
1268                         /* Were any co-routines waiting for data to become available? */\r
1269                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
1270                         {\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
1276                                 {\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
1280                                 }\r
1281                         }\r
1282                 }\r
1283                 else\r
1284                 {\r
1285                         xReturn = errQUEUE_FULL;\r
1286                 }\r
1287         }\r
1288         portENABLE_INTERRUPTS();\r
1289 \r
1290         return xReturn;\r
1291 }\r
1292 #endif\r
1293 /*-----------------------------------------------------------*/\r
1294 \r
1295 #if configUSE_CO_ROUTINES == 1\r
1296 signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait )\r
1297 {\r
1298 signed portBASE_TYPE xReturn;\r
1299 \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
1304         {\r
1305                 if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 )\r
1306                 {\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
1310                         {\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
1316                         }\r
1317                         else\r
1318                         {\r
1319                                 portENABLE_INTERRUPTS();\r
1320                                 return errQUEUE_FULL;\r
1321                         }\r
1322                 }\r
1323         }\r
1324         portENABLE_INTERRUPTS();\r
1325 \r
1326         portNOP();\r
1327 \r
1328         portDISABLE_INTERRUPTS();\r
1329         {\r
1330                 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
1331                 {\r
1332                         /* Data is available from the queue. */\r
1333                         pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
1334                         if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
1335                         {\r
1336                                 pxQueue->pcReadFrom = pxQueue->pcHead;\r
1337                         }\r
1338                         --( pxQueue->uxMessagesWaiting );\r
1339                         memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
1340 \r
1341                         xReturn = pdPASS;\r
1342 \r
1343                         /* Were any co-routines waiting for space to become available? */\r
1344                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )\r
1345                         {\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
1351                                 {\r
1352                                         xReturn = errQUEUE_YIELD;\r
1353                                 }\r
1354                         }       \r
1355                 }\r
1356                 else\r
1357                 {\r
1358                         xReturn = pdFAIL;\r
1359                 }\r
1360         }\r
1361         portENABLE_INTERRUPTS();\r
1362 \r
1363         return xReturn;\r
1364 }\r
1365 #endif\r
1366 /*-----------------------------------------------------------*/\r
1367 \r
1368 \r
1369 \r
1370 #if configUSE_CO_ROUTINES == 1\r
1371 signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken )\r
1372 {\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
1376         {\r
1377                 prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );\r
1378 \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
1382                 {\r
1383                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
1384                         {\r
1385                                 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
1386                                 {\r
1387                                         return pdTRUE;\r
1388                                 }\r
1389                         }\r
1390                 }\r
1391         }\r
1392 \r
1393         return xCoRoutinePreviouslyWoken;\r
1394 }\r
1395 #endif\r
1396 /*-----------------------------------------------------------*/\r
1397 \r
1398 #if configUSE_CO_ROUTINES == 1\r
1399 signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxCoRoutineWoken )\r
1400 {\r
1401 signed portBASE_TYPE xReturn;\r
1402 \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
1406         {\r
1407                 /* Copy the data from the queue. */\r
1408                 pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
1409                 if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
1410                 {\r
1411                         pxQueue->pcReadFrom = pxQueue->pcHead;\r
1412                 }\r
1413                 --( pxQueue->uxMessagesWaiting );\r
1414                 memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
1415 \r
1416                 if( !( *pxCoRoutineWoken ) )\r
1417                 {\r
1418                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )\r
1419                         {\r
1420                                 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
1421                                 {\r
1422                                         *pxCoRoutineWoken = pdTRUE;\r
1423                                 }\r
1424                         }\r
1425                 }\r
1426 \r
1427                 xReturn = pdPASS;\r
1428         }\r
1429         else\r
1430         {\r
1431                 xReturn = pdFAIL;\r
1432         }\r
1433 \r
1434         return xReturn;\r
1435 }\r
1436 #endif\r
1437 /*-----------------------------------------------------------*/\r
1438 \r