]> git.sur5r.net Git - freertos/blob - Source/queue.c
Update Cortex M3 ports to ensure 8 byte alignment.
[freertos] / Source / queue.c
1 /*\r
2     FreeRTOS V6.0.1 - Copyright (C) 2009 Real Time Engineers Ltd.\r
3 \r
4     ***************************************************************************\r
5     *                                                                         *\r
6     * If you are:                                                             *\r
7     *                                                                         *\r
8     *    + New to FreeRTOS,                                                   *\r
9     *    + Wanting to learn FreeRTOS or multitasking in general quickly       *\r
10     *    + Looking for basic training,                                        *\r
11     *    + Wanting to improve your FreeRTOS skills and productivity           *\r
12     *                                                                         *\r
13     * then take a look at the FreeRTOS eBook                                  *\r
14     *                                                                         *\r
15     *        "Using the FreeRTOS Real Time Kernel - a Practical Guide"        *\r
16     *                  http://www.FreeRTOS.org/Documentation                  *\r
17     *                                                                         *\r
18     * A pdf reference manual is also available.  Both are usually delivered   *\r
19     * to your inbox within 20 minutes to two hours when purchased between 8am *\r
20     * and 8pm GMT (although please allow up to 24 hours in case of            *\r
21     * exceptional circumstances).  Thank you for your support!                *\r
22     *                                                                         *\r
23     ***************************************************************************\r
24 \r
25     This file is part of the FreeRTOS distribution.\r
26 \r
27     FreeRTOS is free software; you can redistribute it and/or modify it under\r
28     the terms of the GNU General Public License (version 2) as published by the\r
29     Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
30     ***NOTE*** The exception to the GPL is included to allow you to distribute\r
31     a combined work that includes FreeRTOS without being obliged to provide the\r
32     source code for proprietary components outside of the FreeRTOS kernel.\r
33     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT\r
34     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
35     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\r
36     more details. You should have received a copy of the GNU General Public \r
37     License and the FreeRTOS license exception along with FreeRTOS; if not it \r
38     can be viewed here: http://www.freertos.org/a00114.html and also obtained \r
39     by writing to Richard Barry, contact details for whom are available on the\r
40     FreeRTOS WEB site.\r
41 \r
42     1 tab == 4 spaces!\r
43 \r
44     http://www.FreeRTOS.org - Documentation, latest information, license and\r
45     contact details.\r
46 \r
47     http://www.SafeRTOS.com - A version that is certified for use in safety\r
48     critical systems.\r
49 \r
50     http://www.OpenRTOS.com - Commercial support, development, porting,\r
51     licensing and training services.\r
52 */\r
53 \r
54 #include <stdlib.h>\r
55 #include <string.h>\r
56 \r
57 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining\r
58 all the API functions to use the MPU wrappers.  That should only be done when\r
59 task.h is included from an application file. */\r
60 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
61 \r
62 #include "FreeRTOS.h"\r
63 #include "task.h"\r
64 #include "croutine.h"\r
65 \r
66 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
67 \r
68 /*-----------------------------------------------------------\r
69  * PUBLIC LIST API documented in list.h\r
70  *----------------------------------------------------------*/\r
71 \r
72 /* Constants used with the cRxLock and cTxLock structure members. */\r
73 #define queueUNLOCKED                                   ( ( signed portBASE_TYPE ) -1 )\r
74 #define queueLOCKED_UNMODIFIED                  ( ( signed portBASE_TYPE ) 0 )\r
75 \r
76 #define queueERRONEOUS_UNBLOCK                  ( -1 )\r
77 \r
78 /* For internal use only. */\r
79 #define queueSEND_TO_BACK                               ( 0 )\r
80 #define queueSEND_TO_FRONT                              ( 1 )\r
81 \r
82 /* Effectively make a union out of the xQUEUE structure. */\r
83 #define pxMutexHolder                                   pcTail\r
84 #define uxQueueType                                             pcHead\r
85 #define uxRecursiveCallCount                    pcReadFrom\r
86 #define queueQUEUE_IS_MUTEX                             NULL\r
87 \r
88 /* Semaphores do not actually store or copy data, so have an items size of\r
89 zero. */\r
90 #define queueSEMAPHORE_QUEUE_ITEM_LENGTH ( 0 )\r
91 #define queueDONT_BLOCK                                  ( ( portTickType ) 0 )\r
92 #define queueMUTEX_GIVE_BLOCK_TIME               ( ( portTickType ) 0 )\r
93 \r
94 /*\r
95  * Definition of the queue used by the scheduler.\r
96  * Items are queued by copy, not reference.\r
97  */\r
98 typedef struct QueueDefinition\r
99 {\r
100         signed char *pcHead;                            /*< Points to the beginning of the queue storage area. */\r
101         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
102 \r
103         signed char *pcWriteTo;                         /*< Points to the free next place in the storage area. */\r
104         signed char *pcReadFrom;                        /*< Points to the last place that a queued item was read from. */\r
105 \r
106         xList xTasksWaitingToSend;                              /*< List of tasks that are blocked waiting to post onto this queue.  Stored in priority order. */\r
107         xList xTasksWaitingToReceive;                   /*< List of tasks that are blocked waiting to read from this queue.  Stored in priority order. */\r
108 \r
109         volatile unsigned portBASE_TYPE uxMessagesWaiting;/*< The number of items currently in the queue. */\r
110         unsigned portBASE_TYPE uxLength;                /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */\r
111         unsigned portBASE_TYPE uxItemSize;              /*< The size of each items that the queue will hold. */\r
112 \r
113         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
114         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
115 \r
116 } xQUEUE;\r
117 /*-----------------------------------------------------------*/\r
118 \r
119 /*\r
120  * Inside this file xQueueHandle is a pointer to a xQUEUE structure.\r
121  * To keep the definition private the API header file defines it as a\r
122  * pointer to void.\r
123  */\r
124 typedef xQUEUE * xQueueHandle;\r
125 \r
126 /*\r
127  * Prototypes for public functions are included here so we don't have to\r
128  * include the API header file (as it defines xQueueHandle differently).  These\r
129  * functions are documented in the API header file.\r
130  */\r
131 xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize ) PRIVILEGED_FUNCTION;\r
132 signed portBASE_TYPE xQueueGenericSend( xQueueHandle xQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) PRIVILEGED_FUNCTION;\r
133 unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;\r
134 void vQueueDelete( xQueueHandle xQueue ) PRIVILEGED_FUNCTION;\r
135 signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portBASE_TYPE xCopyPosition ) PRIVILEGED_FUNCTION;\r
136 signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ) PRIVILEGED_FUNCTION;\r
137 signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken ) PRIVILEGED_FUNCTION;\r
138 xQueueHandle xQueueCreateMutex( void ) PRIVILEGED_FUNCTION;\r
139 xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount ) PRIVILEGED_FUNCTION;\r
140 portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle xMutex, portTickType xBlockTime ) PRIVILEGED_FUNCTION;\r
141 portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle xMutex ) PRIVILEGED_FUNCTION;\r
142 signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) PRIVILEGED_FUNCTION;\r
143 signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ) PRIVILEGED_FUNCTION;\r
144 signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;\r
145 signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;\r
146 unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;\r
147 \r
148 /*\r
149  * Co-routine queue functions differ from task queue functions.  Co-routines are\r
150  * an optional component.\r
151  */\r
152 #if configUSE_CO_ROUTINES == 1\r
153         signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken ) PRIVILEGED_FUNCTION;\r
154         signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken ) PRIVILEGED_FUNCTION;\r
155         signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;\r
156         signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;\r
157 #endif\r
158 \r
159 /*\r
160  * The queue registry is just a means for kernel aware debuggers to locate\r
161  * queue structures.  It has no other purpose so is an optional component.\r
162  */\r
163 #if configQUEUE_REGISTRY_SIZE > 0\r
164 \r
165         /* The type stored within the queue registry array.  This allows a name\r
166         to be assigned to each queue making kernel aware debugging a little\r
167         more user friendly. */\r
168         typedef struct QUEUE_REGISTRY_ITEM\r
169         {\r
170                 signed char *pcQueueName;\r
171                 xQueueHandle xHandle;\r
172         } xQueueRegistryItem;\r
173 \r
174         /* The queue registry is simply an array of xQueueRegistryItem structures.\r
175         The pcQueueName member of a structure being NULL is indicative of the\r
176         array position being vacant. */\r
177         xQueueRegistryItem xQueueRegistry[ configQUEUE_REGISTRY_SIZE ];\r
178 \r
179         /* Removes a queue from the registry by simply setting the pcQueueName\r
180         member to NULL. */\r
181         static void vQueueUnregisterQueue( xQueueHandle xQueue ) PRIVILEGED_FUNCTION;\r
182         void vQueueAddToRegistry( xQueueHandle xQueue, signed char *pcQueueName ) PRIVILEGED_FUNCTION;\r
183 #endif\r
184 \r
185 /*\r
186  * Unlocks a queue locked by a call to prvLockQueue.  Locking a queue does not\r
187  * prevent an ISR from adding or removing items to the queue, but does prevent\r
188  * an ISR from removing tasks from the queue event lists.  If an ISR finds a\r
189  * queue is locked it will instead increment the appropriate queue lock count\r
190  * to indicate that a task may require unblocking.  When the queue in unlocked\r
191  * these lock counts are inspected, and the appropriate action taken.\r
192  */\r
193 static void prvUnlockQueue( xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;\r
194 \r
195 /*\r
196  * Uses a critical section to determine if there is any data in a queue.\r
197  *\r
198  * @return pdTRUE if the queue contains no items, otherwise pdFALSE.\r
199  */\r
200 static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;\r
201 \r
202 /*\r
203  * Uses a critical section to determine if there is any space in a queue.\r
204  *\r
205  * @return pdTRUE if there is no space, otherwise pdFALSE;\r
206  */\r
207 static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;\r
208 \r
209 /*\r
210  * Copies an item into the queue, either at the front of the queue or the\r
211  * back of the queue.\r
212  */\r
213 static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition ) PRIVILEGED_FUNCTION;\r
214 \r
215 /*\r
216  * Copies an item out of a queue.\r
217  */\r
218 static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer ) PRIVILEGED_FUNCTION;\r
219 /*-----------------------------------------------------------*/\r
220 \r
221 /*\r
222  * Macro to mark a queue as locked.  Locking a queue prevents an ISR from\r
223  * accessing the queue event lists.\r
224  */\r
225 #define prvLockQueue( pxQueue )                                                 \\r
226 {                                                                                                               \\r
227         taskENTER_CRITICAL();                                                           \\r
228         {                                                                                                       \\r
229                 if( pxQueue->xRxLock == queueUNLOCKED )                 \\r
230                 {                                                                                               \\r
231                         pxQueue->xRxLock = queueLOCKED_UNMODIFIED;      \\r
232                 }                                                                                               \\r
233                 if( pxQueue->xTxLock == queueUNLOCKED )                 \\r
234                 {                                                                                               \\r
235                         pxQueue->xTxLock = queueLOCKED_UNMODIFIED;      \\r
236                 }                                                                                               \\r
237         }                                                                                                       \\r
238         taskEXIT_CRITICAL();                                                            \\r
239 }\r
240 /*-----------------------------------------------------------*/\r
241 \r
242 \r
243 /*-----------------------------------------------------------\r
244  * PUBLIC QUEUE MANAGEMENT API documented in queue.h\r
245  *----------------------------------------------------------*/\r
246 \r
247 xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize )\r
248 {\r
249 xQUEUE *pxNewQueue;\r
250 size_t xQueueSizeInBytes;\r
251 \r
252         /* Allocate the new queue structure. */\r
253         if( uxQueueLength > ( unsigned portBASE_TYPE ) 0 )\r
254         {\r
255                 pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );\r
256                 if( pxNewQueue != NULL )\r
257                 {\r
258                         /* Create the list of pointers to queue items.  The queue is one byte\r
259                         longer than asked for to make wrap checking easier/faster. */\r
260                         xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ) + ( size_t ) 1;\r
261 \r
262                         pxNewQueue->pcHead = ( signed char * ) pvPortMalloc( xQueueSizeInBytes );\r
263                         if( pxNewQueue->pcHead != NULL )\r
264                         {\r
265                                 /* Initialise the queue members as described above where the\r
266                                 queue type is defined. */\r
267                                 pxNewQueue->pcTail = pxNewQueue->pcHead + ( uxQueueLength * uxItemSize );\r
268                                 pxNewQueue->uxMessagesWaiting = 0;\r
269                                 pxNewQueue->pcWriteTo = pxNewQueue->pcHead;\r
270                                 pxNewQueue->pcReadFrom = pxNewQueue->pcHead + ( ( uxQueueLength - 1 ) * uxItemSize );\r
271                                 pxNewQueue->uxLength = uxQueueLength;\r
272                                 pxNewQueue->uxItemSize = uxItemSize;\r
273                                 pxNewQueue->xRxLock = queueUNLOCKED;\r
274                                 pxNewQueue->xTxLock = queueUNLOCKED;\r
275 \r
276                                 /* Likewise ensure the event queues start with the correct state. */\r
277                                 vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );\r
278                                 vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );\r
279 \r
280                                 traceQUEUE_CREATE( pxNewQueue );\r
281                                 return  pxNewQueue;\r
282                         }\r
283                         else\r
284                         {\r
285                                 traceQUEUE_CREATE_FAILED();\r
286                                 vPortFree( pxNewQueue );\r
287                         }\r
288                 }\r
289         }\r
290 \r
291         /* Will only reach here if we could not allocate enough memory or no memory\r
292         was required. */\r
293         return NULL;\r
294 }\r
295 /*-----------------------------------------------------------*/\r
296 \r
297 #if ( configUSE_MUTEXES == 1 )\r
298 \r
299         xQueueHandle xQueueCreateMutex( void )\r
300         {\r
301         xQUEUE *pxNewQueue;\r
302 \r
303                 /* Allocate the new queue structure. */\r
304                 pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );\r
305                 if( pxNewQueue != NULL )\r
306                 {\r
307                         /* Information required for priority inheritance. */\r
308                         pxNewQueue->pxMutexHolder = NULL;\r
309                         pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX;\r
310 \r
311                         /* Queues used as a mutex no data is actually copied into or out\r
312                         of the queue. */\r
313                         pxNewQueue->pcWriteTo = NULL;\r
314                         pxNewQueue->pcReadFrom = NULL;\r
315 \r
316                         /* Each mutex has a length of 1 (like a binary semaphore) and\r
317                         an item size of 0 as nothing is actually copied into or out\r
318                         of the mutex. */\r
319                         pxNewQueue->uxMessagesWaiting = 0;\r
320                         pxNewQueue->uxLength = 1;\r
321                         pxNewQueue->uxItemSize = 0;\r
322                         pxNewQueue->xRxLock = queueUNLOCKED;\r
323                         pxNewQueue->xTxLock = queueUNLOCKED;\r
324 \r
325                         /* Ensure the event queues start with the correct state. */\r
326                         vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );\r
327                         vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );\r
328 \r
329                         /* Start with the semaphore in the expected state. */\r
330                         xQueueGenericSend( pxNewQueue, NULL, 0, queueSEND_TO_BACK );\r
331 \r
332                         traceCREATE_MUTEX( pxNewQueue );\r
333                 }\r
334                 else\r
335                 {\r
336                         traceCREATE_MUTEX_FAILED();\r
337                 }\r
338 \r
339                 return pxNewQueue;\r
340         }\r
341 \r
342 #endif /* configUSE_MUTEXES */\r
343 /*-----------------------------------------------------------*/\r
344 \r
345 #if configUSE_RECURSIVE_MUTEXES == 1\r
346 \r
347         portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle pxMutex )\r
348         {\r
349         portBASE_TYPE xReturn;\r
350 \r
351                 /* If this is the task that holds the mutex then pxMutexHolder will not\r
352                 change outside of this task.  If this task does not hold the mutex then\r
353                 pxMutexHolder can never coincidentally equal the tasks handle, and as\r
354                 this is the only condition we are interested in it does not matter if\r
355                 pxMutexHolder is accessed simultaneously by another task.  Therefore no\r
356                 mutual exclusion is required to test the pxMutexHolder variable. */\r
357                 if( pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle() )\r
358                 {\r
359                         traceGIVE_MUTEX_RECURSIVE( pxMutex );\r
360 \r
361                         /* uxRecursiveCallCount cannot be zero if pxMutexHolder is equal to\r
362                         the task handle, therefore no underflow check is required.  Also,\r
363                         uxRecursiveCallCount is only modified by the mutex holder, and as\r
364                         there can only be one, no mutual exclusion is required to modify the\r
365                         uxRecursiveCallCount member. */\r
366                         ( pxMutex->uxRecursiveCallCount )--;\r
367 \r
368                         /* Have we unwound the call count? */\r
369                         if( pxMutex->uxRecursiveCallCount == 0 )\r
370                         {\r
371                                 /* Return the mutex.  This will automatically unblock any other\r
372                                 task that might be waiting to access the mutex. */\r
373                                 xQueueGenericSend( pxMutex, NULL, queueMUTEX_GIVE_BLOCK_TIME, queueSEND_TO_BACK );\r
374                         }\r
375 \r
376                         xReturn = pdPASS;\r
377                 }\r
378                 else\r
379                 {\r
380                         /* We cannot give the mutex because we are not the holder. */\r
381                         xReturn = pdFAIL;\r
382 \r
383                         traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex );\r
384                 }\r
385 \r
386                 return xReturn;\r
387         }\r
388 \r
389 #endif /* configUSE_RECURSIVE_MUTEXES */\r
390 /*-----------------------------------------------------------*/\r
391 \r
392 #if configUSE_RECURSIVE_MUTEXES == 1\r
393 \r
394         portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle pxMutex, portTickType xBlockTime )\r
395         {\r
396         portBASE_TYPE xReturn;\r
397 \r
398                 /* Comments regarding mutual exclusion as per those within\r
399                 xQueueGiveMutexRecursive(). */\r
400 \r
401                 traceTAKE_MUTEX_RECURSIVE( pxMutex );\r
402 \r
403                 if( pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle() )\r
404                 {\r
405                         ( pxMutex->uxRecursiveCallCount )++;\r
406                         xReturn = pdPASS;\r
407                 }\r
408                 else\r
409                 {\r
410                         xReturn = xQueueGenericReceive( pxMutex, NULL, xBlockTime, pdFALSE );\r
411 \r
412                         /* pdPASS will only be returned if we successfully obtained the mutex,\r
413                         we may have blocked to reach here. */\r
414                         if( xReturn == pdPASS )\r
415                         {\r
416                                 ( pxMutex->uxRecursiveCallCount )++;\r
417                         }\r
418                 }\r
419 \r
420                 return xReturn;\r
421         }\r
422 \r
423 #endif /* configUSE_RECURSIVE_MUTEXES */\r
424 /*-----------------------------------------------------------*/\r
425 \r
426 #if configUSE_COUNTING_SEMAPHORES == 1\r
427 \r
428         xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount )\r
429         {\r
430         xQueueHandle pxHandle;\r
431 \r
432                 pxHandle = xQueueCreate( ( unsigned portBASE_TYPE ) uxCountValue, queueSEMAPHORE_QUEUE_ITEM_LENGTH );\r
433 \r
434                 if( pxHandle != NULL )\r
435                 {\r
436                         pxHandle->uxMessagesWaiting = uxInitialCount;\r
437 \r
438                         traceCREATE_COUNTING_SEMAPHORE();\r
439                 }\r
440                 else\r
441                 {\r
442                         traceCREATE_COUNTING_SEMAPHORE_FAILED();\r
443                 }\r
444 \r
445                 return pxHandle;\r
446         }\r
447 \r
448 #endif /* configUSE_COUNTING_SEMAPHORES */\r
449 /*-----------------------------------------------------------*/\r
450 \r
451 signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )\r
452 {\r
453 signed portBASE_TYPE xEntryTimeSet = pdFALSE;\r
454 xTimeOutType xTimeOut;\r
455 \r
456         /* This function relaxes the coding standard somewhat to allow return\r
457         statements within the function itself.  This is done in the interest\r
458         of execution time efficiency. */\r
459         for( ;; )\r
460         {\r
461                 taskENTER_CRITICAL();\r
462                 {\r
463                         /* Is there room on the queue now?  To be running we must be\r
464                         the highest priority task wanting to access the queue. */\r
465                         if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
466                         {\r
467                                 traceQUEUE_SEND( pxQueue );\r
468                                 prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );\r
469 \r
470                                 /* If there was a task waiting for data to arrive on the\r
471                                 queue then unblock it now. */\r
472                                 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
473                                 {\r
474                                         if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )\r
475                                         {\r
476                                                 /* The unblocked task has a priority higher than\r
477                                                 our own so yield immediately.  Yes it is ok to do\r
478                                                 this from within the critical section - the kernel\r
479                                                 takes care of that. */\r
480                                                 portYIELD_WITHIN_API();\r
481                                         }\r
482                                 }\r
483 \r
484                                 taskEXIT_CRITICAL();\r
485 \r
486                                 /* Return to the original privilege level before exiting the\r
487                                 function. */\r
488                                 return pdPASS;\r
489                         }\r
490                         else\r
491                         {\r
492                                 if( xTicksToWait == ( portTickType ) 0 )\r
493                                 {\r
494                                         /* The queue was full and no block time is specified (or\r
495                                         the block time has expired) so leave now. */\r
496                                         taskEXIT_CRITICAL();\r
497 \r
498                                         /* Return to the original privilege level before exiting\r
499                                         the function. */\r
500                                         traceQUEUE_SEND_FAILED( pxQueue );\r
501                                         return errQUEUE_FULL;\r
502                                 }\r
503                                 else if( xEntryTimeSet == pdFALSE )\r
504                                 {\r
505                                         /* The queue was full and a block time was specified so\r
506                                         configure the timeout structure. */\r
507                                         vTaskSetTimeOutState( &xTimeOut );\r
508                                         xEntryTimeSet = pdTRUE;\r
509                                 }\r
510                         }\r
511                 }\r
512                 taskEXIT_CRITICAL();\r
513 \r
514                 /* Interrupts and other tasks can send to and receive from the queue\r
515                 now the critical section has been exited. */\r
516 \r
517                 vTaskSuspendAll();\r
518                 prvLockQueue( pxQueue );\r
519 \r
520                 /* Update the timeout state to see if it has expired yet. */\r
521                 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
522                 {\r
523                         if( prvIsQueueFull( pxQueue ) )\r
524                         {\r
525                                 traceBLOCKING_ON_QUEUE_SEND( pxQueue );\r
526                                 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );\r
527 \r
528                                 /* Unlocking the queue means queue events can effect the\r
529                                 event list.  It is possible     that interrupts occurring now\r
530                                 remove this task from the event list again - but as the\r
531                                 scheduler is suspended the task will go onto the pending\r
532                                 ready last instead of the actual ready list. */\r
533                                 prvUnlockQueue( pxQueue );\r
534 \r
535                                 /* Resuming the scheduler will move tasks from the pending\r
536                                 ready list into the ready list - so it is feasible that this\r
537                                 task is already in a ready list before it yields - in which\r
538                                 case the yield will not cause a context switch unless there\r
539                                 is also a higher priority task in the pending ready list. */\r
540                                 if( !xTaskResumeAll() )\r
541                                 {\r
542                                         portYIELD_WITHIN_API();\r
543                                 }\r
544                         }\r
545                         else\r
546                         {\r
547                                 /* Try again. */\r
548                                 prvUnlockQueue( pxQueue );\r
549                                 ( void ) xTaskResumeAll();\r
550                         }\r
551                 }\r
552                 else\r
553                 {\r
554                         /* The timeout has expired. */\r
555                         prvUnlockQueue( pxQueue );\r
556                         ( void ) xTaskResumeAll();\r
557 \r
558                         /* Return to the original privilege level before exiting the\r
559                         function. */\r
560                         traceQUEUE_SEND_FAILED( pxQueue );\r
561                         return errQUEUE_FULL;\r
562                 }\r
563         }\r
564 }\r
565 /*-----------------------------------------------------------*/\r
566 \r
567 #if configUSE_ALTERNATIVE_API == 1\r
568 \r
569         signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )\r
570         {\r
571         signed portBASE_TYPE xEntryTimeSet = pdFALSE;\r
572         xTimeOutType xTimeOut;\r
573 \r
574                 for( ;; )\r
575                 {\r
576                         taskENTER_CRITICAL();\r
577                         {\r
578                                 /* Is there room on the queue now?  To be running we must be\r
579                                 the highest priority task wanting to access the queue. */\r
580                                 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
581                                 {\r
582                                         traceQUEUE_SEND( pxQueue );\r
583                                         prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );\r
584 \r
585                                         /* If there was a task waiting for data to arrive on the\r
586                                         queue then unblock it now. */\r
587                                         if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
588                                         {\r
589                                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )\r
590                                                 {\r
591                                                         /* The unblocked task has a priority higher than\r
592                                                         our own so yield immediately. */\r
593                                                         portYIELD_WITHIN_API();\r
594                                                 }\r
595                                         }\r
596 \r
597                                         taskEXIT_CRITICAL();\r
598                                         return pdPASS;\r
599                                 }\r
600                                 else\r
601                                 {\r
602                                         if( xTicksToWait == ( portTickType ) 0 )\r
603                                         {\r
604                                                 taskEXIT_CRITICAL();\r
605                                                 return errQUEUE_FULL;\r
606                                         }\r
607                                         else if( xEntryTimeSet == pdFALSE )\r
608                                         {\r
609                                                 vTaskSetTimeOutState( &xTimeOut );\r
610                                                 xEntryTimeSet = pdTRUE;\r
611                                         }\r
612                                 }\r
613                         }\r
614                         taskEXIT_CRITICAL();\r
615 \r
616                         taskENTER_CRITICAL();\r
617                         {\r
618                                 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
619                                 {\r
620                                         if( prvIsQueueFull( pxQueue ) )\r
621                                         {\r
622                                                 traceBLOCKING_ON_QUEUE_SEND( pxQueue );\r
623                                                 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );\r
624                                                 portYIELD_WITHIN_API();\r
625                                         }\r
626                                 }\r
627                                 else\r
628                                 {\r
629                                         taskEXIT_CRITICAL();\r
630                                         traceQUEUE_SEND_FAILED( pxQueue );\r
631                                         return errQUEUE_FULL;\r
632                                 }\r
633                         }\r
634                         taskEXIT_CRITICAL();\r
635                 }\r
636         }\r
637 \r
638 #endif /* configUSE_ALTERNATIVE_API */\r
639 /*-----------------------------------------------------------*/\r
640 \r
641 #if configUSE_ALTERNATIVE_API == 1\r
642 \r
643         signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )\r
644         {\r
645         signed portBASE_TYPE xEntryTimeSet = pdFALSE;\r
646         xTimeOutType xTimeOut;\r
647         signed char *pcOriginalReadPosition;\r
648 \r
649                 for( ;; )\r
650                 {\r
651                         taskENTER_CRITICAL();\r
652                         {\r
653                                 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
654                                 {\r
655                                         /* Remember our read position in case we are just peeking. */\r
656                                         pcOriginalReadPosition = pxQueue->pcReadFrom;\r
657 \r
658                                         prvCopyDataFromQueue( pxQueue, pvBuffer );\r
659 \r
660                                         if( xJustPeeking == pdFALSE )\r
661                                         {\r
662                                                 traceQUEUE_RECEIVE( pxQueue );\r
663 \r
664                                                 /* We are actually removing data. */\r
665                                                 --( pxQueue->uxMessagesWaiting );\r
666 \r
667                                                 #if ( configUSE_MUTEXES == 1 )\r
668                                                 {\r
669                                                         if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
670                                                         {\r
671                                                                 /* Record the information required to implement\r
672                                                                 priority inheritance should it become necessary. */\r
673                                                                 pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();\r
674                                                         }\r
675                                                 }\r
676                                                 #endif\r
677 \r
678                                                 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )\r
679                                                 {\r
680                                                         if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )\r
681                                                         {\r
682                                                                 portYIELD_WITHIN_API();\r
683                                                         }\r
684                                                 }\r
685                                         }\r
686                                         else\r
687                                         {\r
688                                                 traceQUEUE_PEEK( pxQueue );\r
689 \r
690                                                 /* We are not removing the data, so reset our read\r
691                                                 pointer. */\r
692                                                 pxQueue->pcReadFrom = pcOriginalReadPosition;\r
693 \r
694                                                 /* The data is being left in the queue, so see if there are\r
695                                                 any other tasks waiting for the data. */\r
696                                                 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
697                                                 {\r
698                                                         /* Tasks that are removed from the event list will get added to\r
699                                                         the pending ready list as the scheduler is still suspended. */\r
700                                                         if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
701                                                         {\r
702                                                                 /* The task waiting has a higher priority than this task. */\r
703                                                                 portYIELD_WITHIN_API();\r
704                                                         }\r
705                                                 }\r
706 \r
707                                         }\r
708 \r
709                                         taskEXIT_CRITICAL();\r
710                                         return pdPASS;\r
711                                 }\r
712                                 else\r
713                                 {\r
714                                         if( xTicksToWait == ( portTickType ) 0 )\r
715                                         {\r
716                                                 taskEXIT_CRITICAL();\r
717                                                 traceQUEUE_RECEIVE_FAILED( pxQueue );\r
718                                                 return errQUEUE_EMPTY;\r
719                                         }\r
720                                         else if( xEntryTimeSet == pdFALSE )\r
721                                         {\r
722                                                 vTaskSetTimeOutState( &xTimeOut );\r
723                                                 xEntryTimeSet = pdTRUE;\r
724                                         }\r
725                                 }\r
726                         }\r
727                         taskEXIT_CRITICAL();\r
728 \r
729                         taskENTER_CRITICAL();\r
730                         {\r
731                                 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
732                                 {\r
733                                         if( prvIsQueueEmpty( pxQueue ) )\r
734                                         {\r
735                                                 traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );\r
736 \r
737                                                 #if ( configUSE_MUTEXES == 1 )\r
738                                                 {\r
739                                                         if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
740                                                         {\r
741                                                                 portENTER_CRITICAL();\r
742                                                                         vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );\r
743                                                                 portEXIT_CRITICAL();\r
744                                                         }\r
745                                                 }\r
746                                                 #endif\r
747 \r
748                                                 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );\r
749                                                 portYIELD_WITHIN_API();\r
750                                         }\r
751                                 }\r
752                                 else\r
753                                 {\r
754                                         taskEXIT_CRITICAL();\r
755                                         traceQUEUE_RECEIVE_FAILED( pxQueue );\r
756                                         return errQUEUE_EMPTY;\r
757                                 }\r
758                         }\r
759                         taskEXIT_CRITICAL();\r
760                 }\r
761         }\r
762 \r
763 \r
764 #endif /* configUSE_ALTERNATIVE_API */\r
765 /*-----------------------------------------------------------*/\r
766 \r
767 signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portBASE_TYPE xCopyPosition )\r
768 {\r
769 signed portBASE_TYPE xReturn;\r
770 unsigned portBASE_TYPE uxSavedInterruptStatus;\r
771 \r
772         /* Similar to xQueueGenericSend, except we don't block if there is no room\r
773         in the queue.  Also we don't directly wake a task that was blocked on a\r
774         queue read, instead we return a flag to say whether a context switch is\r
775         required or not (i.e. has a task with a higher priority than us been woken\r
776         by this post). */\r
777         uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();\r
778         {\r
779                 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
780                 {\r
781                         traceQUEUE_SEND_FROM_ISR( pxQueue );\r
782 \r
783                         prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );\r
784 \r
785                         /* If the queue is locked we do not alter the event list.  This will\r
786                         be done when the queue is unlocked later. */\r
787                         if( pxQueue->xTxLock == queueUNLOCKED )\r
788                         {\r
789                                 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
790                                 {\r
791                                         if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
792                                         {\r
793                                                 /* The task waiting has a higher priority so record that a\r
794                                                 context switch is required. */\r
795                                                 *pxHigherPriorityTaskWoken = pdTRUE;\r
796                                         }\r
797                                 }\r
798                         }\r
799                         else\r
800                         {\r
801                                 /* Increment the lock count so the task that unlocks the queue\r
802                                 knows that data was posted while it was locked. */\r
803                                 ++( pxQueue->xTxLock );\r
804                         }\r
805 \r
806                         xReturn = pdPASS;\r
807                 }\r
808                 else\r
809                 {\r
810                         traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue );\r
811                         xReturn = errQUEUE_FULL;\r
812                 }\r
813         }\r
814         portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );\r
815 \r
816         return xReturn;\r
817 }\r
818 /*-----------------------------------------------------------*/\r
819 \r
820 signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )\r
821 {\r
822 signed portBASE_TYPE xEntryTimeSet = pdFALSE;\r
823 xTimeOutType xTimeOut;\r
824 signed char *pcOriginalReadPosition;\r
825 \r
826         /* This function relaxes the coding standard somewhat to allow return\r
827         statements within the function itself.  This is done in the interest\r
828         of execution time efficiency. */\r
829 \r
830         for( ;; )\r
831         {\r
832                 taskENTER_CRITICAL();\r
833                 {\r
834                         /* Is there data in the queue now?  To be running we must be\r
835                         the highest priority task wanting to access the queue. */\r
836                         if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
837                         {\r
838                                 /* Remember our read position in case we are just peeking. */\r
839                                 pcOriginalReadPosition = pxQueue->pcReadFrom;\r
840 \r
841                                 prvCopyDataFromQueue( pxQueue, pvBuffer );\r
842 \r
843                                 if( xJustPeeking == pdFALSE )\r
844                                 {\r
845                                         traceQUEUE_RECEIVE( pxQueue );\r
846 \r
847                                         /* We are actually removing data. */\r
848                                         --( pxQueue->uxMessagesWaiting );\r
849 \r
850                                         #if ( configUSE_MUTEXES == 1 )\r
851                                         {\r
852                                                 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
853                                                 {\r
854                                                         /* Record the information required to implement\r
855                                                         priority inheritance should it become necessary. */\r
856                                                         pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();\r
857                                                 }\r
858                                         }\r
859                                         #endif\r
860 \r
861                                         if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )\r
862                                         {\r
863                                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )\r
864                                                 {\r
865                                                         portYIELD_WITHIN_API();\r
866                                                 }\r
867                                         }\r
868                                 }\r
869                                 else\r
870                                 {\r
871                                         traceQUEUE_PEEK( pxQueue );\r
872 \r
873                                         /* We are not removing the data, so reset our read\r
874                                         pointer. */\r
875                                         pxQueue->pcReadFrom = pcOriginalReadPosition;\r
876 \r
877                                         /* The data is being left in the queue, so see if there are\r
878                                         any other tasks waiting for the data. */\r
879                                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
880                                         {\r
881                                                 /* Tasks that are removed from the event list will get added to\r
882                                                 the pending ready list as the scheduler is still suspended. */\r
883                                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
884                                                 {\r
885                                                         /* The task waiting has a higher priority than this task. */\r
886                                                         portYIELD_WITHIN_API();\r
887                                                 }\r
888                                         }\r
889 \r
890                                 }\r
891 \r
892                                 taskEXIT_CRITICAL();\r
893                                 return pdPASS;\r
894                         }\r
895                         else\r
896                         {\r
897                                 if( xTicksToWait == ( portTickType ) 0 )\r
898                                 {\r
899                                         /* The queue was empty and no block time is specified (or\r
900                                         the block time has expired) so leave now. */\r
901                                         taskEXIT_CRITICAL();\r
902                                         traceQUEUE_RECEIVE_FAILED( pxQueue );\r
903                                         return errQUEUE_EMPTY;\r
904                                 }\r
905                                 else if( xEntryTimeSet == pdFALSE )\r
906                                 {\r
907                                         /* The queue was empty and a block time was specified so\r
908                                         configure the timeout structure. */\r
909                                         vTaskSetTimeOutState( &xTimeOut );\r
910                                         xEntryTimeSet = pdTRUE;\r
911                                 }\r
912                         }\r
913                 }\r
914                 taskEXIT_CRITICAL();\r
915 \r
916                 /* Interrupts and other tasks can send to and receive from the queue\r
917                 now the critical section has been exited. */\r
918 \r
919                 vTaskSuspendAll();\r
920                 prvLockQueue( pxQueue );\r
921 \r
922                 /* Update the timeout state to see if it has expired yet. */\r
923                 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
924                 {\r
925                         if( prvIsQueueEmpty( pxQueue ) )\r
926                         {\r
927                                 traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );\r
928 \r
929                                 #if ( configUSE_MUTEXES == 1 )\r
930                                 {\r
931                                         if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
932                                         {\r
933                                                 portENTER_CRITICAL();\r
934                                                 {\r
935                                                         vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );\r
936                                                 }\r
937                                                 portEXIT_CRITICAL();\r
938                                         }\r
939                                 }\r
940                                 #endif\r
941 \r
942                                 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );\r
943                                 prvUnlockQueue( pxQueue );\r
944                                 if( !xTaskResumeAll() )\r
945                                 {\r
946                                         portYIELD_WITHIN_API();\r
947                                 }\r
948                         }\r
949                         else\r
950                         {\r
951                                 /* Try again. */\r
952                                 prvUnlockQueue( pxQueue );\r
953                                 ( void ) xTaskResumeAll();\r
954                         }\r
955                 }\r
956                 else\r
957                 {\r
958                         prvUnlockQueue( pxQueue );\r
959                         ( void ) xTaskResumeAll();\r
960                         traceQUEUE_RECEIVE_FAILED( pxQueue );\r
961                         return errQUEUE_EMPTY;\r
962                 }\r
963         }\r
964 }\r
965 /*-----------------------------------------------------------*/\r
966 \r
967 signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken )\r
968 {\r
969 signed portBASE_TYPE xReturn;\r
970 unsigned portBASE_TYPE uxSavedInterruptStatus;\r
971 \r
972         uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();\r
973         {\r
974                 /* We cannot block from an ISR, so check there is data available. */\r
975                 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
976                 {\r
977                         traceQUEUE_RECEIVE_FROM_ISR( pxQueue );\r
978 \r
979                         prvCopyDataFromQueue( pxQueue, pvBuffer );\r
980                         --( pxQueue->uxMessagesWaiting );\r
981 \r
982                         /* If the queue is locked we will not modify the event list.  Instead\r
983                         we update the lock count so the task that unlocks the queue will know\r
984                         that an ISR has removed data while the queue was locked. */\r
985                         if( pxQueue->xRxLock == queueUNLOCKED )\r
986                         {\r
987                                 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )\r
988                                 {\r
989                                         if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
990                                         {\r
991                                                 /* The task waiting has a higher priority than us so\r
992                                                 force a context switch. */\r
993                                                 *pxTaskWoken = pdTRUE;\r
994                                         }\r
995                                 }\r
996                         }\r
997                         else\r
998                         {\r
999                                 /* Increment the lock count so the task that unlocks the queue\r
1000                                 knows that data was removed while it was locked. */\r
1001                                 ++( pxQueue->xRxLock );\r
1002                         }\r
1003 \r
1004                         xReturn = pdPASS;\r
1005                 }\r
1006                 else\r
1007                 {\r
1008                         xReturn = pdFAIL;\r
1009                         traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue );\r
1010                 }\r
1011         }\r
1012         portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );\r
1013 \r
1014         return xReturn;\r
1015 }\r
1016 /*-----------------------------------------------------------*/\r
1017 \r
1018 unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle pxQueue )\r
1019 {\r
1020 unsigned portBASE_TYPE uxReturn;\r
1021 \r
1022         taskENTER_CRITICAL();\r
1023                 uxReturn = pxQueue->uxMessagesWaiting;\r
1024         taskEXIT_CRITICAL();\r
1025 \r
1026         return uxReturn;\r
1027 }\r
1028 /*-----------------------------------------------------------*/\r
1029 \r
1030 unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue )\r
1031 {\r
1032 unsigned portBASE_TYPE uxReturn;\r
1033 \r
1034         uxReturn = pxQueue->uxMessagesWaiting;\r
1035 \r
1036         return uxReturn;\r
1037 }\r
1038 /*-----------------------------------------------------------*/\r
1039 \r
1040 void vQueueDelete( xQueueHandle pxQueue )\r
1041 {\r
1042         traceQUEUE_DELETE( pxQueue );\r
1043         vQueueUnregisterQueue( pxQueue );\r
1044         vPortFree( pxQueue->pcHead );\r
1045         vPortFree( pxQueue );\r
1046 }\r
1047 /*-----------------------------------------------------------*/\r
1048 \r
1049 static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition )\r
1050 {\r
1051         if( pxQueue->uxItemSize == ( unsigned portBASE_TYPE ) 0 )\r
1052         {\r
1053                 #if ( configUSE_MUTEXES == 1 )\r
1054                 {\r
1055                         if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
1056                         {\r
1057                                 /* The mutex is no longer being held. */\r
1058                                 vTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder );\r
1059                                 pxQueue->pxMutexHolder = NULL;\r
1060                         }\r
1061                 }\r
1062                 #endif\r
1063         }\r
1064         else if( xPosition == queueSEND_TO_BACK )\r
1065         {\r
1066                 memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );\r
1067                 pxQueue->pcWriteTo += pxQueue->uxItemSize;\r
1068                 if( pxQueue->pcWriteTo >= pxQueue->pcTail )\r
1069                 {\r
1070                         pxQueue->pcWriteTo = pxQueue->pcHead;\r
1071                 }\r
1072         }\r
1073         else\r
1074         {\r
1075                 memcpy( ( void * ) pxQueue->pcReadFrom, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );\r
1076                 pxQueue->pcReadFrom -= pxQueue->uxItemSize;\r
1077                 if( pxQueue->pcReadFrom < pxQueue->pcHead )\r
1078                 {\r
1079                         pxQueue->pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize );\r
1080                 }\r
1081         }\r
1082 \r
1083         ++( pxQueue->uxMessagesWaiting );\r
1084 }\r
1085 /*-----------------------------------------------------------*/\r
1086 \r
1087 static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer )\r
1088 {\r
1089         if( pxQueue->uxQueueType != queueQUEUE_IS_MUTEX )\r
1090         {\r
1091                 pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
1092                 if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
1093                 {\r
1094                         pxQueue->pcReadFrom = pxQueue->pcHead;\r
1095                 }\r
1096                 memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
1097         }\r
1098 }\r
1099 /*-----------------------------------------------------------*/\r
1100 \r
1101 static void prvUnlockQueue( xQueueHandle pxQueue )\r
1102 {\r
1103         /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */\r
1104 \r
1105         /* The lock counts contains the number of extra data items placed or\r
1106         removed from the queue while the queue was locked.  When a queue is\r
1107         locked items can be added or removed, but the event lists cannot be\r
1108         updated. */\r
1109         taskENTER_CRITICAL();\r
1110         {\r
1111                 /* See if data was added to the queue while it was locked. */\r
1112                 while( pxQueue->xTxLock > queueLOCKED_UNMODIFIED )\r
1113                 {\r
1114                         /* Data was posted while the queue was locked.  Are any tasks\r
1115                         blocked waiting for data to become available? */\r
1116                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
1117                         {\r
1118                                 /* Tasks that are removed from the event list will get added to\r
1119                                 the pending ready list as the scheduler is still suspended. */\r
1120                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
1121                                 {\r
1122                                         /* The task waiting has a higher priority so record that a\r
1123                                         context switch is required. */\r
1124                                         vTaskMissedYield();\r
1125                                 }\r
1126 \r
1127                                 --( pxQueue->xTxLock );\r
1128                         }\r
1129                         else\r
1130                         {\r
1131                                 break;\r
1132                         }\r
1133                 }\r
1134 \r
1135                 pxQueue->xTxLock = queueUNLOCKED;\r
1136         }\r
1137         taskEXIT_CRITICAL();\r
1138 \r
1139         /* Do the same for the Rx lock. */\r
1140         taskENTER_CRITICAL();\r
1141         {\r
1142                 while( pxQueue->xRxLock > queueLOCKED_UNMODIFIED )\r
1143                 {\r
1144                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )\r
1145                         {\r
1146                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
1147                                 {\r
1148                                         vTaskMissedYield();\r
1149                                 }\r
1150 \r
1151                                 --( pxQueue->xRxLock );\r
1152                         }\r
1153                         else\r
1154                         {\r
1155                                 break;\r
1156                         }\r
1157                 }\r
1158 \r
1159                 pxQueue->xRxLock = queueUNLOCKED;\r
1160         }\r
1161         taskEXIT_CRITICAL();\r
1162 }\r
1163 /*-----------------------------------------------------------*/\r
1164 \r
1165 static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue )\r
1166 {\r
1167 signed portBASE_TYPE xReturn;\r
1168 \r
1169         taskENTER_CRITICAL();\r
1170                 xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );\r
1171         taskEXIT_CRITICAL();\r
1172 \r
1173         return xReturn;\r
1174 }\r
1175 /*-----------------------------------------------------------*/\r
1176 \r
1177 signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue )\r
1178 {\r
1179 signed portBASE_TYPE xReturn;\r
1180 \r
1181         xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );\r
1182 \r
1183         return xReturn;\r
1184 }\r
1185 /*-----------------------------------------------------------*/\r
1186 \r
1187 static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue )\r
1188 {\r
1189 signed portBASE_TYPE xReturn;\r
1190 \r
1191         taskENTER_CRITICAL();\r
1192                 xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );\r
1193         taskEXIT_CRITICAL();\r
1194 \r
1195         return xReturn;\r
1196 }\r
1197 /*-----------------------------------------------------------*/\r
1198 \r
1199 signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue )\r
1200 {\r
1201 signed portBASE_TYPE xReturn;\r
1202 \r
1203         xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );\r
1204 \r
1205         return xReturn;\r
1206 }\r
1207 /*-----------------------------------------------------------*/\r
1208 \r
1209 #if configUSE_CO_ROUTINES == 1\r
1210 signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )\r
1211 {\r
1212 signed portBASE_TYPE xReturn;\r
1213 \r
1214         /* If the queue is already full we may have to block.  A critical section\r
1215         is required to prevent an interrupt removing something from the queue\r
1216         between the check to see if the queue is full and blocking on the queue. */\r
1217         portDISABLE_INTERRUPTS();\r
1218         {\r
1219                 if( prvIsQueueFull( pxQueue ) )\r
1220                 {\r
1221                         /* The queue is full - do we want to block or just leave without\r
1222                         posting? */\r
1223                         if( xTicksToWait > ( portTickType ) 0 )\r
1224                         {\r
1225                                 /* As this is called from a coroutine we cannot block directly, but\r
1226                                 return indicating that we need to block. */\r
1227                                 vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToSend ) );\r
1228                                 portENABLE_INTERRUPTS();\r
1229                                 return errQUEUE_BLOCKED;\r
1230                         }\r
1231                         else\r
1232                         {\r
1233                                 portENABLE_INTERRUPTS();\r
1234                                 return errQUEUE_FULL;\r
1235                         }\r
1236                 }\r
1237         }\r
1238         portENABLE_INTERRUPTS();\r
1239 \r
1240         portNOP();\r
1241 \r
1242         portDISABLE_INTERRUPTS();\r
1243         {\r
1244                 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
1245                 {\r
1246                         /* There is room in the queue, copy the data into the queue. */\r
1247                         prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );\r
1248                         xReturn = pdPASS;\r
1249 \r
1250                         /* Were any co-routines waiting for data to become available? */\r
1251                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
1252                         {\r
1253                                 /* In this instance the co-routine could be placed directly\r
1254                                 into the ready list as we are within a critical section.\r
1255                                 Instead the same pending ready list mechanism is used as if\r
1256                                 the event were caused from within an interrupt. */\r
1257                                 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
1258                                 {\r
1259                                         /* The co-routine waiting has a higher priority so record\r
1260                                         that a yield might be appropriate. */\r
1261                                         xReturn = errQUEUE_YIELD;\r
1262                                 }\r
1263                         }\r
1264                 }\r
1265                 else\r
1266                 {\r
1267                         xReturn = errQUEUE_FULL;\r
1268                 }\r
1269         }\r
1270         portENABLE_INTERRUPTS();\r
1271 \r
1272         return xReturn;\r
1273 }\r
1274 #endif\r
1275 /*-----------------------------------------------------------*/\r
1276 \r
1277 #if configUSE_CO_ROUTINES == 1\r
1278 signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait )\r
1279 {\r
1280 signed portBASE_TYPE xReturn;\r
1281 \r
1282         /* If the queue is already empty we may have to block.  A critical section\r
1283         is required to prevent an interrupt adding something to the queue\r
1284         between the check to see if the queue is empty and blocking on the queue. */\r
1285         portDISABLE_INTERRUPTS();\r
1286         {\r
1287                 if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 )\r
1288                 {\r
1289                         /* There are no messages in the queue, do we want to block or just\r
1290                         leave with nothing? */\r
1291                         if( xTicksToWait > ( portTickType ) 0 )\r
1292                         {\r
1293                                 /* As this is a co-routine we cannot block directly, but return\r
1294                                 indicating that we need to block. */\r
1295                                 vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToReceive ) );\r
1296                                 portENABLE_INTERRUPTS();\r
1297                                 return errQUEUE_BLOCKED;\r
1298                         }\r
1299                         else\r
1300                         {\r
1301                                 portENABLE_INTERRUPTS();\r
1302                                 return errQUEUE_FULL;\r
1303                         }\r
1304                 }\r
1305         }\r
1306         portENABLE_INTERRUPTS();\r
1307 \r
1308         portNOP();\r
1309 \r
1310         portDISABLE_INTERRUPTS();\r
1311         {\r
1312                 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
1313                 {\r
1314                         /* Data is available from the queue. */\r
1315                         pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
1316                         if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
1317                         {\r
1318                                 pxQueue->pcReadFrom = pxQueue->pcHead;\r
1319                         }\r
1320                         --( pxQueue->uxMessagesWaiting );\r
1321                         memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
1322 \r
1323                         xReturn = pdPASS;\r
1324 \r
1325                         /* Were any co-routines waiting for space to become available? */\r
1326                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )\r
1327                         {\r
1328                                 /* In this instance the co-routine could be placed directly\r
1329                                 into the ready list as we are within a critical section.\r
1330                                 Instead the same pending ready list mechanism is used as if\r
1331                                 the event were caused from within an interrupt. */\r
1332                                 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
1333                                 {\r
1334                                         xReturn = errQUEUE_YIELD;\r
1335                                 }\r
1336                         }\r
1337                 }\r
1338                 else\r
1339                 {\r
1340                         xReturn = pdFAIL;\r
1341                 }\r
1342         }\r
1343         portENABLE_INTERRUPTS();\r
1344 \r
1345         return xReturn;\r
1346 }\r
1347 #endif\r
1348 /*-----------------------------------------------------------*/\r
1349 \r
1350 \r
1351 \r
1352 #if configUSE_CO_ROUTINES == 1\r
1353 signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken )\r
1354 {\r
1355         /* Cannot block within an ISR so if there is no space on the queue then\r
1356         exit without doing anything. */\r
1357         if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
1358         {\r
1359                 prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );\r
1360 \r
1361                 /* We only want to wake one co-routine per ISR, so check that a\r
1362                 co-routine has not already been woken. */\r
1363                 if( !xCoRoutinePreviouslyWoken )\r
1364                 {\r
1365                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
1366                         {\r
1367                                 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
1368                                 {\r
1369                                         return pdTRUE;\r
1370                                 }\r
1371                         }\r
1372                 }\r
1373         }\r
1374 \r
1375         return xCoRoutinePreviouslyWoken;\r
1376 }\r
1377 #endif\r
1378 /*-----------------------------------------------------------*/\r
1379 \r
1380 #if configUSE_CO_ROUTINES == 1\r
1381 signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxCoRoutineWoken )\r
1382 {\r
1383 signed portBASE_TYPE xReturn;\r
1384 \r
1385         /* We cannot block from an ISR, so check there is data available. If\r
1386         not then just leave without doing anything. */\r
1387         if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
1388         {\r
1389                 /* Copy the data from the queue. */\r
1390                 pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
1391                 if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
1392                 {\r
1393                         pxQueue->pcReadFrom = pxQueue->pcHead;\r
1394                 }\r
1395                 --( pxQueue->uxMessagesWaiting );\r
1396                 memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
1397 \r
1398                 if( !( *pxCoRoutineWoken ) )\r
1399                 {\r
1400                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )\r
1401                         {\r
1402                                 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
1403                                 {\r
1404                                         *pxCoRoutineWoken = pdTRUE;\r
1405                                 }\r
1406                         }\r
1407                 }\r
1408 \r
1409                 xReturn = pdPASS;\r
1410         }\r
1411         else\r
1412         {\r
1413                 xReturn = pdFAIL;\r
1414         }\r
1415 \r
1416         return xReturn;\r
1417 }\r
1418 #endif\r
1419 /*-----------------------------------------------------------*/\r
1420 \r
1421 #if configQUEUE_REGISTRY_SIZE > 0\r
1422 \r
1423         void vQueueAddToRegistry( xQueueHandle xQueue, signed char *pcQueueName )\r
1424         {\r
1425         unsigned portBASE_TYPE ux;\r
1426 \r
1427                 /* See if there is an empty space in the registry.  A NULL name denotes\r
1428                 a free slot. */\r
1429                 for( ux = 0; ux < configQUEUE_REGISTRY_SIZE; ux++ )\r
1430                 {\r
1431                         if( xQueueRegistry[ ux ].pcQueueName == NULL )\r
1432                         {\r
1433                                 /* Store the information on this queue. */\r
1434                                 xQueueRegistry[ ux ].pcQueueName = pcQueueName;\r
1435                                 xQueueRegistry[ ux ].xHandle = xQueue;\r
1436                                 break;\r
1437                         }\r
1438                 }\r
1439         }\r
1440 \r
1441 #endif\r
1442         /*-----------------------------------------------------------*/\r
1443 \r
1444 #if configQUEUE_REGISTRY_SIZE > 0\r
1445 \r
1446         static void vQueueUnregisterQueue( xQueueHandle xQueue )\r
1447         {\r
1448         unsigned portBASE_TYPE ux;\r
1449 \r
1450                 /* See if the handle of the queue being unregistered in actually in the\r
1451                 registry. */\r
1452                 for( ux = 0; ux < configQUEUE_REGISTRY_SIZE; ux++ )\r
1453                 {\r
1454                         if( xQueueRegistry[ ux ].xHandle == xQueue )\r
1455                         {\r
1456                                 /* Set the name to NULL to show that this slot if free again. */\r
1457                                 xQueueRegistry[ ux ].pcQueueName = NULL;\r
1458                                 break;\r
1459                         }\r
1460                 }\r
1461 \r
1462         }\r
1463 \r
1464 #endif\r
1465 \r