]> git.sur5r.net Git - freertos/blob - Source/queue.c
Continue work on the timers module.
[freertos] / Source / queue.c
1 /*\r
2     FreeRTOS V6.1.1 - Copyright (C) 2011 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 books - available as PDF or paperback  *\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         taskENTER_CRITICAL();                                                                   \\r
227         {                                                                                                               \\r
228                 if( ( pxQueue )->xRxLock == queueUNLOCKED )                     \\r
229                 {                                                                                                       \\r
230                         ( pxQueue )->xRxLock = queueLOCKED_UNMODIFIED;  \\r
231                 }                                                                                                       \\r
232                 if( ( pxQueue )->xTxLock == queueUNLOCKED )                     \\r
233                 {                                                                                                       \\r
234                         ( pxQueue )->xTxLock = queueLOCKED_UNMODIFIED;  \\r
235                 }                                                                                                       \\r
236         }                                                                                                               \\r
237         taskEXIT_CRITICAL()\r
238 /*-----------------------------------------------------------*/\r
239 \r
240 \r
241 /*-----------------------------------------------------------\r
242  * PUBLIC QUEUE MANAGEMENT API documented in queue.h\r
243  *----------------------------------------------------------*/\r
244 \r
245 xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize )\r
246 {\r
247 xQUEUE *pxNewQueue;\r
248 size_t xQueueSizeInBytes;\r
249 xQueueHandle xReturn = NULL;\r
250 \r
251         /* Allocate the new queue structure. */\r
252         if( uxQueueLength > ( unsigned portBASE_TYPE ) 0 )\r
253         {\r
254                 pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );\r
255                 if( pxNewQueue != NULL )\r
256                 {\r
257                         /* Create the list of pointers to queue items.  The queue is one byte\r
258                         longer than asked for to make wrap checking easier/faster. */\r
259                         xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ) + ( size_t ) 1;\r
260 \r
261                         pxNewQueue->pcHead = ( signed char * ) pvPortMalloc( xQueueSizeInBytes );\r
262                         if( pxNewQueue->pcHead != NULL )\r
263                         {\r
264                                 /* Initialise the queue members as described above where the\r
265                                 queue type is defined. */\r
266                                 pxNewQueue->pcTail = pxNewQueue->pcHead + ( uxQueueLength * uxItemSize );\r
267                                 pxNewQueue->uxMessagesWaiting = ( unsigned portBASE_TYPE ) 0U;\r
268                                 pxNewQueue->pcWriteTo = pxNewQueue->pcHead;\r
269                                 pxNewQueue->pcReadFrom = pxNewQueue->pcHead + ( ( uxQueueLength - ( unsigned portBASE_TYPE ) 1U ) * uxItemSize );\r
270                                 pxNewQueue->uxLength = uxQueueLength;\r
271                                 pxNewQueue->uxItemSize = uxItemSize;\r
272                                 pxNewQueue->xRxLock = queueUNLOCKED;\r
273                                 pxNewQueue->xTxLock = queueUNLOCKED;\r
274 \r
275                                 /* Likewise ensure the event queues start with the correct state. */\r
276                                 vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );\r
277                                 vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );\r
278 \r
279                                 traceQUEUE_CREATE( pxNewQueue );\r
280                                 xReturn = pxNewQueue;\r
281                         }\r
282                         else\r
283                         {\r
284                                 traceQUEUE_CREATE_FAILED();\r
285                                 vPortFree( pxNewQueue );\r
286                         }\r
287                 }\r
288         }\r
289 \r
290         return xReturn;\r
291 }\r
292 /*-----------------------------------------------------------*/\r
293 \r
294 #if ( configUSE_MUTEXES == 1 )\r
295 \r
296         xQueueHandle xQueueCreateMutex( void )\r
297         {\r
298         xQUEUE *pxNewQueue;\r
299 \r
300                 /* Allocate the new queue structure. */\r
301                 pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );\r
302                 if( pxNewQueue != NULL )\r
303                 {\r
304                         /* Information required for priority inheritance. */\r
305                         pxNewQueue->pxMutexHolder = NULL;\r
306                         pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX;\r
307 \r
308                         /* Queues used as a mutex no data is actually copied into or out\r
309                         of the queue. */\r
310                         pxNewQueue->pcWriteTo = NULL;\r
311                         pxNewQueue->pcReadFrom = NULL;\r
312 \r
313                         /* Each mutex has a length of 1 (like a binary semaphore) and\r
314                         an item size of 0 as nothing is actually copied into or out\r
315                         of the mutex. */\r
316                         pxNewQueue->uxMessagesWaiting = ( unsigned portBASE_TYPE ) 0U;\r
317                         pxNewQueue->uxLength = ( unsigned portBASE_TYPE ) 1U;\r
318                         pxNewQueue->uxItemSize = ( unsigned portBASE_TYPE ) 0U;\r
319                         pxNewQueue->xRxLock = queueUNLOCKED;\r
320                         pxNewQueue->xTxLock = queueUNLOCKED;\r
321 \r
322                         /* Ensure the event queues start with the correct state. */\r
323                         vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );\r
324                         vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );\r
325 \r
326                         /* Start with the semaphore in the expected state. */\r
327                         xQueueGenericSend( pxNewQueue, NULL, ( portTickType ) 0U, queueSEND_TO_BACK );\r
328 \r
329                         traceCREATE_MUTEX( pxNewQueue );\r
330                 }\r
331                 else\r
332                 {\r
333                         traceCREATE_MUTEX_FAILED();\r
334                 }\r
335 \r
336                 return pxNewQueue;\r
337         }\r
338 \r
339 #endif /* configUSE_MUTEXES */\r
340 /*-----------------------------------------------------------*/\r
341 \r
342 #if configUSE_RECURSIVE_MUTEXES == 1\r
343 \r
344         portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle pxMutex )\r
345         {\r
346         portBASE_TYPE xReturn;\r
347 \r
348                 /* If this is the task that holds the mutex then pxMutexHolder will not\r
349                 change outside of this task.  If this task does not hold the mutex then\r
350                 pxMutexHolder can never coincidentally equal the tasks handle, and as\r
351                 this is the only condition we are interested in it does not matter if\r
352                 pxMutexHolder is accessed simultaneously by another task.  Therefore no\r
353                 mutual exclusion is required to test the pxMutexHolder variable. */\r
354                 if( pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle() )\r
355                 {\r
356                         traceGIVE_MUTEX_RECURSIVE( pxMutex );\r
357 \r
358                         /* uxRecursiveCallCount cannot be zero if pxMutexHolder is equal to\r
359                         the task handle, therefore no underflow check is required.  Also,\r
360                         uxRecursiveCallCount is only modified by the mutex holder, and as\r
361                         there can only be one, no mutual exclusion is required to modify the\r
362                         uxRecursiveCallCount member. */\r
363                         ( pxMutex->uxRecursiveCallCount )--;\r
364 \r
365                         /* Have we unwound the call count? */\r
366                         if( pxMutex->uxRecursiveCallCount == 0 )\r
367                         {\r
368                                 /* Return the mutex.  This will automatically unblock any other\r
369                                 task that might be waiting to access the mutex. */\r
370                                 xQueueGenericSend( pxMutex, NULL, queueMUTEX_GIVE_BLOCK_TIME, queueSEND_TO_BACK );\r
371                         }\r
372 \r
373                         xReturn = pdPASS;\r
374                 }\r
375                 else\r
376                 {\r
377                         /* We cannot give the mutex because we are not the holder. */\r
378                         xReturn = pdFAIL;\r
379 \r
380                         traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex );\r
381                 }\r
382 \r
383                 return xReturn;\r
384         }\r
385 \r
386 #endif /* configUSE_RECURSIVE_MUTEXES */\r
387 /*-----------------------------------------------------------*/\r
388 \r
389 #if configUSE_RECURSIVE_MUTEXES == 1\r
390 \r
391         portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle pxMutex, portTickType xBlockTime )\r
392         {\r
393         portBASE_TYPE xReturn;\r
394 \r
395                 /* Comments regarding mutual exclusion as per those within\r
396                 xQueueGiveMutexRecursive(). */\r
397 \r
398                 traceTAKE_MUTEX_RECURSIVE( pxMutex );\r
399 \r
400                 if( pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle() )\r
401                 {\r
402                         ( pxMutex->uxRecursiveCallCount )++;\r
403                         xReturn = pdPASS;\r
404                 }\r
405                 else\r
406                 {\r
407                         xReturn = xQueueGenericReceive( pxMutex, NULL, xBlockTime, pdFALSE );\r
408 \r
409                         /* pdPASS will only be returned if we successfully obtained the mutex,\r
410                         we may have blocked to reach here. */\r
411                         if( xReturn == pdPASS )\r
412                         {\r
413                                 ( pxMutex->uxRecursiveCallCount )++;\r
414                         }\r
415                         else\r
416                         {\r
417                                 traceTAKE_MUTEX_RECURSIVE_FAILED( pxMutex );\r
418                         }\r
419                 }\r
420 \r
421                 return xReturn;\r
422         }\r
423 \r
424 #endif /* configUSE_RECURSIVE_MUTEXES */\r
425 /*-----------------------------------------------------------*/\r
426 \r
427 #if configUSE_COUNTING_SEMAPHORES == 1\r
428 \r
429         xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount )\r
430         {\r
431         xQueueHandle pxHandle;\r
432 \r
433                 pxHandle = xQueueCreate( ( unsigned portBASE_TYPE ) uxCountValue, queueSEMAPHORE_QUEUE_ITEM_LENGTH );\r
434 \r
435                 if( pxHandle != NULL )\r
436                 {\r
437                         pxHandle->uxMessagesWaiting = uxInitialCount;\r
438 \r
439                         traceCREATE_COUNTING_SEMAPHORE();\r
440                 }\r
441                 else\r
442                 {\r
443                         traceCREATE_COUNTING_SEMAPHORE_FAILED();\r
444                 }\r
445 \r
446                 return pxHandle;\r
447         }\r
448 \r
449 #endif /* configUSE_COUNTING_SEMAPHORES */\r
450 /*-----------------------------------------------------------*/\r
451 \r
452 signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )\r
453 {\r
454 signed portBASE_TYPE xEntryTimeSet = pdFALSE;\r
455 xTimeOutType xTimeOut;\r
456 \r
457         /* This function relaxes the coding standard somewhat to allow return\r
458         statements within the function itself.  This is done in the interest\r
459         of execution time efficiency. */\r
460         for( ;; )\r
461         {\r
462                 taskENTER_CRITICAL();\r
463                 {\r
464                         /* Is there room on the queue now?  To be running we must be\r
465                         the highest priority task wanting to access the queue. */\r
466                         if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
467                         {\r
468                                 traceQUEUE_SEND( pxQueue );\r
469                                 prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );\r
470 \r
471                                 /* If there was a task waiting for data to arrive on the\r
472                                 queue then unblock it now. */\r
473                                 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
474                                 {\r
475                                         if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )\r
476                                         {\r
477                                                 /* The unblocked task has a priority higher than\r
478                                                 our own so yield immediately.  Yes it is ok to do\r
479                                                 this from within the critical section - the kernel\r
480                                                 takes care of that. */\r
481                                                 portYIELD_WITHIN_API();\r
482                                         }\r
483                                 }\r
484 \r
485                                 taskEXIT_CRITICAL();\r
486 \r
487                                 /* Return to the original privilege level before exiting the\r
488                                 function. */\r
489                                 return pdPASS;\r
490                         }\r
491                         else\r
492                         {\r
493                                 if( xTicksToWait == ( portTickType ) 0 )\r
494                                 {\r
495                                         /* The queue was full and no block time is specified (or\r
496                                         the block time has expired) so leave now. */\r
497                                         taskEXIT_CRITICAL();\r
498 \r
499                                         /* Return to the original privilege level before exiting\r
500                                         the function. */\r
501                                         traceQUEUE_SEND_FAILED( pxQueue );\r
502                                         return errQUEUE_FULL;\r
503                                 }\r
504                                 else if( xEntryTimeSet == pdFALSE )\r
505                                 {\r
506                                         /* The queue was full and a block time was specified so\r
507                                         configure the timeout structure. */\r
508                                         vTaskSetTimeOutState( &xTimeOut );\r
509                                         xEntryTimeSet = pdTRUE;\r
510                                 }\r
511                         }\r
512                 }\r
513                 taskEXIT_CRITICAL();\r
514 \r
515                 /* Interrupts and other tasks can send to and receive from the queue\r
516                 now the critical section has been exited. */\r
517 \r
518                 vTaskSuspendAll();\r
519                 prvLockQueue( pxQueue );\r
520 \r
521                 /* Update the timeout state to see if it has expired yet. */\r
522                 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
523                 {\r
524                         if( prvIsQueueFull( pxQueue ) )\r
525                         {\r
526                                 traceBLOCKING_ON_QUEUE_SEND( pxQueue );\r
527                                 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );\r
528 \r
529                                 /* Unlocking the queue means queue events can effect the\r
530                                 event list.  It is possible     that interrupts occurring now\r
531                                 remove this task from the event list again - but as the\r
532                                 scheduler is suspended the task will go onto the pending\r
533                                 ready last instead of the actual ready list. */\r
534                                 prvUnlockQueue( pxQueue );\r
535 \r
536                                 /* Resuming the scheduler will move tasks from the pending\r
537                                 ready list into the ready list - so it is feasible that this\r
538                                 task is already in a ready list before it yields - in which\r
539                                 case the yield will not cause a context switch unless there\r
540                                 is also a higher priority task in the pending ready list. */\r
541                                 if( !xTaskResumeAll() )\r
542                                 {\r
543                                         portYIELD_WITHIN_API();\r
544                                 }\r
545                         }\r
546                         else\r
547                         {\r
548                                 /* Try again. */\r
549                                 prvUnlockQueue( pxQueue );\r
550                                 ( void ) xTaskResumeAll();\r
551                         }\r
552                 }\r
553                 else\r
554                 {\r
555                         /* The timeout has expired. */\r
556                         prvUnlockQueue( pxQueue );\r
557                         ( void ) xTaskResumeAll();\r
558 \r
559                         /* Return to the original privilege level before exiting the\r
560                         function. */\r
561                         traceQUEUE_SEND_FAILED( pxQueue );\r
562                         return errQUEUE_FULL;\r
563                 }\r
564         }\r
565 }\r
566 /*-----------------------------------------------------------*/\r
567 \r
568 #if configUSE_ALTERNATIVE_API == 1\r
569 \r
570         signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )\r
571         {\r
572         signed portBASE_TYPE xEntryTimeSet = pdFALSE;\r
573         xTimeOutType xTimeOut;\r
574 \r
575                 for( ;; )\r
576                 {\r
577                         taskENTER_CRITICAL();\r
578                         {\r
579                                 /* Is there room on the queue now?  To be running we must be\r
580                                 the highest priority task wanting to access the queue. */\r
581                                 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
582                                 {\r
583                                         traceQUEUE_SEND( pxQueue );\r
584                                         prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );\r
585 \r
586                                         /* If there was a task waiting for data to arrive on the\r
587                                         queue then unblock it now. */\r
588                                         if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
589                                         {\r
590                                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )\r
591                                                 {\r
592                                                         /* The unblocked task has a priority higher than\r
593                                                         our own so yield immediately. */\r
594                                                         portYIELD_WITHIN_API();\r
595                                                 }\r
596                                         }\r
597 \r
598                                         taskEXIT_CRITICAL();\r
599                                         return pdPASS;\r
600                                 }\r
601                                 else\r
602                                 {\r
603                                         if( xTicksToWait == ( portTickType ) 0 )\r
604                                         {\r
605                                                 taskEXIT_CRITICAL();\r
606                                                 return errQUEUE_FULL;\r
607                                         }\r
608                                         else if( xEntryTimeSet == pdFALSE )\r
609                                         {\r
610                                                 vTaskSetTimeOutState( &xTimeOut );\r
611                                                 xEntryTimeSet = pdTRUE;\r
612                                         }\r
613                                 }\r
614                         }\r
615                         taskEXIT_CRITICAL();\r
616 \r
617                         taskENTER_CRITICAL();\r
618                         {\r
619                                 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
620                                 {\r
621                                         if( prvIsQueueFull( pxQueue ) )\r
622                                         {\r
623                                                 traceBLOCKING_ON_QUEUE_SEND( pxQueue );\r
624                                                 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );\r
625                                                 portYIELD_WITHIN_API();\r
626                                         }\r
627                                 }\r
628                                 else\r
629                                 {\r
630                                         taskEXIT_CRITICAL();\r
631                                         traceQUEUE_SEND_FAILED( pxQueue );\r
632                                         return errQUEUE_FULL;\r
633                                 }\r
634                         }\r
635                         taskEXIT_CRITICAL();\r
636                 }\r
637         }\r
638 \r
639 #endif /* configUSE_ALTERNATIVE_API */\r
640 /*-----------------------------------------------------------*/\r
641 \r
642 #if configUSE_ALTERNATIVE_API == 1\r
643 \r
644         signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )\r
645         {\r
646         signed portBASE_TYPE xEntryTimeSet = pdFALSE;\r
647         xTimeOutType xTimeOut;\r
648         signed char *pcOriginalReadPosition;\r
649 \r
650                 for( ;; )\r
651                 {\r
652                         taskENTER_CRITICAL();\r
653                         {\r
654                                 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
655                                 {\r
656                                         /* Remember our read position in case we are just peeking. */\r
657                                         pcOriginalReadPosition = pxQueue->pcReadFrom;\r
658 \r
659                                         prvCopyDataFromQueue( pxQueue, pvBuffer );\r
660 \r
661                                         if( xJustPeeking == pdFALSE )\r
662                                         {\r
663                                                 traceQUEUE_RECEIVE( pxQueue );\r
664 \r
665                                                 /* We are actually removing data. */\r
666                                                 --( pxQueue->uxMessagesWaiting );\r
667 \r
668                                                 #if ( configUSE_MUTEXES == 1 )\r
669                                                 {\r
670                                                         if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
671                                                         {\r
672                                                                 /* Record the information required to implement\r
673                                                                 priority inheritance should it become necessary. */\r
674                                                                 pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();\r
675                                                         }\r
676                                                 }\r
677                                                 #endif\r
678 \r
679                                                 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )\r
680                                                 {\r
681                                                         if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )\r
682                                                         {\r
683                                                                 portYIELD_WITHIN_API();\r
684                                                         }\r
685                                                 }\r
686                                         }\r
687                                         else\r
688                                         {\r
689                                                 traceQUEUE_PEEK( pxQueue );\r
690 \r
691                                                 /* We are not removing the data, so reset our read\r
692                                                 pointer. */\r
693                                                 pxQueue->pcReadFrom = pcOriginalReadPosition;\r
694 \r
695                                                 /* The data is being left in the queue, so see if there are\r
696                                                 any other tasks waiting for the data. */\r
697                                                 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
698                                                 {\r
699                                                         /* Tasks that are removed from the event list will get added to\r
700                                                         the pending ready list as the scheduler is still suspended. */\r
701                                                         if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
702                                                         {\r
703                                                                 /* The task waiting has a higher priority than this task. */\r
704                                                                 portYIELD_WITHIN_API();\r
705                                                         }\r
706                                                 }\r
707 \r
708                                         }\r
709 \r
710                                         taskEXIT_CRITICAL();\r
711                                         return pdPASS;\r
712                                 }\r
713                                 else\r
714                                 {\r
715                                         if( xTicksToWait == ( portTickType ) 0 )\r
716                                         {\r
717                                                 taskEXIT_CRITICAL();\r
718                                                 traceQUEUE_RECEIVE_FAILED( pxQueue );\r
719                                                 return errQUEUE_EMPTY;\r
720                                         }\r
721                                         else if( xEntryTimeSet == pdFALSE )\r
722                                         {\r
723                                                 vTaskSetTimeOutState( &xTimeOut );\r
724                                                 xEntryTimeSet = pdTRUE;\r
725                                         }\r
726                                 }\r
727                         }\r
728                         taskEXIT_CRITICAL();\r
729 \r
730                         taskENTER_CRITICAL();\r
731                         {\r
732                                 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
733                                 {\r
734                                         if( prvIsQueueEmpty( pxQueue ) )\r
735                                         {\r
736                                                 traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );\r
737 \r
738                                                 #if ( configUSE_MUTEXES == 1 )\r
739                                                 {\r
740                                                         if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
741                                                         {\r
742                                                                 portENTER_CRITICAL();\r
743                                                                         vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );\r
744                                                                 portEXIT_CRITICAL();\r
745                                                         }\r
746                                                 }\r
747                                                 #endif\r
748 \r
749                                                 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );\r
750                                                 portYIELD_WITHIN_API();\r
751                                         }\r
752                                 }\r
753                                 else\r
754                                 {\r
755                                         taskEXIT_CRITICAL();\r
756                                         traceQUEUE_RECEIVE_FAILED( pxQueue );\r
757                                         return errQUEUE_EMPTY;\r
758                                 }\r
759                         }\r
760                         taskEXIT_CRITICAL();\r
761                 }\r
762         }\r
763 \r
764 \r
765 #endif /* configUSE_ALTERNATIVE_API */\r
766 /*-----------------------------------------------------------*/\r
767 \r
768 signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portBASE_TYPE xCopyPosition )\r
769 {\r
770 signed portBASE_TYPE xReturn;\r
771 unsigned portBASE_TYPE uxSavedInterruptStatus;\r
772 \r
773         /* Similar to xQueueGenericSend, except we don't block if there is no room\r
774         in the queue.  Also we don't directly wake a task that was blocked on a\r
775         queue read, instead we return a flag to say whether a context switch is\r
776         required or not (i.e. has a task with a higher priority than us been woken\r
777         by this post). */\r
778         uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();\r
779         {\r
780                 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
781                 {\r
782                         traceQUEUE_SEND_FROM_ISR( pxQueue );\r
783 \r
784                         prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );\r
785 \r
786                         /* If the queue is locked we do not alter the event list.  This will\r
787                         be done when the queue is unlocked later. */\r
788                         if( pxQueue->xTxLock == queueUNLOCKED )\r
789                         {\r
790                                 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
791                                 {\r
792                                         if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
793                                         {\r
794                                                 /* The task waiting has a higher priority so record that a\r
795                                                 context switch is required. */\r
796                                                 *pxHigherPriorityTaskWoken = pdTRUE;\r
797                                         }\r
798                                 }\r
799                         }\r
800                         else\r
801                         {\r
802                                 /* Increment the lock count so the task that unlocks the queue\r
803                                 knows that data was posted while it was locked. */\r
804                                 ++( pxQueue->xTxLock );\r
805                         }\r
806 \r
807                         xReturn = pdPASS;\r
808                 }\r
809                 else\r
810                 {\r
811                         traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue );\r
812                         xReturn = errQUEUE_FULL;\r
813                 }\r
814         }\r
815         portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );\r
816 \r
817         return xReturn;\r
818 }\r
819 /*-----------------------------------------------------------*/\r
820 \r
821 signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )\r
822 {\r
823 signed portBASE_TYPE xEntryTimeSet = pdFALSE;\r
824 xTimeOutType xTimeOut;\r
825 signed char *pcOriginalReadPosition;\r
826 \r
827         /* This function relaxes the coding standard somewhat to allow return\r
828         statements within the function itself.  This is done in the interest\r
829         of execution time efficiency. */\r
830 \r
831         for( ;; )\r
832         {\r
833                 taskENTER_CRITICAL();\r
834                 {\r
835                         /* Is there data in the queue now?  To be running we must be\r
836                         the highest priority task wanting to access the queue. */\r
837                         if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
838                         {\r
839                                 /* Remember our read position in case we are just peeking. */\r
840                                 pcOriginalReadPosition = pxQueue->pcReadFrom;\r
841 \r
842                                 prvCopyDataFromQueue( pxQueue, pvBuffer );\r
843 \r
844                                 if( xJustPeeking == pdFALSE )\r
845                                 {\r
846                                         traceQUEUE_RECEIVE( pxQueue );\r
847 \r
848                                         /* We are actually removing data. */\r
849                                         --( pxQueue->uxMessagesWaiting );\r
850 \r
851                                         #if ( configUSE_MUTEXES == 1 )\r
852                                         {\r
853                                                 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
854                                                 {\r
855                                                         /* Record the information required to implement\r
856                                                         priority inheritance should it become necessary. */\r
857                                                         pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();\r
858                                                 }\r
859                                         }\r
860                                         #endif\r
861 \r
862                                         if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )\r
863                                         {\r
864                                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )\r
865                                                 {\r
866                                                         portYIELD_WITHIN_API();\r
867                                                 }\r
868                                         }\r
869                                 }\r
870                                 else\r
871                                 {\r
872                                         traceQUEUE_PEEK( pxQueue );\r
873 \r
874                                         /* We are not removing the data, so reset our read\r
875                                         pointer. */\r
876                                         pxQueue->pcReadFrom = pcOriginalReadPosition;\r
877 \r
878                                         /* The data is being left in the queue, so see if there are\r
879                                         any other tasks waiting for the data. */\r
880                                         if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
881                                         {\r
882                                                 /* Tasks that are removed from the event list will get added to\r
883                                                 the pending ready list as the scheduler is still suspended. */\r
884                                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
885                                                 {\r
886                                                         /* The task waiting has a higher priority than this task. */\r
887                                                         portYIELD_WITHIN_API();\r
888                                                 }\r
889                                         }\r
890 \r
891                                 }\r
892 \r
893                                 taskEXIT_CRITICAL();\r
894                                 return pdPASS;\r
895                         }\r
896                         else\r
897                         {\r
898                                 if( xTicksToWait == ( portTickType ) 0 )\r
899                                 {\r
900                                         /* The queue was empty and no block time is specified (or\r
901                                         the block time has expired) so leave now. */\r
902                                         taskEXIT_CRITICAL();\r
903                                         traceQUEUE_RECEIVE_FAILED( pxQueue );\r
904                                         return errQUEUE_EMPTY;\r
905                                 }\r
906                                 else if( xEntryTimeSet == pdFALSE )\r
907                                 {\r
908                                         /* The queue was empty and a block time was specified so\r
909                                         configure the timeout structure. */\r
910                                         vTaskSetTimeOutState( &xTimeOut );\r
911                                         xEntryTimeSet = pdTRUE;\r
912                                 }\r
913                         }\r
914                 }\r
915                 taskEXIT_CRITICAL();\r
916 \r
917                 /* Interrupts and other tasks can send to and receive from the queue\r
918                 now the critical section has been exited. */\r
919 \r
920                 vTaskSuspendAll();\r
921                 prvLockQueue( pxQueue );\r
922 \r
923                 /* Update the timeout state to see if it has expired yet. */\r
924                 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
925                 {\r
926                         if( prvIsQueueEmpty( pxQueue ) )\r
927                         {\r
928                                 traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );\r
929 \r
930                                 #if ( configUSE_MUTEXES == 1 )\r
931                                 {\r
932                                         if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
933                                         {\r
934                                                 portENTER_CRITICAL();\r
935                                                 {\r
936                                                         vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );\r
937                                                 }\r
938                                                 portEXIT_CRITICAL();\r
939                                         }\r
940                                 }\r
941                                 #endif\r
942 \r
943                                 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );\r
944                                 prvUnlockQueue( pxQueue );\r
945                                 if( !xTaskResumeAll() )\r
946                                 {\r
947                                         portYIELD_WITHIN_API();\r
948                                 }\r
949                         }\r
950                         else\r
951                         {\r
952                                 /* Try again. */\r
953                                 prvUnlockQueue( pxQueue );\r
954                                 ( void ) xTaskResumeAll();\r
955                         }\r
956                 }\r
957                 else\r
958                 {\r
959                         prvUnlockQueue( pxQueue );\r
960                         ( void ) xTaskResumeAll();\r
961                         traceQUEUE_RECEIVE_FAILED( pxQueue );\r
962                         return errQUEUE_EMPTY;\r
963                 }\r
964         }\r
965 }\r
966 /*-----------------------------------------------------------*/\r
967 \r
968 signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken )\r
969 {\r
970 signed portBASE_TYPE xReturn;\r
971 unsigned portBASE_TYPE uxSavedInterruptStatus;\r
972 \r
973         uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();\r
974         {\r
975                 /* We cannot block from an ISR, so check there is data available. */\r
976                 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
977                 {\r
978                         traceQUEUE_RECEIVE_FROM_ISR( pxQueue );\r
979 \r
980                         prvCopyDataFromQueue( pxQueue, pvBuffer );\r
981                         --( pxQueue->uxMessagesWaiting );\r
982 \r
983                         /* If the queue is locked we will not modify the event list.  Instead\r
984                         we update the lock count so the task that unlocks the queue will know\r
985                         that an ISR has removed data while the queue was locked. */\r
986                         if( pxQueue->xRxLock == queueUNLOCKED )\r
987                         {\r
988                                 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )\r
989                                 {\r
990                                         if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
991                                         {\r
992                                                 /* The task waiting has a higher priority than us so\r
993                                                 force a context switch. */\r
994                                                 *pxTaskWoken = pdTRUE;\r
995                                         }\r
996                                 }\r
997                         }\r
998                         else\r
999                         {\r
1000                                 /* Increment the lock count so the task that unlocks the queue\r
1001                                 knows that data was removed while it was locked. */\r
1002                                 ++( pxQueue->xRxLock );\r
1003                         }\r
1004 \r
1005                         xReturn = pdPASS;\r
1006                 }\r
1007                 else\r
1008                 {\r
1009                         xReturn = pdFAIL;\r
1010                         traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue );\r
1011                 }\r
1012         }\r
1013         portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );\r
1014 \r
1015         return xReturn;\r
1016 }\r
1017 /*-----------------------------------------------------------*/\r
1018 \r
1019 unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle pxQueue )\r
1020 {\r
1021 unsigned portBASE_TYPE uxReturn;\r
1022 \r
1023         taskENTER_CRITICAL();\r
1024                 uxReturn = pxQueue->uxMessagesWaiting;\r
1025         taskEXIT_CRITICAL();\r
1026 \r
1027         return uxReturn;\r
1028 }\r
1029 /*-----------------------------------------------------------*/\r
1030 \r
1031 unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue )\r
1032 {\r
1033 unsigned portBASE_TYPE uxReturn;\r
1034 \r
1035         uxReturn = pxQueue->uxMessagesWaiting;\r
1036 \r
1037         return uxReturn;\r
1038 }\r
1039 /*-----------------------------------------------------------*/\r
1040 \r
1041 void vQueueDelete( xQueueHandle pxQueue )\r
1042 {\r
1043         traceQUEUE_DELETE( pxQueue );\r
1044         vQueueUnregisterQueue( pxQueue );\r
1045         vPortFree( pxQueue->pcHead );\r
1046         vPortFree( pxQueue );\r
1047 }\r
1048 /*-----------------------------------------------------------*/\r
1049 \r
1050 static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition )\r
1051 {\r
1052         if( pxQueue->uxItemSize == ( unsigned portBASE_TYPE ) 0 )\r
1053         {\r
1054                 #if ( configUSE_MUTEXES == 1 )\r
1055                 {\r
1056                         if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
1057                         {\r
1058                                 /* The mutex is no longer being held. */\r
1059                                 vTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder );\r
1060                                 pxQueue->pxMutexHolder = NULL;\r
1061                         }\r
1062                 }\r
1063                 #endif\r
1064         }\r
1065         else if( xPosition == queueSEND_TO_BACK )\r
1066         {\r
1067                 memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );\r
1068                 pxQueue->pcWriteTo += pxQueue->uxItemSize;\r
1069                 if( pxQueue->pcWriteTo >= pxQueue->pcTail )\r
1070                 {\r
1071                         pxQueue->pcWriteTo = pxQueue->pcHead;\r
1072                 }\r
1073         }\r
1074         else\r
1075         {\r
1076                 memcpy( ( void * ) pxQueue->pcReadFrom, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );\r
1077                 pxQueue->pcReadFrom -= pxQueue->uxItemSize;\r
1078                 if( pxQueue->pcReadFrom < pxQueue->pcHead )\r
1079                 {\r
1080                         pxQueue->pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize );\r
1081                 }\r
1082         }\r
1083 \r
1084         ++( pxQueue->uxMessagesWaiting );\r
1085 }\r
1086 /*-----------------------------------------------------------*/\r
1087 \r
1088 static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer )\r
1089 {\r
1090         if( pxQueue->uxQueueType != queueQUEUE_IS_MUTEX )\r
1091         {\r
1092                 pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
1093                 if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
1094                 {\r
1095                         pxQueue->pcReadFrom = pxQueue->pcHead;\r
1096                 }\r
1097                 memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
1098         }\r
1099 }\r
1100 /*-----------------------------------------------------------*/\r
1101 \r
1102 static void prvUnlockQueue( xQueueHandle pxQueue )\r
1103 {\r
1104         /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */\r
1105 \r
1106         /* The lock counts contains the number of extra data items placed or\r
1107         removed from the queue while the queue was locked.  When a queue is\r
1108         locked items can be added or removed, but the event lists cannot be\r
1109         updated. */\r
1110         taskENTER_CRITICAL();\r
1111         {\r
1112                 /* See if data was added to the queue while it was locked. */\r
1113                 while( pxQueue->xTxLock > queueLOCKED_UNMODIFIED )\r
1114                 {\r
1115                         /* Data was posted while the queue was locked.  Are any tasks\r
1116                         blocked waiting for data to become available? */\r
1117                         if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
1118                         {\r
1119                                 /* Tasks that are removed from the event list will get added to\r
1120                                 the pending ready list as the scheduler is still suspended. */\r
1121                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
1122                                 {\r
1123                                         /* The task waiting has a higher priority so record that a\r
1124                                         context switch is required. */\r
1125                                         vTaskMissedYield();\r
1126                                 }\r
1127 \r
1128                                 --( pxQueue->xTxLock );\r
1129                         }\r
1130                         else\r
1131                         {\r
1132                                 break;\r
1133                         }\r
1134                 }\r
1135 \r
1136                 pxQueue->xTxLock = queueUNLOCKED;\r
1137         }\r
1138         taskEXIT_CRITICAL();\r
1139 \r
1140         /* Do the same for the Rx lock. */\r
1141         taskENTER_CRITICAL();\r
1142         {\r
1143                 while( pxQueue->xRxLock > queueLOCKED_UNMODIFIED )\r
1144                 {\r
1145                         if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )\r
1146                         {\r
1147                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
1148                                 {\r
1149                                         vTaskMissedYield();\r
1150                                 }\r
1151 \r
1152                                 --( pxQueue->xRxLock );\r
1153                         }\r
1154                         else\r
1155                         {\r
1156                                 break;\r
1157                         }\r
1158                 }\r
1159 \r
1160                 pxQueue->xRxLock = queueUNLOCKED;\r
1161         }\r
1162         taskEXIT_CRITICAL();\r
1163 }\r
1164 /*-----------------------------------------------------------*/\r
1165 \r
1166 static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue )\r
1167 {\r
1168 signed portBASE_TYPE xReturn;\r
1169 \r
1170         taskENTER_CRITICAL();\r
1171                 xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );\r
1172         taskEXIT_CRITICAL();\r
1173 \r
1174         return xReturn;\r
1175 }\r
1176 /*-----------------------------------------------------------*/\r
1177 \r
1178 signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue )\r
1179 {\r
1180 signed portBASE_TYPE xReturn;\r
1181 \r
1182         xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );\r
1183 \r
1184         return xReturn;\r
1185 }\r
1186 /*-----------------------------------------------------------*/\r
1187 \r
1188 static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue )\r
1189 {\r
1190 signed portBASE_TYPE xReturn;\r
1191 \r
1192         taskENTER_CRITICAL();\r
1193                 xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );\r
1194         taskEXIT_CRITICAL();\r
1195 \r
1196         return xReturn;\r
1197 }\r
1198 /*-----------------------------------------------------------*/\r
1199 \r
1200 signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue )\r
1201 {\r
1202 signed portBASE_TYPE xReturn;\r
1203 \r
1204         xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );\r
1205 \r
1206         return xReturn;\r
1207 }\r
1208 /*-----------------------------------------------------------*/\r
1209 \r
1210 #if configUSE_CO_ROUTINES == 1\r
1211 signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )\r
1212 {\r
1213 signed portBASE_TYPE xReturn;\r
1214 \r
1215         /* If the queue is already full we may have to block.  A critical section\r
1216         is required to prevent an interrupt removing something from the queue\r
1217         between the check to see if the queue is full and blocking on the queue. */\r
1218         portDISABLE_INTERRUPTS();\r
1219         {\r
1220                 if( prvIsQueueFull( pxQueue ) )\r
1221                 {\r
1222                         /* The queue is full - do we want to block or just leave without\r
1223                         posting? */\r
1224                         if( xTicksToWait > ( portTickType ) 0 )\r
1225                         {\r
1226                                 /* As this is called from a coroutine we cannot block directly, but\r
1227                                 return indicating that we need to block. */\r
1228                                 vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToSend ) );\r
1229                                 portENABLE_INTERRUPTS();\r
1230                                 return errQUEUE_BLOCKED;\r
1231                         }\r
1232                         else\r
1233                         {\r
1234                                 portENABLE_INTERRUPTS();\r
1235                                 return errQUEUE_FULL;\r
1236                         }\r
1237                 }\r
1238         }\r
1239         portENABLE_INTERRUPTS();\r
1240 \r
1241         portNOP();\r
1242 \r
1243         portDISABLE_INTERRUPTS();\r
1244         {\r
1245                 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
1246                 {\r
1247                         /* There is room in the queue, copy the data into the queue. */\r
1248                         prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );\r
1249                         xReturn = pdPASS;\r
1250 \r
1251                         /* Were any co-routines waiting for data to become available? */\r
1252                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
1253                         {\r
1254                                 /* In this instance the co-routine could be placed directly\r
1255                                 into the ready list as we are within a critical section.\r
1256                                 Instead the same pending ready list mechanism is used as if\r
1257                                 the event were caused from within an interrupt. */\r
1258                                 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
1259                                 {\r
1260                                         /* The co-routine waiting has a higher priority so record\r
1261                                         that a yield might be appropriate. */\r
1262                                         xReturn = errQUEUE_YIELD;\r
1263                                 }\r
1264                         }\r
1265                 }\r
1266                 else\r
1267                 {\r
1268                         xReturn = errQUEUE_FULL;\r
1269                 }\r
1270         }\r
1271         portENABLE_INTERRUPTS();\r
1272 \r
1273         return xReturn;\r
1274 }\r
1275 #endif\r
1276 /*-----------------------------------------------------------*/\r
1277 \r
1278 #if configUSE_CO_ROUTINES == 1\r
1279 signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait )\r
1280 {\r
1281 signed portBASE_TYPE xReturn;\r
1282 \r
1283         /* If the queue is already empty we may have to block.  A critical section\r
1284         is required to prevent an interrupt adding something to the queue\r
1285         between the check to see if the queue is empty and blocking on the queue. */\r
1286         portDISABLE_INTERRUPTS();\r
1287         {\r
1288                 if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 )\r
1289                 {\r
1290                         /* There are no messages in the queue, do we want to block or just\r
1291                         leave with nothing? */\r
1292                         if( xTicksToWait > ( portTickType ) 0 )\r
1293                         {\r
1294                                 /* As this is a co-routine we cannot block directly, but return\r
1295                                 indicating that we need to block. */\r
1296                                 vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToReceive ) );\r
1297                                 portENABLE_INTERRUPTS();\r
1298                                 return errQUEUE_BLOCKED;\r
1299                         }\r
1300                         else\r
1301                         {\r
1302                                 portENABLE_INTERRUPTS();\r
1303                                 return errQUEUE_FULL;\r
1304                         }\r
1305                 }\r
1306         }\r
1307         portENABLE_INTERRUPTS();\r
1308 \r
1309         portNOP();\r
1310 \r
1311         portDISABLE_INTERRUPTS();\r
1312         {\r
1313                 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
1314                 {\r
1315                         /* Data is available from the queue. */\r
1316                         pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
1317                         if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
1318                         {\r
1319                                 pxQueue->pcReadFrom = pxQueue->pcHead;\r
1320                         }\r
1321                         --( pxQueue->uxMessagesWaiting );\r
1322                         memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
1323 \r
1324                         xReturn = pdPASS;\r
1325 \r
1326                         /* Were any co-routines waiting for space to become available? */\r
1327                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )\r
1328                         {\r
1329                                 /* In this instance the co-routine could be placed directly\r
1330                                 into the ready list as we are within a critical section.\r
1331                                 Instead the same pending ready list mechanism is used as if\r
1332                                 the event were caused from within an interrupt. */\r
1333                                 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
1334                                 {\r
1335                                         xReturn = errQUEUE_YIELD;\r
1336                                 }\r
1337                         }\r
1338                 }\r
1339                 else\r
1340                 {\r
1341                         xReturn = pdFAIL;\r
1342                 }\r
1343         }\r
1344         portENABLE_INTERRUPTS();\r
1345 \r
1346         return xReturn;\r
1347 }\r
1348 #endif\r
1349 /*-----------------------------------------------------------*/\r
1350 \r
1351 \r
1352 \r
1353 #if configUSE_CO_ROUTINES == 1\r
1354 signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken )\r
1355 {\r
1356         /* Cannot block within an ISR so if there is no space on the queue then\r
1357         exit without doing anything. */\r
1358         if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
1359         {\r
1360                 prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );\r
1361 \r
1362                 /* We only want to wake one co-routine per ISR, so check that a\r
1363                 co-routine has not already been woken. */\r
1364                 if( !xCoRoutinePreviouslyWoken )\r
1365                 {\r
1366                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
1367                         {\r
1368                                 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
1369                                 {\r
1370                                         return pdTRUE;\r
1371                                 }\r
1372                         }\r
1373                 }\r
1374         }\r
1375 \r
1376         return xCoRoutinePreviouslyWoken;\r
1377 }\r
1378 #endif\r
1379 /*-----------------------------------------------------------*/\r
1380 \r
1381 #if configUSE_CO_ROUTINES == 1\r
1382 signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxCoRoutineWoken )\r
1383 {\r
1384 signed portBASE_TYPE xReturn;\r
1385 \r
1386         /* We cannot block from an ISR, so check there is data available. If\r
1387         not then just leave without doing anything. */\r
1388         if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
1389         {\r
1390                 /* Copy the data from the queue. */\r
1391                 pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
1392                 if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
1393                 {\r
1394                         pxQueue->pcReadFrom = pxQueue->pcHead;\r
1395                 }\r
1396                 --( pxQueue->uxMessagesWaiting );\r
1397                 memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
1398 \r
1399                 if( !( *pxCoRoutineWoken ) )\r
1400                 {\r
1401                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )\r
1402                         {\r
1403                                 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
1404                                 {\r
1405                                         *pxCoRoutineWoken = pdTRUE;\r
1406                                 }\r
1407                         }\r
1408                 }\r
1409 \r
1410                 xReturn = pdPASS;\r
1411         }\r
1412         else\r
1413         {\r
1414                 xReturn = pdFAIL;\r
1415         }\r
1416 \r
1417         return xReturn;\r
1418 }\r
1419 #endif\r
1420 /*-----------------------------------------------------------*/\r
1421 \r
1422 #if configQUEUE_REGISTRY_SIZE > 0\r
1423 \r
1424         void vQueueAddToRegistry( xQueueHandle xQueue, signed char *pcQueueName )\r
1425         {\r
1426         unsigned portBASE_TYPE ux;\r
1427 \r
1428                 /* See if there is an empty space in the registry.  A NULL name denotes\r
1429                 a free slot. */\r
1430                 for( ux = 0; ux < configQUEUE_REGISTRY_SIZE; ux++ )\r
1431                 {\r
1432                         if( xQueueRegistry[ ux ].pcQueueName == NULL )\r
1433                         {\r
1434                                 /* Store the information on this queue. */\r
1435                                 xQueueRegistry[ ux ].pcQueueName = pcQueueName;\r
1436                                 xQueueRegistry[ ux ].xHandle = xQueue;\r
1437                                 break;\r
1438                         }\r
1439                 }\r
1440         }\r
1441 \r
1442 #endif\r
1443         /*-----------------------------------------------------------*/\r
1444 \r
1445 #if configQUEUE_REGISTRY_SIZE > 0\r
1446 \r
1447         static void vQueueUnregisterQueue( xQueueHandle xQueue )\r
1448         {\r
1449         unsigned portBASE_TYPE ux;\r
1450 \r
1451                 /* See if the handle of the queue being unregistered in actually in the\r
1452                 registry. */\r
1453                 for( ux = 0; ux < configQUEUE_REGISTRY_SIZE; ux++ )\r
1454                 {\r
1455                         if( xQueueRegistry[ ux ].xHandle == xQueue )\r
1456                         {\r
1457                                 /* Set the name to NULL to show that this slot if free again. */\r
1458                                 xQueueRegistry[ ux ].pcQueueName = NULL;\r
1459                                 break;\r
1460                         }\r
1461                 }\r
1462 \r
1463         }\r
1464 \r
1465 #endif\r
1466 \r