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