]> git.sur5r.net Git - freertos/blob - FreeRTOS/Source/queue.c
Update version number ready to release the FAT file system demo.
[freertos] / FreeRTOS / Source / queue.c
1 /*\r
2     FreeRTOS V7.4.2 - Copyright (C) 2013 Real Time Engineers Ltd.\r
3 \r
4     FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME.  PLEASE VISIT\r
5     http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
6 \r
7     ***************************************************************************\r
8      *                                                                       *\r
9      *    FreeRTOS tutorial books are available in pdf and paperback.        *\r
10      *    Complete, revised, and edited pdf reference manuals are also       *\r
11      *    available.                                                         *\r
12      *                                                                       *\r
13      *    Purchasing FreeRTOS documentation will not only help you, by       *\r
14      *    ensuring you get running as quickly as possible and with an        *\r
15      *    in-depth knowledge of how to use FreeRTOS, it will also help       *\r
16      *    the FreeRTOS project to continue with its mission of providing     *\r
17      *    professional grade, cross platform, de facto standard solutions    *\r
18      *    for microcontrollers - completely free of charge!                  *\r
19      *                                                                       *\r
20      *    >>> See http://www.FreeRTOS.org/Documentation for details. <<<     *\r
21      *                                                                       *\r
22      *    Thank you for using FreeRTOS, and thank you for your support!      *\r
23      *                                                                       *\r
24     ***************************************************************************\r
25 \r
26 \r
27     This file is part of the FreeRTOS distribution.\r
28 \r
29     FreeRTOS is free software; you can redistribute it and/or modify it under\r
30     the terms of the GNU General Public License (version 2) as published by the\r
31     Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
32 \r
33     >>>>>>NOTE<<<<<< The modification to the GPL is included to allow you to\r
34     distribute a combined work that includes FreeRTOS without being obliged to\r
35     provide the source code for proprietary components outside of the FreeRTOS\r
36     kernel.\r
37 \r
38     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
39     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
40     FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more\r
41     details. You should have received a copy of the GNU General Public License\r
42     and the FreeRTOS license exception along with FreeRTOS; if not it can be\r
43     viewed here: http://www.freertos.org/a00114.html and also obtained by\r
44     writing to Real Time Engineers Ltd., contact details for whom are available\r
45     on the FreeRTOS WEB site.\r
46 \r
47     1 tab == 4 spaces!\r
48 \r
49     ***************************************************************************\r
50      *                                                                       *\r
51      *    Having a problem?  Start by reading the FAQ "My application does   *\r
52      *    not run, what could be wrong?"                                     *\r
53      *                                                                       *\r
54      *    http://www.FreeRTOS.org/FAQHelp.html                               *\r
55      *                                                                       *\r
56     ***************************************************************************\r
57 \r
58 \r
59     http://www.FreeRTOS.org - Documentation, books, training, latest versions, \r
60     license and Real Time Engineers Ltd. contact details.\r
61 \r
62     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
63     including FreeRTOS+Trace - an indispensable productivity tool, and our new\r
64     fully thread aware and reentrant UDP/IP stack.\r
65 \r
66     http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High \r
67     Integrity Systems, who sell the code with commercial support, \r
68     indemnification and middleware, under the OpenRTOS brand.\r
69     \r
70     http://www.SafeRTOS.com - High Integrity Systems also provide a safety \r
71     engineered and independently SIL3 certified version for use in safety and \r
72     mission critical applications that require provable dependability.\r
73 */\r
74 \r
75 #include <stdlib.h>\r
76 #include <string.h>\r
77 \r
78 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining\r
79 all the API functions to use the MPU wrappers.  That should only be done when\r
80 task.h is included from an application file. */\r
81 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
82 \r
83 #include "FreeRTOS.h"\r
84 #include "task.h"\r
85 #include "queue.h"\r
86 \r
87 #if ( configUSE_CO_ROUTINES == 1 )\r
88         #include "croutine.h"\r
89 #endif\r
90 \r
91 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
92 \r
93 /* Constants used with the cRxLock and xTxLock structure members. */\r
94 #define queueUNLOCKED                                   ( ( signed portBASE_TYPE ) -1 )\r
95 #define queueLOCKED_UNMODIFIED                  ( ( signed portBASE_TYPE ) 0 )\r
96 \r
97 #define queueERRONEOUS_UNBLOCK                  ( -1 )\r
98 \r
99 /* Effectively make a union out of the xQUEUE structure. */\r
100 #define pxMutexHolder                                   pcTail\r
101 #define uxQueueType                                             pcHead\r
102 #define uxRecursiveCallCount                    pcReadFrom\r
103 #define queueQUEUE_IS_MUTEX                             NULL\r
104 \r
105 /* Semaphores do not actually store or copy data, so have an items size of\r
106 zero. */\r
107 #define queueSEMAPHORE_QUEUE_ITEM_LENGTH ( ( unsigned portBASE_TYPE ) 0 )\r
108 #define queueDONT_BLOCK                                  ( ( portTickType ) 0U )\r
109 #define queueMUTEX_GIVE_BLOCK_TIME               ( ( portTickType ) 0U )\r
110 \r
111 \r
112 /*\r
113  * Definition of the queue used by the scheduler.\r
114  * Items are queued by copy, not reference.\r
115  */\r
116 typedef struct QueueDefinition\r
117 {\r
118         signed char *pcHead;                                    /*< Points to the beginning of the queue storage area. */\r
119         signed char *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
120 \r
121         signed char *pcWriteTo;                                 /*< Points to the free next place in the storage area. */\r
122         signed char *pcReadFrom;                                /*< Points to the last place that a queued item was read from. */\r
123 \r
124         xList xTasksWaitingToSend;                              /*< List of tasks that are blocked waiting to post onto this queue.  Stored in priority order. */\r
125         xList xTasksWaitingToReceive;                   /*< List of tasks that are blocked waiting to read from this queue.  Stored in priority order. */\r
126 \r
127         volatile unsigned portBASE_TYPE uxMessagesWaiting;/*< The number of items currently in the queue. */\r
128         unsigned portBASE_TYPE uxLength;                /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */\r
129         unsigned portBASE_TYPE uxItemSize;              /*< The size of each items that the queue will hold. */\r
130 \r
131         volatile 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
132         volatile 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
133 \r
134         #if ( configUSE_TRACE_FACILITY == 1 )\r
135                 unsigned char ucQueueNumber;\r
136                 unsigned char ucQueueType;\r
137         #endif\r
138 \r
139         #if ( configUSE_QUEUE_SETS == 1 )\r
140                 struct QueueDefinition *pxQueueSetContainer;\r
141         #endif\r
142 \r
143 } xQUEUE;\r
144 /*-----------------------------------------------------------*/\r
145 \r
146 /*\r
147  * The queue registry is just a means for kernel aware debuggers to locate\r
148  * queue structures.  It has no other purpose so is an optional component.\r
149  */\r
150 #if ( configQUEUE_REGISTRY_SIZE > 0 )\r
151 \r
152         /* The type stored within the queue registry array.  This allows a name\r
153         to be assigned to each queue making kernel aware debugging a little\r
154         more user friendly. */\r
155         typedef struct QUEUE_REGISTRY_ITEM\r
156         {\r
157                 signed char *pcQueueName;\r
158                 xQueueHandle xHandle;\r
159         } xQueueRegistryItem;\r
160 \r
161         /* The queue registry is simply an array of xQueueRegistryItem structures.\r
162         The pcQueueName member of a structure being NULL is indicative of the\r
163         array position being vacant. */\r
164         xQueueRegistryItem xQueueRegistry[ configQUEUE_REGISTRY_SIZE ];\r
165 \r
166         /* Removes a queue from the registry by simply setting the pcQueueName\r
167         member to NULL. */\r
168         static void prvQueueUnregisterQueue( xQueueHandle xQueue ) PRIVILEGED_FUNCTION;\r
169 \r
170 #endif /* configQUEUE_REGISTRY_SIZE */\r
171 \r
172 /*\r
173  * Unlocks a queue locked by a call to prvLockQueue.  Locking a queue does not\r
174  * prevent an ISR from adding or removing items to the queue, but does prevent\r
175  * an ISR from removing tasks from the queue event lists.  If an ISR finds a\r
176  * queue is locked it will instead increment the appropriate queue lock count\r
177  * to indicate that a task may require unblocking.  When the queue in unlocked\r
178  * these lock counts are inspected, and the appropriate action taken.\r
179  */\r
180 static void prvUnlockQueue( xQUEUE *pxQueue ) PRIVILEGED_FUNCTION;\r
181 \r
182 /*\r
183  * Uses a critical section to determine if there is any data in a queue.\r
184  *\r
185  * @return pdTRUE if the queue contains no items, otherwise pdFALSE.\r
186  */\r
187 static signed portBASE_TYPE prvIsQueueEmpty( const xQUEUE *pxQueue ) PRIVILEGED_FUNCTION;\r
188 \r
189 /*\r
190  * Uses a critical section to determine if there is any space in a queue.\r
191  *\r
192  * @return pdTRUE if there is no space, otherwise pdFALSE;\r
193  */\r
194 static signed portBASE_TYPE prvIsQueueFull( const xQUEUE *pxQueue ) PRIVILEGED_FUNCTION;\r
195 \r
196 /*\r
197  * Copies an item into the queue, either at the front of the queue or the\r
198  * back of the queue.\r
199  */\r
200 static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition ) PRIVILEGED_FUNCTION;\r
201 \r
202 /*\r
203  * Copies an item out of a queue.\r
204  */\r
205 static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer ) PRIVILEGED_FUNCTION;\r
206 \r
207 #if ( configUSE_QUEUE_SETS == 1 )\r
208         /*\r
209          * Checks to see if a queue is a member of a queue set, and if so, notifies\r
210          * the queue set that the queue contains data.\r
211          */\r
212         static portBASE_TYPE prvNotifyQueueSetContainer( xQUEUE *pxQueue, portBASE_TYPE xCopyPosition );\r
213 #endif\r
214 \r
215 /*-----------------------------------------------------------*/\r
216 \r
217 /*\r
218  * Macro to mark a queue as locked.  Locking a queue prevents an ISR from\r
219  * accessing the queue event lists.\r
220  */\r
221 #define prvLockQueue( pxQueue )                                                         \\r
222         taskENTER_CRITICAL();                                                                   \\r
223         {                                                                                                               \\r
224                 if( ( pxQueue )->xRxLock == queueUNLOCKED )                     \\r
225                 {                                                                                                       \\r
226                         ( pxQueue )->xRxLock = queueLOCKED_UNMODIFIED;  \\r
227                 }                                                                                                       \\r
228                 if( ( pxQueue )->xTxLock == queueUNLOCKED )                     \\r
229                 {                                                                                                       \\r
230                         ( pxQueue )->xTxLock = queueLOCKED_UNMODIFIED;  \\r
231                 }                                                                                                       \\r
232         }                                                                                                               \\r
233         taskEXIT_CRITICAL()\r
234 /*-----------------------------------------------------------*/\r
235 \r
236 portBASE_TYPE xQueueGenericReset( xQueueHandle xQueue, portBASE_TYPE xNewQueue )\r
237 {\r
238 xQUEUE *pxQueue;\r
239 \r
240         pxQueue = ( xQUEUE * ) xQueue;\r
241         configASSERT( pxQueue );\r
242 \r
243         taskENTER_CRITICAL();\r
244         {\r
245                 pxQueue->pcTail = pxQueue->pcHead + ( pxQueue->uxLength * pxQueue->uxItemSize );\r
246                 pxQueue->uxMessagesWaiting = ( unsigned portBASE_TYPE ) 0U;\r
247                 pxQueue->pcWriteTo = pxQueue->pcHead;\r
248                 pxQueue->pcReadFrom = pxQueue->pcHead + ( ( pxQueue->uxLength - ( unsigned portBASE_TYPE ) 1U ) * pxQueue->uxItemSize );\r
249                 pxQueue->xRxLock = queueUNLOCKED;\r
250                 pxQueue->xTxLock = queueUNLOCKED;\r
251 \r
252                 if( xNewQueue == pdFALSE )\r
253                 {\r
254                         /* If there are tasks blocked waiting to read from the queue, then\r
255                         the tasks will remain blocked as after this function exits the queue\r
256                         will still be empty.  If there are tasks blocked waiting to     write to\r
257                         the queue, then one should be unblocked as after this function exits\r
258                         it will be possible to write to it. */\r
259                         if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )\r
260                         {\r
261                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )\r
262                                 {\r
263                                         portYIELD_WITHIN_API();\r
264                                 }\r
265                         }\r
266                 }\r
267                 else\r
268                 {\r
269                         /* Ensure the event queues start in the correct state. */\r
270                         vListInitialise( &( pxQueue->xTasksWaitingToSend ) );\r
271                         vListInitialise( &( pxQueue->xTasksWaitingToReceive ) );\r
272                 }\r
273         }\r
274         taskEXIT_CRITICAL();\r
275 \r
276         /* A value is returned for calling semantic consistency with previous\r
277         versions. */\r
278         return pdPASS;\r
279 }\r
280 /*-----------------------------------------------------------*/\r
281 \r
282 xQueueHandle xQueueGenericCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize, unsigned char ucQueueType )\r
283 {\r
284 xQUEUE *pxNewQueue;\r
285 size_t xQueueSizeInBytes;\r
286 xQueueHandle xReturn = NULL;\r
287 \r
288         /* Remove compiler warnings about unused parameters should\r
289         configUSE_TRACE_FACILITY not be set to 1. */\r
290         ( void ) ucQueueType;\r
291 \r
292         /* Allocate the new queue structure. */\r
293         if( uxQueueLength > ( unsigned portBASE_TYPE ) 0 )\r
294         {\r
295                 pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );\r
296                 if( pxNewQueue != NULL )\r
297                 {\r
298                         /* Create the list of pointers to queue items.  The queue is one byte\r
299                         longer than asked for to make wrap checking easier/faster. */\r
300                         xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ) + ( size_t ) 1;\r
301 \r
302                         pxNewQueue->pcHead = ( signed char * ) pvPortMalloc( xQueueSizeInBytes );\r
303                         if( pxNewQueue->pcHead != NULL )\r
304                         {\r
305                                 /* Initialise the queue members as described above where the\r
306                                 queue type is defined. */\r
307                                 pxNewQueue->uxLength = uxQueueLength;\r
308                                 pxNewQueue->uxItemSize = uxItemSize;\r
309                                 xQueueGenericReset( pxNewQueue, pdTRUE );\r
310 \r
311                                 #if ( configUSE_TRACE_FACILITY == 1 )\r
312                                 {\r
313                                         pxNewQueue->ucQueueType = ucQueueType;\r
314                                 }\r
315                                 #endif /* configUSE_TRACE_FACILITY */\r
316 \r
317                                 #if( configUSE_QUEUE_SETS == 1 )\r
318                                 {\r
319                                         pxNewQueue->pxQueueSetContainer = NULL;\r
320                                 }\r
321                                 #endif /* configUSE_QUEUE_SETS */\r
322 \r
323                                 traceQUEUE_CREATE( pxNewQueue );\r
324                                 xReturn = pxNewQueue;\r
325                         }\r
326                         else\r
327                         {\r
328                                 traceQUEUE_CREATE_FAILED( ucQueueType );\r
329                                 vPortFree( pxNewQueue );\r
330                         }\r
331                 }\r
332         }\r
333 \r
334         configASSERT( xReturn );\r
335 \r
336         return xReturn;\r
337 }\r
338 /*-----------------------------------------------------------*/\r
339 \r
340 #if ( configUSE_MUTEXES == 1 )\r
341 \r
342         xQueueHandle xQueueCreateMutex( unsigned char ucQueueType )\r
343         {\r
344         xQUEUE *pxNewQueue;\r
345 \r
346                 /* Prevent compiler warnings about unused parameters if\r
347                 configUSE_TRACE_FACILITY does not equal 1. */\r
348                 ( void ) ucQueueType;\r
349 \r
350                 /* Allocate the new queue structure. */\r
351                 pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );\r
352                 if( pxNewQueue != NULL )\r
353                 {\r
354                         /* Information required for priority inheritance. */\r
355                         pxNewQueue->pxMutexHolder = NULL;\r
356                         pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX;\r
357 \r
358                         /* Queues used as a mutex no data is actually copied into or out\r
359                         of the queue. */\r
360                         pxNewQueue->pcWriteTo = NULL;\r
361                         pxNewQueue->pcReadFrom = NULL;\r
362 \r
363                         /* Each mutex has a length of 1 (like a binary semaphore) and\r
364                         an item size of 0 as nothing is actually copied into or out\r
365                         of the mutex. */\r
366                         pxNewQueue->uxMessagesWaiting = ( unsigned portBASE_TYPE ) 0U;\r
367                         pxNewQueue->uxLength = ( unsigned portBASE_TYPE ) 1U;\r
368                         pxNewQueue->uxItemSize = ( unsigned portBASE_TYPE ) 0U;\r
369                         pxNewQueue->xRxLock = queueUNLOCKED;\r
370                         pxNewQueue->xTxLock = queueUNLOCKED;\r
371 \r
372                         #if ( configUSE_TRACE_FACILITY == 1 )\r
373                         {\r
374                                 pxNewQueue->ucQueueType = ucQueueType;\r
375                         }\r
376                         #endif\r
377 \r
378                         #if ( configUSE_QUEUE_SETS == 1 )\r
379                         {\r
380                                 pxNewQueue->pxQueueSetContainer = NULL;\r
381                         }\r
382                         #endif\r
383 \r
384                         /* Ensure the event queues start with the correct state. */\r
385                         vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );\r
386                         vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );\r
387 \r
388                         traceCREATE_MUTEX( pxNewQueue );\r
389 \r
390                         /* Start with the semaphore in the expected state. */\r
391                         xQueueGenericSend( pxNewQueue, NULL, ( portTickType ) 0U, queueSEND_TO_BACK );\r
392                 }\r
393                 else\r
394                 {\r
395                         traceCREATE_MUTEX_FAILED();\r
396                 }\r
397 \r
398                 configASSERT( pxNewQueue );\r
399                 return pxNewQueue;\r
400         }\r
401 \r
402 #endif /* configUSE_MUTEXES */\r
403 /*-----------------------------------------------------------*/\r
404 \r
405 #if ( ( configUSE_MUTEXES == 1 ) && ( INCLUDE_xSemaphoreGetMutexHolder == 1 ) )\r
406 \r
407         void* xQueueGetMutexHolder( xQueueHandle xSemaphore )\r
408         {\r
409         void *pxReturn;\r
410 \r
411                 /* This function is called by xSemaphoreGetMutexHolder(), and should not\r
412                 be called directly.  Note:  This is is a good way of determining if the\r
413                 calling task is the mutex holder, but not a good way of determining the\r
414                 identity of the mutex holder, as the holder may change between the\r
415                 following critical section exiting and the function returning. */\r
416                 taskENTER_CRITICAL();\r
417                 {\r
418                         if( ( ( xQUEUE * ) xSemaphore )->uxQueueType == queueQUEUE_IS_MUTEX )\r
419                         {\r
420                                 pxReturn = ( void * ) ( ( xQUEUE * ) xSemaphore )->pxMutexHolder;\r
421                         }\r
422                         else\r
423                         {\r
424                                 pxReturn = NULL;\r
425                         }\r
426                 }\r
427                 taskEXIT_CRITICAL();\r
428 \r
429                 return pxReturn;\r
430         }\r
431 \r
432 #endif\r
433 /*-----------------------------------------------------------*/\r
434 \r
435 #if ( configUSE_RECURSIVE_MUTEXES == 1 )\r
436 \r
437         portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle xMutex )\r
438         {\r
439         portBASE_TYPE xReturn;\r
440         xQUEUE *pxMutex;\r
441 \r
442                 pxMutex = ( xQUEUE * ) xMutex;\r
443                 configASSERT( pxMutex );\r
444 \r
445                 /* If this is the task that holds the mutex then pxMutexHolder will not\r
446                 change outside of this task.  If this task does not hold the mutex then\r
447                 pxMutexHolder can never coincidentally equal the tasks handle, and as\r
448                 this is the only condition we are interested in it does not matter if\r
449                 pxMutexHolder is accessed simultaneously by another task.  Therefore no\r
450                 mutual exclusion is required to test the pxMutexHolder variable. */\r
451                 if( pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle() )\r
452                 {\r
453                         traceGIVE_MUTEX_RECURSIVE( pxMutex );\r
454 \r
455                         /* uxRecursiveCallCount cannot be zero if pxMutexHolder is equal to\r
456                         the task handle, therefore no underflow check is required.  Also,\r
457                         uxRecursiveCallCount is only modified by the mutex holder, and as\r
458                         there can only be one, no mutual exclusion is required to modify the\r
459                         uxRecursiveCallCount member. */\r
460                         ( pxMutex->uxRecursiveCallCount )--;\r
461 \r
462                         /* Have we unwound the call count? */\r
463                         if( pxMutex->uxRecursiveCallCount == 0 )\r
464                         {\r
465                                 /* Return the mutex.  This will automatically unblock any other\r
466                                 task that might be waiting to access the mutex. */\r
467                                 xQueueGenericSend( pxMutex, NULL, queueMUTEX_GIVE_BLOCK_TIME, queueSEND_TO_BACK );\r
468                         }\r
469 \r
470                         xReturn = pdPASS;\r
471                 }\r
472                 else\r
473                 {\r
474                         /* We cannot give the mutex because we are not the holder. */\r
475                         xReturn = pdFAIL;\r
476 \r
477                         traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex );\r
478                 }\r
479 \r
480                 return xReturn;\r
481         }\r
482 \r
483 #endif /* configUSE_RECURSIVE_MUTEXES */\r
484 /*-----------------------------------------------------------*/\r
485 \r
486 #if ( configUSE_RECURSIVE_MUTEXES == 1 )\r
487 \r
488         portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle xMutex, portTickType xBlockTime )\r
489         {\r
490         portBASE_TYPE xReturn;\r
491         xQUEUE *pxMutex;\r
492 \r
493                 pxMutex = ( xQUEUE * ) xMutex;\r
494                 configASSERT( pxMutex );\r
495 \r
496                 /* Comments regarding mutual exclusion as per those within\r
497                 xQueueGiveMutexRecursive(). */\r
498 \r
499                 traceTAKE_MUTEX_RECURSIVE( pxMutex );\r
500 \r
501                 if( pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle() )\r
502                 {\r
503                         ( pxMutex->uxRecursiveCallCount )++;\r
504                         xReturn = pdPASS;\r
505                 }\r
506                 else\r
507                 {\r
508                         xReturn = xQueueGenericReceive( pxMutex, NULL, xBlockTime, pdFALSE );\r
509 \r
510                         /* pdPASS will only be returned if we successfully obtained the mutex,\r
511                         we may have blocked to reach here. */\r
512                         if( xReturn == pdPASS )\r
513                         {\r
514                                 ( pxMutex->uxRecursiveCallCount )++;\r
515                         }\r
516                         else\r
517                         {\r
518                                 traceTAKE_MUTEX_RECURSIVE_FAILED( pxMutex );\r
519                         }\r
520                 }\r
521 \r
522                 return xReturn;\r
523         }\r
524 \r
525 #endif /* configUSE_RECURSIVE_MUTEXES */\r
526 /*-----------------------------------------------------------*/\r
527 \r
528 #if ( configUSE_COUNTING_SEMAPHORES == 1 )\r
529 \r
530         xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount )\r
531         {\r
532         xQueueHandle xHandle;\r
533 \r
534                 xHandle = xQueueGenericCreate( ( unsigned portBASE_TYPE ) uxCountValue, queueSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_COUNTING_SEMAPHORE );\r
535 \r
536                 if( xHandle != NULL )\r
537                 {\r
538                         ( ( xQUEUE * ) xHandle )->uxMessagesWaiting = uxInitialCount;\r
539 \r
540                         traceCREATE_COUNTING_SEMAPHORE();\r
541                 }\r
542                 else\r
543                 {\r
544                         traceCREATE_COUNTING_SEMAPHORE_FAILED();\r
545                 }\r
546 \r
547                 configASSERT( xHandle );\r
548                 return xHandle;\r
549         }\r
550 \r
551 #endif /* configUSE_COUNTING_SEMAPHORES */\r
552 /*-----------------------------------------------------------*/\r
553 \r
554 signed portBASE_TYPE xQueueGenericSend( xQueueHandle xQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )\r
555 {\r
556 signed portBASE_TYPE xEntryTimeSet = pdFALSE;\r
557 xTimeOutType xTimeOut;\r
558 xQUEUE *pxQueue;\r
559 \r
560         pxQueue = ( xQUEUE * ) xQueue;\r
561         configASSERT( pxQueue );\r
562         configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );\r
563 \r
564         /* This function relaxes the coding standard somewhat to allow return\r
565         statements within the function itself.  This is done in the interest\r
566         of execution time efficiency. */\r
567         for( ;; )\r
568         {\r
569                 taskENTER_CRITICAL();\r
570                 {\r
571                         /* Is there room on the queue now?  To be running we must be\r
572                         the highest priority task wanting to access the queue. */\r
573                         if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
574                         {\r
575                                 traceQUEUE_SEND( pxQueue );\r
576                                 prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );\r
577 \r
578                                 #if ( configUSE_QUEUE_SETS == 1 )\r
579                                 {\r
580                                         if( pxQueue->pxQueueSetContainer != NULL )\r
581                                         {\r
582                                                 if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) == pdTRUE )\r
583                                                 {\r
584                                                         /* The queue is a member of a queue set, and posting\r
585                                                         to the queue set caused a higher priority task to\r
586                                                         unblock. A context switch is required. */\r
587                                                         portYIELD_WITHIN_API();\r
588                                                 }\r
589                                         }\r
590                                         else\r
591                                         {\r
592                                                 /* If there was a task waiting for data to arrive on the\r
593                                                 queue then unblock it now. */\r
594                                                 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
595                                                 {\r
596                                                         if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )\r
597                                                         {\r
598                                                                 /* The unblocked task has a priority higher than\r
599                                                                 our own so yield immediately.  Yes it is ok to\r
600                                                                 do this from within the critical section - the\r
601                                                                 kernel takes care of that. */\r
602                                                                 portYIELD_WITHIN_API();\r
603                                                         }\r
604                                                 }\r
605                                         }\r
606                                 }\r
607                                 #else /* configUSE_QUEUE_SETS */\r
608                                 {\r
609                                         /* If there was a task waiting for data to arrive on the\r
610                                         queue then unblock it now. */\r
611                                         if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
612                                         {\r
613                                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )\r
614                                                 {\r
615                                                         /* The unblocked task has a priority higher than\r
616                                                         our own so yield immediately.  Yes it is ok to do\r
617                                                         this from within the critical section - the kernel\r
618                                                         takes care of that. */\r
619                                                         portYIELD_WITHIN_API();\r
620                                                 }\r
621                                         }\r
622                                 }\r
623                                 #endif /* configUSE_QUEUE_SETS */\r
624 \r
625                                 taskEXIT_CRITICAL();\r
626 \r
627                                 /* Return to the original privilege level before exiting the\r
628                                 function. */\r
629                                 return pdPASS;\r
630                         }\r
631                         else\r
632                         {\r
633                                 if( xTicksToWait == ( portTickType ) 0 )\r
634                                 {\r
635                                         /* The queue was full and no block time is specified (or\r
636                                         the block time has expired) so leave now. */\r
637                                         taskEXIT_CRITICAL();\r
638 \r
639                                         /* Return to the original privilege level before exiting\r
640                                         the function. */\r
641                                         traceQUEUE_SEND_FAILED( pxQueue );\r
642                                         return errQUEUE_FULL;\r
643                                 }\r
644                                 else if( xEntryTimeSet == pdFALSE )\r
645                                 {\r
646                                         /* The queue was full and a block time was specified so\r
647                                         configure the timeout structure. */\r
648                                         vTaskSetTimeOutState( &xTimeOut );\r
649                                         xEntryTimeSet = pdTRUE;\r
650                                 }\r
651                         }\r
652                 }\r
653                 taskEXIT_CRITICAL();\r
654 \r
655                 /* Interrupts and other tasks can send to and receive from the queue\r
656                 now the critical section has been exited. */\r
657 \r
658                 vTaskSuspendAll();\r
659                 prvLockQueue( pxQueue );\r
660 \r
661                 /* Update the timeout state to see if it has expired yet. */\r
662                 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
663                 {\r
664                         if( prvIsQueueFull( pxQueue ) != pdFALSE )\r
665                         {\r
666                                 traceBLOCKING_ON_QUEUE_SEND( pxQueue );\r
667                                 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );\r
668 \r
669                                 /* Unlocking the queue means queue events can effect the\r
670                                 event list.  It is possible     that interrupts occurring now\r
671                                 remove this task from the event list again - but as the\r
672                                 scheduler is suspended the task will go onto the pending\r
673                                 ready last instead of the actual ready list. */\r
674                                 prvUnlockQueue( pxQueue );\r
675 \r
676                                 /* Resuming the scheduler will move tasks from the pending\r
677                                 ready list into the ready list - so it is feasible that this\r
678                                 task is already in a ready list before it yields - in which\r
679                                 case the yield will not cause a context switch unless there\r
680                                 is also a higher priority task in the pending ready list. */\r
681                                 if( xTaskResumeAll() == pdFALSE )\r
682                                 {\r
683                                         portYIELD_WITHIN_API();\r
684                                 }\r
685                         }\r
686                         else\r
687                         {\r
688                                 /* Try again. */\r
689                                 prvUnlockQueue( pxQueue );\r
690                                 ( void ) xTaskResumeAll();\r
691                         }\r
692                 }\r
693                 else\r
694                 {\r
695                         /* The timeout has expired. */\r
696                         prvUnlockQueue( pxQueue );\r
697                         ( void ) xTaskResumeAll();\r
698 \r
699                         /* Return to the original privilege level before exiting the\r
700                         function. */\r
701                         traceQUEUE_SEND_FAILED( pxQueue );\r
702                         return errQUEUE_FULL;\r
703                 }\r
704         }\r
705 }\r
706 /*-----------------------------------------------------------*/\r
707 \r
708 #if ( configUSE_ALTERNATIVE_API == 1 )\r
709 \r
710         signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle xQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )\r
711         {\r
712         signed portBASE_TYPE xEntryTimeSet = pdFALSE;\r
713         xTimeOutType xTimeOut;\r
714         xQUEUE *pxQueue;\r
715 \r
716                 pxQueue = ( xQUEUE * ) xQueue;\r
717                 configASSERT( pxQueue );\r
718                 configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );\r
719 \r
720                 for( ;; )\r
721                 {\r
722                         taskENTER_CRITICAL();\r
723                         {\r
724                                 /* Is there room on the queue now?  To be running we must be\r
725                                 the highest priority task wanting to access the queue. */\r
726                                 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
727                                 {\r
728                                         traceQUEUE_SEND( pxQueue );\r
729                                         prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );\r
730 \r
731                                         /* If there was a task waiting for data to arrive on the\r
732                                         queue then unblock it now. */\r
733                                         if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
734                                         {\r
735                                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )\r
736                                                 {\r
737                                                         /* The unblocked task has a priority higher than\r
738                                                         our own so yield immediately. */\r
739                                                         portYIELD_WITHIN_API();\r
740                                                 }\r
741                                         }\r
742 \r
743                                         taskEXIT_CRITICAL();\r
744                                         return pdPASS;\r
745                                 }\r
746                                 else\r
747                                 {\r
748                                         if( xTicksToWait == ( portTickType ) 0 )\r
749                                         {\r
750                                                 taskEXIT_CRITICAL();\r
751                                                 return errQUEUE_FULL;\r
752                                         }\r
753                                         else if( xEntryTimeSet == pdFALSE )\r
754                                         {\r
755                                                 vTaskSetTimeOutState( &xTimeOut );\r
756                                                 xEntryTimeSet = pdTRUE;\r
757                                         }\r
758                                 }\r
759                         }\r
760                         taskEXIT_CRITICAL();\r
761 \r
762                         taskENTER_CRITICAL();\r
763                         {\r
764                                 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
765                                 {\r
766                                         if( prvIsQueueFull( pxQueue ) != pdFALSE )\r
767                                         {\r
768                                                 traceBLOCKING_ON_QUEUE_SEND( pxQueue );\r
769                                                 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );\r
770                                                 portYIELD_WITHIN_API();\r
771                                         }\r
772                                 }\r
773                                 else\r
774                                 {\r
775                                         taskEXIT_CRITICAL();\r
776                                         traceQUEUE_SEND_FAILED( pxQueue );\r
777                                         return errQUEUE_FULL;\r
778                                 }\r
779                         }\r
780                         taskEXIT_CRITICAL();\r
781                 }\r
782         }\r
783 \r
784 #endif /* configUSE_ALTERNATIVE_API */\r
785 /*-----------------------------------------------------------*/\r
786 \r
787 #if ( configUSE_ALTERNATIVE_API == 1 )\r
788 \r
789         signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle xQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )\r
790         {\r
791         signed portBASE_TYPE xEntryTimeSet = pdFALSE;\r
792         xTimeOutType xTimeOut;\r
793         signed char *pcOriginalReadPosition;\r
794         xQUEUE *pxQueue;\r
795 \r
796                 pxQueue = ( xQUEUE * ) xQueue;\r
797                 configASSERT( pxQueue );\r
798                 configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );\r
799 \r
800                 for( ;; )\r
801                 {\r
802                         taskENTER_CRITICAL();\r
803                         {\r
804                                 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
805                                 {\r
806                                         /* Remember our read position in case we are just peeking. */\r
807                                         pcOriginalReadPosition = pxQueue->pcReadFrom;\r
808 \r
809                                         prvCopyDataFromQueue( pxQueue, pvBuffer );\r
810 \r
811                                         if( xJustPeeking == pdFALSE )\r
812                                         {\r
813                                                 traceQUEUE_RECEIVE( pxQueue );\r
814 \r
815                                                 /* We are actually removing data. */\r
816                                                 --( pxQueue->uxMessagesWaiting );\r
817 \r
818                                                 #if ( configUSE_MUTEXES == 1 )\r
819                                                 {\r
820                                                         if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
821                                                         {\r
822                                                                 /* Record the information required to implement\r
823                                                                 priority inheritance should it become necessary. */\r
824                                                                 pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();\r
825                                                         }\r
826                                                 }\r
827                                                 #endif\r
828 \r
829                                                 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )\r
830                                                 {\r
831                                                         if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )\r
832                                                         {\r
833                                                                 portYIELD_WITHIN_API();\r
834                                                         }\r
835                                                 }\r
836                                         }\r
837                                         else\r
838                                         {\r
839                                                 traceQUEUE_PEEK( pxQueue );\r
840 \r
841                                                 /* We are not removing the data, so reset our read\r
842                                                 pointer. */\r
843                                                 pxQueue->pcReadFrom = pcOriginalReadPosition;\r
844 \r
845                                                 /* The data is being left in the queue, so see if there are\r
846                                                 any other tasks waiting for the data. */\r
847                                                 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
848                                                 {\r
849                                                         /* Tasks that are removed from the event list will get added to\r
850                                                         the pending ready list as the scheduler is still suspended. */\r
851                                                         if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
852                                                         {\r
853                                                                 /* The task waiting has a higher priority than this task. */\r
854                                                                 portYIELD_WITHIN_API();\r
855                                                         }\r
856                                                 }\r
857 \r
858                                         }\r
859 \r
860                                         taskEXIT_CRITICAL();\r
861                                         return pdPASS;\r
862                                 }\r
863                                 else\r
864                                 {\r
865                                         if( xTicksToWait == ( portTickType ) 0 )\r
866                                         {\r
867                                                 taskEXIT_CRITICAL();\r
868                                                 traceQUEUE_RECEIVE_FAILED( pxQueue );\r
869                                                 return errQUEUE_EMPTY;\r
870                                         }\r
871                                         else if( xEntryTimeSet == pdFALSE )\r
872                                         {\r
873                                                 vTaskSetTimeOutState( &xTimeOut );\r
874                                                 xEntryTimeSet = pdTRUE;\r
875                                         }\r
876                                 }\r
877                         }\r
878                         taskEXIT_CRITICAL();\r
879 \r
880                         taskENTER_CRITICAL();\r
881                         {\r
882                                 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
883                                 {\r
884                                         if( prvIsQueueEmpty( pxQueue ) != pdFALSE )\r
885                                         {\r
886                                                 traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );\r
887 \r
888                                                 #if ( configUSE_MUTEXES == 1 )\r
889                                                 {\r
890                                                         if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
891                                                         {\r
892                                                                 portENTER_CRITICAL();\r
893                                                                 {\r
894                                                                         vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );\r
895                                                                 }\r
896                                                                 portEXIT_CRITICAL();\r
897                                                         }\r
898                                                 }\r
899                                                 #endif\r
900 \r
901                                                 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );\r
902                                                 portYIELD_WITHIN_API();\r
903                                         }\r
904                                 }\r
905                                 else\r
906                                 {\r
907                                         taskEXIT_CRITICAL();\r
908                                         traceQUEUE_RECEIVE_FAILED( pxQueue );\r
909                                         return errQUEUE_EMPTY;\r
910                                 }\r
911                         }\r
912                         taskEXIT_CRITICAL();\r
913                 }\r
914         }\r
915 \r
916 \r
917 #endif /* configUSE_ALTERNATIVE_API */\r
918 /*-----------------------------------------------------------*/\r
919 \r
920 signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle xQueue, const void * const pvItemToQueue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portBASE_TYPE xCopyPosition )\r
921 {\r
922 signed portBASE_TYPE xReturn;\r
923 unsigned portBASE_TYPE uxSavedInterruptStatus;\r
924 xQUEUE *pxQueue;\r
925 \r
926         pxQueue = ( xQUEUE * ) xQueue;\r
927         configASSERT( pxQueue );\r
928         configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );\r
929 \r
930         /* Similar to xQueueGenericSend, except we don't block if there is no room\r
931         in the queue.  Also we don't directly wake a task that was blocked on a\r
932         queue read, instead we return a flag to say whether a context switch is\r
933         required or not (i.e. has a task with a higher priority than us been woken\r
934         by this post). */\r
935         uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();\r
936         {\r
937                 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
938                 {\r
939                         traceQUEUE_SEND_FROM_ISR( pxQueue );\r
940 \r
941                         prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );\r
942 \r
943                         /* If the queue is locked we do not alter the event list.  This will\r
944                         be done when the queue is unlocked later. */\r
945                         if( pxQueue->xTxLock == queueUNLOCKED )\r
946                         {\r
947                                 #if ( configUSE_QUEUE_SETS == 1 )\r
948                                 {\r
949                                         if( pxQueue->pxQueueSetContainer != NULL )\r
950                                         {\r
951                                                 if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) == pdTRUE )\r
952                                                 {\r
953                                                         /* The queue is a member of a queue set, and posting\r
954                                                         to the queue set caused a higher priority task to\r
955                                                         unblock.  A context switch is required. */\r
956                                                         if( pxHigherPriorityTaskWoken != NULL )\r
957                                                         {\r
958                                                                 *pxHigherPriorityTaskWoken = pdTRUE;\r
959                                                         }\r
960                                                 }\r
961                                         }\r
962                                         else\r
963                                         {\r
964                                                 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
965                                                 {\r
966                                                         if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
967                                                         {\r
968                                                                 /* The task waiting has a higher priority so record that a\r
969                                                                 context switch is required. */\r
970                                                                 if( pxHigherPriorityTaskWoken != NULL )\r
971                                                                 {\r
972                                                                         *pxHigherPriorityTaskWoken = pdTRUE;\r
973                                                                 }\r
974                                                         }\r
975                                                 }\r
976                                         }\r
977                                 }\r
978                                 #else /* configUSE_QUEUE_SETS */\r
979                                 {\r
980                                         if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
981                                         {\r
982                                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
983                                                 {\r
984                                                         /* The task waiting has a higher priority so record that a\r
985                                                         context switch is required. */\r
986                                                         if( pxHigherPriorityTaskWoken != NULL )\r
987                                                         {\r
988                                                                 *pxHigherPriorityTaskWoken = pdTRUE;\r
989                                                         }\r
990                                                 }\r
991                                         }\r
992                                 }\r
993                                 #endif /* configUSE_QUEUE_SETS */\r
994                         }\r
995                         else\r
996                         {\r
997                                 /* Increment the lock count so the task that unlocks the queue\r
998                                 knows that data was posted while it was locked. */\r
999                                 ++( pxQueue->xTxLock );\r
1000                         }\r
1001 \r
1002                         xReturn = pdPASS;\r
1003                 }\r
1004                 else\r
1005                 {\r
1006                         traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue );\r
1007                         xReturn = errQUEUE_FULL;\r
1008                 }\r
1009         }\r
1010         portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );\r
1011 \r
1012         return xReturn;\r
1013 }\r
1014 /*-----------------------------------------------------------*/\r
1015 \r
1016 signed portBASE_TYPE xQueueGenericReceive( xQueueHandle xQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )\r
1017 {\r
1018 signed portBASE_TYPE xEntryTimeSet = pdFALSE;\r
1019 xTimeOutType xTimeOut;\r
1020 signed char *pcOriginalReadPosition;\r
1021 xQUEUE *pxQueue;\r
1022 \r
1023         pxQueue = ( xQUEUE * ) xQueue;\r
1024         configASSERT( pxQueue );\r
1025         configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );\r
1026 \r
1027         /* This function relaxes the coding standard somewhat to allow return\r
1028         statements within the function itself.  This is done in the interest\r
1029         of execution time efficiency. */\r
1030 \r
1031         for( ;; )\r
1032         {\r
1033                 taskENTER_CRITICAL();\r
1034                 {\r
1035                         /* Is there data in the queue now?  To be running we must be\r
1036                         the highest priority task wanting to access the queue. */\r
1037                         if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
1038                         {\r
1039                                 /* Remember our read position in case we are just peeking. */\r
1040                                 pcOriginalReadPosition = pxQueue->pcReadFrom;\r
1041 \r
1042                                 prvCopyDataFromQueue( pxQueue, pvBuffer );\r
1043 \r
1044                                 if( xJustPeeking == pdFALSE )\r
1045                                 {\r
1046                                         traceQUEUE_RECEIVE( pxQueue );\r
1047 \r
1048                                         /* We are actually removing data. */\r
1049                                         --( pxQueue->uxMessagesWaiting );\r
1050 \r
1051                                         #if ( configUSE_MUTEXES == 1 )\r
1052                                         {\r
1053                                                 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
1054                                                 {\r
1055                                                         /* Record the information required to implement\r
1056                                                         priority inheritance should it become necessary. */\r
1057                                                         pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();\r
1058                                                 }\r
1059                                         }\r
1060                                         #endif\r
1061 \r
1062                                         if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )\r
1063                                         {\r
1064                                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )\r
1065                                                 {\r
1066                                                         portYIELD_WITHIN_API();\r
1067                                                 }\r
1068                                         }\r
1069                                 }\r
1070                                 else\r
1071                                 {\r
1072                                         traceQUEUE_PEEK( pxQueue );\r
1073 \r
1074                                         /* The data is not being removed, so reset the read\r
1075                                         pointer. */\r
1076                                         pxQueue->pcReadFrom = pcOriginalReadPosition;\r
1077 \r
1078                                         /* The data is being left in the queue, so see if there are\r
1079                                         any other tasks waiting for the data. */\r
1080                                         if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
1081                                         {\r
1082                                                 /* Tasks that are removed from the event list will get added to\r
1083                                                 the pending ready list as the scheduler is still suspended. */\r
1084                                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
1085                                                 {\r
1086                                                         /* The task waiting has a higher priority than this task. */\r
1087                                                         portYIELD_WITHIN_API();\r
1088                                                 }\r
1089                                         }\r
1090                                 }\r
1091 \r
1092                                 taskEXIT_CRITICAL();\r
1093                                 return pdPASS;\r
1094                         }\r
1095                         else\r
1096                         {\r
1097                                 if( xTicksToWait == ( portTickType ) 0 )\r
1098                                 {\r
1099                                         /* The queue was empty and no block time is specified (or\r
1100                                         the block time has expired) so leave now. */\r
1101                                         taskEXIT_CRITICAL();\r
1102                                         traceQUEUE_RECEIVE_FAILED( pxQueue );\r
1103                                         return errQUEUE_EMPTY;\r
1104                                 }\r
1105                                 else if( xEntryTimeSet == pdFALSE )\r
1106                                 {\r
1107                                         /* The queue was empty and a block time was specified so\r
1108                                         configure the timeout structure. */\r
1109                                         vTaskSetTimeOutState( &xTimeOut );\r
1110                                         xEntryTimeSet = pdTRUE;\r
1111                                 }\r
1112                         }\r
1113                 }\r
1114                 taskEXIT_CRITICAL();\r
1115 \r
1116                 /* Interrupts and other tasks can send to and receive from the queue\r
1117                 now the critical section has been exited. */\r
1118 \r
1119                 vTaskSuspendAll();\r
1120                 prvLockQueue( pxQueue );\r
1121 \r
1122                 /* Update the timeout state to see if it has expired yet. */\r
1123                 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
1124                 {\r
1125                         if( prvIsQueueEmpty( pxQueue ) != pdFALSE )\r
1126                         {\r
1127                                 traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );\r
1128 \r
1129                                 #if ( configUSE_MUTEXES == 1 )\r
1130                                 {\r
1131                                         if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
1132                                         {\r
1133                                                 portENTER_CRITICAL();\r
1134                                                 {\r
1135                                                         vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );\r
1136                                                 }\r
1137                                                 portEXIT_CRITICAL();\r
1138                                         }\r
1139                                 }\r
1140                                 #endif\r
1141 \r
1142                                 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );\r
1143                                 prvUnlockQueue( pxQueue );\r
1144                                 if( xTaskResumeAll() == pdFALSE )\r
1145                                 {\r
1146                                         portYIELD_WITHIN_API();\r
1147                                 }\r
1148                         }\r
1149                         else\r
1150                         {\r
1151                                 /* Try again. */\r
1152                                 prvUnlockQueue( pxQueue );\r
1153                                 ( void ) xTaskResumeAll();\r
1154                         }\r
1155                 }\r
1156                 else\r
1157                 {\r
1158                         prvUnlockQueue( pxQueue );\r
1159                         ( void ) xTaskResumeAll();\r
1160                         traceQUEUE_RECEIVE_FAILED( pxQueue );\r
1161                         return errQUEUE_EMPTY;\r
1162                 }\r
1163         }\r
1164 }\r
1165 /*-----------------------------------------------------------*/\r
1166 \r
1167 signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle xQueue, void * const pvBuffer, signed portBASE_TYPE *pxHigherPriorityTaskWoken )\r
1168 {\r
1169 signed portBASE_TYPE xReturn;\r
1170 unsigned portBASE_TYPE uxSavedInterruptStatus;\r
1171 xQUEUE *pxQueue;\r
1172 \r
1173         pxQueue = ( xQUEUE * ) xQueue;\r
1174         configASSERT( pxQueue );\r
1175         configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );\r
1176 \r
1177         uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();\r
1178         {\r
1179                 /* We cannot block from an ISR, so check there is data available. */\r
1180                 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
1181                 {\r
1182                         traceQUEUE_RECEIVE_FROM_ISR( pxQueue );\r
1183 \r
1184                         prvCopyDataFromQueue( pxQueue, pvBuffer );\r
1185                         --( pxQueue->uxMessagesWaiting );\r
1186 \r
1187                         /* If the queue is locked we will not modify the event list.  Instead\r
1188                         we update the lock count so the task that unlocks the queue will know\r
1189                         that an ISR has removed data while the queue was locked. */\r
1190                         if( pxQueue->xRxLock == queueUNLOCKED )\r
1191                         {\r
1192                                 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )\r
1193                                 {\r
1194                                         if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
1195                                         {\r
1196                                                 /* The task waiting has a higher priority than us so\r
1197                                                 force a context switch. */\r
1198                                                 if( pxHigherPriorityTaskWoken != NULL )\r
1199                                                 {\r
1200                                                         *pxHigherPriorityTaskWoken = pdTRUE;\r
1201                                                 }\r
1202                                         }\r
1203                                 }\r
1204                         }\r
1205                         else\r
1206                         {\r
1207                                 /* Increment the lock count so the task that unlocks the queue\r
1208                                 knows that data was removed while it was locked. */\r
1209                                 ++( pxQueue->xRxLock );\r
1210                         }\r
1211 \r
1212                         xReturn = pdPASS;\r
1213                 }\r
1214                 else\r
1215                 {\r
1216                         xReturn = pdFAIL;\r
1217                         traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue );\r
1218                 }\r
1219         }\r
1220         portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );\r
1221 \r
1222         return xReturn;\r
1223 }\r
1224 /*-----------------------------------------------------------*/\r
1225 \r
1226 unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle xQueue )\r
1227 {\r
1228 unsigned portBASE_TYPE uxReturn;\r
1229 \r
1230         configASSERT( xQueue );\r
1231 \r
1232         taskENTER_CRITICAL();\r
1233                 uxReturn = ( ( xQUEUE * ) xQueue )->uxMessagesWaiting;\r
1234         taskEXIT_CRITICAL();\r
1235 \r
1236         return uxReturn;\r
1237 }\r
1238 /*-----------------------------------------------------------*/\r
1239 \r
1240 unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle xQueue )\r
1241 {\r
1242 unsigned portBASE_TYPE uxReturn;\r
1243 \r
1244         configASSERT( xQueue );\r
1245 \r
1246         uxReturn = ( ( xQUEUE * ) xQueue )->uxMessagesWaiting;\r
1247 \r
1248         return uxReturn;\r
1249 }\r
1250 /*-----------------------------------------------------------*/\r
1251 \r
1252 void vQueueDelete( xQueueHandle xQueue )\r
1253 {\r
1254 xQUEUE *pxQueue;\r
1255 \r
1256         pxQueue = ( xQUEUE * ) xQueue;\r
1257         configASSERT( pxQueue );\r
1258 \r
1259         traceQUEUE_DELETE( pxQueue );\r
1260         #if ( configQUEUE_REGISTRY_SIZE > 0 )\r
1261         {\r
1262                 prvQueueUnregisterQueue( pxQueue );\r
1263         }\r
1264         #endif\r
1265         vPortFree( pxQueue->pcHead );\r
1266         vPortFree( pxQueue );\r
1267 }\r
1268 /*-----------------------------------------------------------*/\r
1269 \r
1270 #if ( configUSE_TRACE_FACILITY == 1 )\r
1271 \r
1272         unsigned char ucQueueGetQueueNumber( xQueueHandle xQueue )\r
1273         {\r
1274                 return ( ( xQUEUE * ) xQueue )->ucQueueNumber;\r
1275         }\r
1276 \r
1277 #endif /* configUSE_TRACE_FACILITY */\r
1278 /*-----------------------------------------------------------*/\r
1279 \r
1280 #if ( configUSE_TRACE_FACILITY == 1 )\r
1281 \r
1282         void vQueueSetQueueNumber( xQueueHandle xQueue, unsigned char ucQueueNumber )\r
1283         {\r
1284                 ( ( xQUEUE * ) xQueue )->ucQueueNumber = ucQueueNumber;\r
1285         }\r
1286 \r
1287 #endif /* configUSE_TRACE_FACILITY */\r
1288 /*-----------------------------------------------------------*/\r
1289 \r
1290 #if ( configUSE_TRACE_FACILITY == 1 )\r
1291 \r
1292         unsigned char ucQueueGetQueueType( xQueueHandle xQueue )\r
1293         {\r
1294                 return ( ( xQUEUE * ) xQueue )->ucQueueType;\r
1295         }\r
1296 \r
1297 #endif /* configUSE_TRACE_FACILITY */\r
1298 /*-----------------------------------------------------------*/\r
1299 \r
1300 static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition )\r
1301 {\r
1302         if( pxQueue->uxItemSize == ( unsigned portBASE_TYPE ) 0 )\r
1303         {\r
1304                 #if ( configUSE_MUTEXES == 1 )\r
1305                 {\r
1306                         if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
1307                         {\r
1308                                 /* The mutex is no longer being held. */\r
1309                                 vTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder );\r
1310                                 pxQueue->pxMutexHolder = NULL;\r
1311                         }\r
1312                 }\r
1313                 #endif\r
1314         }\r
1315         else if( xPosition == queueSEND_TO_BACK )\r
1316         {\r
1317                 memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( size_t ) pxQueue->uxItemSize );\r
1318                 pxQueue->pcWriteTo += pxQueue->uxItemSize;\r
1319                 if( pxQueue->pcWriteTo >= pxQueue->pcTail )\r
1320                 {\r
1321                         pxQueue->pcWriteTo = pxQueue->pcHead;\r
1322                 }\r
1323         }\r
1324         else\r
1325         {\r
1326                 memcpy( ( void * ) pxQueue->pcReadFrom, pvItemToQueue, ( size_t ) pxQueue->uxItemSize );\r
1327                 pxQueue->pcReadFrom -= pxQueue->uxItemSize;\r
1328                 if( pxQueue->pcReadFrom < pxQueue->pcHead )\r
1329                 {\r
1330                         pxQueue->pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize );\r
1331                 }\r
1332         }\r
1333 \r
1334         ++( pxQueue->uxMessagesWaiting );\r
1335 }\r
1336 /*-----------------------------------------------------------*/\r
1337 \r
1338 static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer )\r
1339 {\r
1340         if( pxQueue->uxQueueType != queueQUEUE_IS_MUTEX )\r
1341         {\r
1342                 pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
1343                 if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
1344                 {\r
1345                         pxQueue->pcReadFrom = pxQueue->pcHead;\r
1346                 }\r
1347                 memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( size_t ) pxQueue->uxItemSize );\r
1348         }\r
1349 }\r
1350 /*-----------------------------------------------------------*/\r
1351 \r
1352 static void prvUnlockQueue( xQUEUE *pxQueue )\r
1353 {\r
1354         /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */\r
1355 \r
1356         /* The lock counts contains the number of extra data items placed or\r
1357         removed from the queue while the queue was locked.  When a queue is\r
1358         locked items can be added or removed, but the event lists cannot be\r
1359         updated. */\r
1360         taskENTER_CRITICAL();\r
1361         {\r
1362                 /* See if data was added to the queue while it was locked. */\r
1363                 while( pxQueue->xTxLock > queueLOCKED_UNMODIFIED )\r
1364                 {\r
1365                         /* Data was posted while the queue was locked.  Are any tasks\r
1366                         blocked waiting for data to become available? */\r
1367                         #if ( configUSE_QUEUE_SETS == 1 )\r
1368                         {\r
1369                                 if( pxQueue->pxQueueSetContainer != NULL )\r
1370                                 {\r
1371                                         if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) == pdTRUE )\r
1372                                         {\r
1373                                                 /* The queue is a member of a queue set, and posting to\r
1374                                                 the queue set caused a higher priority task to unblock.\r
1375                                                 A context switch is required. */\r
1376                                                 vTaskMissedYield();\r
1377                                         }\r
1378                                 }\r
1379                                 else\r
1380                                 {\r
1381                                         /* Tasks that are removed from the event list will get added to\r
1382                                         the pending ready list as the scheduler is still suspended. */\r
1383                                         if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
1384                                         {\r
1385                                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
1386                                                 {\r
1387                                                         /* The task waiting has a higher priority so record that a\r
1388                                                         context switch is required. */\r
1389                                                         vTaskMissedYield();\r
1390                                                 }\r
1391                                         }\r
1392                                         else\r
1393                                         {\r
1394                                                 break;\r
1395                                         }\r
1396                                 }\r
1397                         }\r
1398                         #else /* configUSE_QUEUE_SETS */\r
1399                         {\r
1400                                 /* Tasks that are removed from the event list will get added to\r
1401                                 the pending ready list as the scheduler is still suspended. */\r
1402                                 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
1403                                 {\r
1404                                         if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
1405                                         {\r
1406                                                 /* The task waiting has a higher priority so record that a\r
1407                                                 context switch is required. */\r
1408                                                 vTaskMissedYield();\r
1409                                         }\r
1410                                 }\r
1411                                 else\r
1412                                 {\r
1413                                         break;\r
1414                                 }\r
1415                         }\r
1416                         #endif /* configUSE_QUEUE_SETS */\r
1417 \r
1418                         --( pxQueue->xTxLock );\r
1419                 }\r
1420 \r
1421                 pxQueue->xTxLock = queueUNLOCKED;\r
1422         }\r
1423         taskEXIT_CRITICAL();\r
1424 \r
1425         /* Do the same for the Rx lock. */\r
1426         taskENTER_CRITICAL();\r
1427         {\r
1428                 while( pxQueue->xRxLock > queueLOCKED_UNMODIFIED )\r
1429                 {\r
1430                         if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )\r
1431                         {\r
1432                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
1433                                 {\r
1434                                         vTaskMissedYield();\r
1435                                 }\r
1436 \r
1437                                 --( pxQueue->xRxLock );\r
1438                         }\r
1439                         else\r
1440                         {\r
1441                                 break;\r
1442                         }\r
1443                 }\r
1444 \r
1445                 pxQueue->xRxLock = queueUNLOCKED;\r
1446         }\r
1447         taskEXIT_CRITICAL();\r
1448 }\r
1449 /*-----------------------------------------------------------*/\r
1450 \r
1451 static signed portBASE_TYPE prvIsQueueEmpty( const xQUEUE *pxQueue )\r
1452 {\r
1453 signed portBASE_TYPE xReturn;\r
1454 \r
1455         taskENTER_CRITICAL();\r
1456         {\r
1457                 if( pxQueue->uxMessagesWaiting == 0 )\r
1458                 {\r
1459                         xReturn = pdTRUE;\r
1460                 }\r
1461                 else\r
1462                 {\r
1463                         xReturn = pdFALSE;\r
1464                 }\r
1465         }\r
1466         taskEXIT_CRITICAL();\r
1467 \r
1468         return xReturn;\r
1469 }\r
1470 /*-----------------------------------------------------------*/\r
1471 \r
1472 signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle xQueue )\r
1473 {\r
1474 signed portBASE_TYPE xReturn;\r
1475 \r
1476         configASSERT( xQueue );\r
1477         if( ( ( xQUEUE * ) xQueue )->uxMessagesWaiting == 0 )\r
1478         {\r
1479                 xReturn = pdTRUE;\r
1480         }\r
1481         else\r
1482         {\r
1483                 xReturn = pdFALSE;\r
1484         }\r
1485 \r
1486         return xReturn;\r
1487 }\r
1488 /*-----------------------------------------------------------*/\r
1489 \r
1490 static signed portBASE_TYPE prvIsQueueFull( const xQUEUE *pxQueue )\r
1491 {\r
1492 signed portBASE_TYPE xReturn;\r
1493 \r
1494         taskENTER_CRITICAL();\r
1495         {\r
1496                 if( pxQueue->uxMessagesWaiting == pxQueue->uxLength )\r
1497                 {\r
1498                         xReturn = pdTRUE;\r
1499                 }\r
1500                 else\r
1501                 {\r
1502                         xReturn = pdFALSE;\r
1503                 }\r
1504         }\r
1505         taskEXIT_CRITICAL();\r
1506 \r
1507         return xReturn;\r
1508 }\r
1509 /*-----------------------------------------------------------*/\r
1510 \r
1511 signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle xQueue )\r
1512 {\r
1513 signed portBASE_TYPE xReturn;\r
1514 \r
1515         configASSERT( xQueue );\r
1516         if( ( ( xQUEUE * ) xQueue )->uxMessagesWaiting == ( ( xQUEUE * ) xQueue )->uxLength )\r
1517         {\r
1518                 xReturn = pdTRUE;\r
1519         }\r
1520         else\r
1521         {\r
1522                 xReturn = pdFALSE;\r
1523         }\r
1524 \r
1525         return xReturn;\r
1526 }\r
1527 /*-----------------------------------------------------------*/\r
1528 \r
1529 #if ( configUSE_CO_ROUTINES == 1 )\r
1530 \r
1531         signed portBASE_TYPE xQueueCRSend( xQueueHandle xQueue, const void *pvItemToQueue, portTickType xTicksToWait )\r
1532         {\r
1533         signed portBASE_TYPE xReturn;\r
1534         xQUEUE *pxQueue;\r
1535 \r
1536                 pxQueue = ( xQUEUE * ) xQueue;\r
1537 \r
1538                 /* If the queue is already full we may have to block.  A critical section\r
1539                 is required to prevent an interrupt removing something from the queue\r
1540                 between the check to see if the queue is full and blocking on the queue. */\r
1541                 portDISABLE_INTERRUPTS();\r
1542                 {\r
1543                         if( prvIsQueueFull( pxQueue ) != pdFALSE )\r
1544                         {\r
1545                                 /* The queue is full - do we want to block or just leave without\r
1546                                 posting? */\r
1547                                 if( xTicksToWait > ( portTickType ) 0 )\r
1548                                 {\r
1549                                         /* As this is called from a coroutine we cannot block directly, but\r
1550                                         return indicating that we need to block. */\r
1551                                         vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToSend ) );\r
1552                                         portENABLE_INTERRUPTS();\r
1553                                         return errQUEUE_BLOCKED;\r
1554                                 }\r
1555                                 else\r
1556                                 {\r
1557                                         portENABLE_INTERRUPTS();\r
1558                                         return errQUEUE_FULL;\r
1559                                 }\r
1560                         }\r
1561                 }\r
1562                 portENABLE_INTERRUPTS();\r
1563 \r
1564                 portDISABLE_INTERRUPTS();\r
1565                 {\r
1566                         if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
1567                         {\r
1568                                 /* There is room in the queue, copy the data into the queue. */\r
1569                                 prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );\r
1570                                 xReturn = pdPASS;\r
1571 \r
1572                                 /* Were any co-routines waiting for data to become available? */\r
1573                                 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
1574                                 {\r
1575                                         /* In this instance the co-routine could be placed directly\r
1576                                         into the ready list as we are within a critical section.\r
1577                                         Instead the same pending ready list mechanism is used as if\r
1578                                         the event were caused from within an interrupt. */\r
1579                                         if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
1580                                         {\r
1581                                                 /* The co-routine waiting has a higher priority so record\r
1582                                                 that a yield might be appropriate. */\r
1583                                                 xReturn = errQUEUE_YIELD;\r
1584                                         }\r
1585                                 }\r
1586                         }\r
1587                         else\r
1588                         {\r
1589                                 xReturn = errQUEUE_FULL;\r
1590                         }\r
1591                 }\r
1592                 portENABLE_INTERRUPTS();\r
1593 \r
1594                 return xReturn;\r
1595         }\r
1596 \r
1597 #endif /* configUSE_CO_ROUTINES */\r
1598 /*-----------------------------------------------------------*/\r
1599 \r
1600 #if ( configUSE_CO_ROUTINES == 1 )\r
1601 \r
1602         signed portBASE_TYPE xQueueCRReceive( xQueueHandle xQueue, void *pvBuffer, portTickType xTicksToWait )\r
1603         {\r
1604         signed portBASE_TYPE xReturn;\r
1605         xQUEUE *pxQueue;\r
1606 \r
1607                 pxQueue = ( xQUEUE * ) xQueue;\r
1608 \r
1609                 /* If the queue is already empty we may have to block.  A critical section\r
1610                 is required to prevent an interrupt adding something to the queue\r
1611                 between the check to see if the queue is empty and blocking on the queue. */\r
1612                 portDISABLE_INTERRUPTS();\r
1613                 {\r
1614                         if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 )\r
1615                         {\r
1616                                 /* There are no messages in the queue, do we want to block or just\r
1617                                 leave with nothing? */\r
1618                                 if( xTicksToWait > ( portTickType ) 0 )\r
1619                                 {\r
1620                                         /* As this is a co-routine we cannot block directly, but return\r
1621                                         indicating that we need to block. */\r
1622                                         vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToReceive ) );\r
1623                                         portENABLE_INTERRUPTS();\r
1624                                         return errQUEUE_BLOCKED;\r
1625                                 }\r
1626                                 else\r
1627                                 {\r
1628                                         portENABLE_INTERRUPTS();\r
1629                                         return errQUEUE_FULL;\r
1630                                 }\r
1631                         }\r
1632                 }\r
1633                 portENABLE_INTERRUPTS();\r
1634 \r
1635                 portDISABLE_INTERRUPTS();\r
1636                 {\r
1637                         if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
1638                         {\r
1639                                 /* Data is available from the queue. */\r
1640                                 pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
1641                                 if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
1642                                 {\r
1643                                         pxQueue->pcReadFrom = pxQueue->pcHead;\r
1644                                 }\r
1645                                 --( pxQueue->uxMessagesWaiting );\r
1646                                 memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
1647 \r
1648                                 xReturn = pdPASS;\r
1649 \r
1650                                 /* Were any co-routines waiting for space to become available? */\r
1651                                 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )\r
1652                                 {\r
1653                                         /* In this instance the co-routine could be placed directly\r
1654                                         into the ready list as we are within a critical section.\r
1655                                         Instead the same pending ready list mechanism is used as if\r
1656                                         the event were caused from within an interrupt. */\r
1657                                         if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
1658                                         {\r
1659                                                 xReturn = errQUEUE_YIELD;\r
1660                                         }\r
1661                                 }\r
1662                         }\r
1663                         else\r
1664                         {\r
1665                                 xReturn = pdFAIL;\r
1666                         }\r
1667                 }\r
1668                 portENABLE_INTERRUPTS();\r
1669 \r
1670                 return xReturn;\r
1671         }\r
1672 \r
1673 #endif /* configUSE_CO_ROUTINES */\r
1674 /*-----------------------------------------------------------*/\r
1675 \r
1676 #if ( configUSE_CO_ROUTINES == 1 )\r
1677 \r
1678         signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle xQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken )\r
1679         {\r
1680         xQUEUE *pxQueue;\r
1681 \r
1682                 pxQueue = ( xQUEUE * ) xQueue;\r
1683 \r
1684                 /* Cannot block within an ISR so if there is no space on the queue then\r
1685                 exit without doing anything. */\r
1686                 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
1687                 {\r
1688                         prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );\r
1689 \r
1690                         /* We only want to wake one co-routine per ISR, so check that a\r
1691                         co-routine has not already been woken. */\r
1692                         if( xCoRoutinePreviouslyWoken == pdFALSE )\r
1693                         {\r
1694                                 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
1695                                 {\r
1696                                         if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
1697                                         {\r
1698                                                 return pdTRUE;\r
1699                                         }\r
1700                                 }\r
1701                         }\r
1702                 }\r
1703 \r
1704                 return xCoRoutinePreviouslyWoken;\r
1705         }\r
1706 \r
1707 #endif /* configUSE_CO_ROUTINES */\r
1708 /*-----------------------------------------------------------*/\r
1709 \r
1710 #if ( configUSE_CO_ROUTINES == 1 )\r
1711 \r
1712         signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle xQueue, void *pvBuffer, signed portBASE_TYPE *pxCoRoutineWoken )\r
1713         {\r
1714         signed portBASE_TYPE xReturn;\r
1715         xQUEUE * pxQueue;\r
1716 \r
1717                 pxQueue = ( xQUEUE * ) xQueue;\r
1718 \r
1719                 /* We cannot block from an ISR, so check there is data available. If\r
1720                 not then just leave without doing anything. */\r
1721                 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
1722                 {\r
1723                         /* Copy the data from the queue. */\r
1724                         pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
1725                         if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
1726                         {\r
1727                                 pxQueue->pcReadFrom = pxQueue->pcHead;\r
1728                         }\r
1729                         --( pxQueue->uxMessagesWaiting );\r
1730                         memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
1731 \r
1732                         if( ( *pxCoRoutineWoken ) == pdFALSE )\r
1733                         {\r
1734                                 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )\r
1735                                 {\r
1736                                         if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
1737                                         {\r
1738                                                 *pxCoRoutineWoken = pdTRUE;\r
1739                                         }\r
1740                                 }\r
1741                         }\r
1742 \r
1743                         xReturn = pdPASS;\r
1744                 }\r
1745                 else\r
1746                 {\r
1747                         xReturn = pdFAIL;\r
1748                 }\r
1749 \r
1750                 return xReturn;\r
1751         }\r
1752 \r
1753 #endif /* configUSE_CO_ROUTINES */\r
1754 /*-----------------------------------------------------------*/\r
1755 \r
1756 #if ( configQUEUE_REGISTRY_SIZE > 0 )\r
1757 \r
1758         void vQueueAddToRegistry( xQueueHandle xQueue, signed char *pcQueueName )\r
1759         {\r
1760         unsigned portBASE_TYPE ux;\r
1761 \r
1762                 /* See if there is an empty space in the registry.  A NULL name denotes\r
1763                 a free slot. */\r
1764                 for( ux = ( unsigned portBASE_TYPE ) 0U; ux < ( unsigned portBASE_TYPE ) configQUEUE_REGISTRY_SIZE; ux++ )\r
1765                 {\r
1766                         if( xQueueRegistry[ ux ].pcQueueName == NULL )\r
1767                         {\r
1768                                 /* Store the information on this queue. */\r
1769                                 xQueueRegistry[ ux ].pcQueueName = pcQueueName;\r
1770                                 xQueueRegistry[ ux ].xHandle = xQueue;\r
1771                                 break;\r
1772                         }\r
1773                 }\r
1774         }\r
1775 \r
1776 #endif /* configQUEUE_REGISTRY_SIZE */\r
1777 /*-----------------------------------------------------------*/\r
1778 \r
1779 #if ( configQUEUE_REGISTRY_SIZE > 0 )\r
1780 \r
1781         static void prvQueueUnregisterQueue( xQueueHandle xQueue )\r
1782         {\r
1783         unsigned portBASE_TYPE ux;\r
1784 \r
1785                 /* See if the handle of the queue being unregistered in actually in the\r
1786                 registry. */\r
1787                 for( ux = ( unsigned portBASE_TYPE ) 0U; ux < ( unsigned portBASE_TYPE ) configQUEUE_REGISTRY_SIZE; ux++ )\r
1788                 {\r
1789                         if( xQueueRegistry[ ux ].xHandle == xQueue )\r
1790                         {\r
1791                                 /* Set the name to NULL to show that this slot if free again. */\r
1792                                 xQueueRegistry[ ux ].pcQueueName = NULL;\r
1793                                 break;\r
1794                         }\r
1795                 }\r
1796 \r
1797         }\r
1798 \r
1799 #endif /* configQUEUE_REGISTRY_SIZE */\r
1800 /*-----------------------------------------------------------*/\r
1801 \r
1802 #if ( configUSE_TIMERS == 1 )\r
1803 \r
1804         void vQueueWaitForMessageRestricted( xQueueHandle xQueue, portTickType xTicksToWait )\r
1805         {\r
1806         xQUEUE *pxQueue;\r
1807 \r
1808                 pxQueue = ( xQUEUE * ) xQueue;\r
1809 \r
1810                 /* This function should not be called by application code hence the\r
1811                 'Restricted' in its name.  It is not part of the public API.  It is\r
1812                 designed for use by kernel code, and has special calling requirements.\r
1813                 It can result in vListInsert() being called on a list that can only\r
1814                 possibly ever have one item in it, so the list will be fast, but even\r
1815                 so it should be called with the scheduler locked and not from a critical\r
1816                 section. */\r
1817 \r
1818                 /* Only do anything if there are no messages in the queue.  This function\r
1819                 will not actually cause the task to block, just place it on a blocked\r
1820                 list.  It will not block until the scheduler is unlocked - at which\r
1821                 time a yield will be performed.  If an item is added to the queue while\r
1822                 the queue is locked, and the calling task blocks on the queue, then the\r
1823                 calling task will be immediately unblocked when the queue is unlocked. */\r
1824                 prvLockQueue( pxQueue );\r
1825                 if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0U )\r
1826                 {\r
1827                         /* There is nothing in the queue, block for the specified period. */\r
1828                         vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );\r
1829                 }\r
1830                 prvUnlockQueue( pxQueue );\r
1831         }\r
1832 \r
1833 #endif /* configUSE_TIMERS */\r
1834 /*-----------------------------------------------------------*/\r
1835 \r
1836 #if ( configUSE_QUEUE_SETS == 1 )\r
1837 \r
1838         xQueueSetHandle xQueueCreateSet( unsigned portBASE_TYPE uxEventQueueLength )\r
1839         {\r
1840         xQueueSetHandle pxQueue;\r
1841 \r
1842                 pxQueue = xQueueGenericCreate( uxEventQueueLength, sizeof( xQUEUE * ), queueQUEUE_TYPE_SET );\r
1843 \r
1844                 return pxQueue;\r
1845         }\r
1846 \r
1847 #endif /* configUSE_QUEUE_SETS */\r
1848 /*-----------------------------------------------------------*/\r
1849 \r
1850 #if ( configUSE_QUEUE_SETS == 1 )\r
1851 \r
1852         portBASE_TYPE xQueueAddToSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet )\r
1853         {\r
1854         portBASE_TYPE xReturn;\r
1855 \r
1856                 if( ( ( xQUEUE * ) xQueueOrSemaphore )->pxQueueSetContainer != NULL )\r
1857                 {\r
1858                         xReturn = pdFAIL;\r
1859                 }\r
1860                 else\r
1861                 {\r
1862                         taskENTER_CRITICAL();\r
1863                         {\r
1864                                 ( ( xQUEUE * ) xQueueOrSemaphore )->pxQueueSetContainer = xQueueSet;\r
1865                         }\r
1866                         taskEXIT_CRITICAL();\r
1867                         xReturn = pdPASS;\r
1868                 }\r
1869 \r
1870                 return xReturn;\r
1871         }\r
1872 \r
1873 #endif /* configUSE_QUEUE_SETS */\r
1874 /*-----------------------------------------------------------*/\r
1875 \r
1876 #if ( configUSE_QUEUE_SETS == 1 )\r
1877 \r
1878         portBASE_TYPE xQueueRemoveFromSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet )\r
1879         {\r
1880         portBASE_TYPE xReturn;\r
1881         xQUEUE *pxQueueOrSemaphore;\r
1882 \r
1883                 pxQueueOrSemaphore = ( xQUEUE * ) xQueueOrSemaphore;\r
1884 \r
1885                 if( pxQueueOrSemaphore->pxQueueSetContainer != xQueueSet )\r
1886                 {\r
1887                         /* The queue was not a member of the set. */\r
1888                         xReturn = pdFAIL;\r
1889                 }\r
1890                 else if( pxQueueOrSemaphore->uxMessagesWaiting != 0 )\r
1891                 {\r
1892                         /* It is dangerous to remove a queue from a set when the queue is\r
1893                         not empty because the queue set will still hold pending events for\r
1894                         the queue. */\r
1895                         xReturn = pdFAIL;\r
1896                 }\r
1897                 else\r
1898                 {\r
1899                         taskENTER_CRITICAL();\r
1900                         {\r
1901                                 /* The queue is no longer contained in the set. */\r
1902                                 pxQueueOrSemaphore->pxQueueSetContainer = NULL;\r
1903                         }\r
1904                         taskEXIT_CRITICAL();\r
1905                         xReturn = pdPASS;\r
1906                 }\r
1907 \r
1908                 return xReturn;\r
1909         }\r
1910 \r
1911 #endif /* configUSE_QUEUE_SETS */\r
1912 /*-----------------------------------------------------------*/\r
1913 \r
1914 #if ( configUSE_QUEUE_SETS == 1 )\r
1915 \r
1916         xQueueSetMemberHandle xQueueSelectFromSet( xQueueSetHandle xQueueSet, portTickType xBlockTimeTicks )\r
1917         {\r
1918         xQueueSetMemberHandle xReturn = NULL;\r
1919 \r
1920                 xQueueGenericReceive( ( xQueueHandle ) xQueueSet, &xReturn, xBlockTimeTicks, pdFALSE );\r
1921                 return xReturn;\r
1922         }\r
1923 \r
1924 #endif /* configUSE_QUEUE_SETS */\r
1925 /*-----------------------------------------------------------*/\r
1926 \r
1927 #if ( configUSE_QUEUE_SETS == 1 )\r
1928 \r
1929         xQueueSetMemberHandle xQueueSelectFromSetFromISR( xQueueSetHandle xQueueSet )\r
1930         {\r
1931         xQueueSetMemberHandle xReturn = NULL;\r
1932 \r
1933                 xQueueReceiveFromISR( ( xQueueHandle ) xQueueSet, &xReturn, NULL );\r
1934                 return xReturn;\r
1935         }\r
1936 \r
1937 #endif /* configUSE_QUEUE_SETS */\r
1938 /*-----------------------------------------------------------*/\r
1939 \r
1940 #if ( configUSE_QUEUE_SETS == 1 )\r
1941 \r
1942         static portBASE_TYPE prvNotifyQueueSetContainer( xQUEUE *pxQueue, portBASE_TYPE xCopyPosition )\r
1943         {\r
1944         xQUEUE *pxQueueSetContainer = pxQueue->pxQueueSetContainer;\r
1945         portBASE_TYPE xReturn = pdFALSE;\r
1946 \r
1947                 configASSERT( pxQueueSetContainer );\r
1948                 configASSERT( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength );\r
1949 \r
1950                 if( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength )\r
1951                 {\r
1952                         traceQUEUE_SEND( pxQueueSetContainer );\r
1953                         /* The data copies is the handle of the queue that contains data. */\r
1954                         prvCopyDataToQueue( pxQueueSetContainer, &pxQueue, xCopyPosition );\r
1955                         if( listLIST_IS_EMPTY( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) == pdFALSE )\r
1956                         {\r
1957                                 if( xTaskRemoveFromEventList( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) != pdFALSE )\r
1958                                 {\r
1959                                         /* The task waiting has a higher priority */\r
1960                                         xReturn = pdTRUE;\r
1961                                 }\r
1962                         }\r
1963                 }\r
1964 \r
1965                 return xReturn;\r
1966         }\r
1967 \r
1968 #endif /* configUSE_QUEUE_SETS */\r
1969 \r