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