]> git.sur5r.net Git - freertos/blob - Source/queue.c
Prepare for V5.0.4 release.
[freertos] / Source / queue.c
1 /*\r
2         FreeRTOS.org V5.0.4 - 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 /* The two tasks are blocked on the queue, the low priority task is polling/running. */\r
947 \r
948 /* An interrupt occurs here - which unblocks the HP tasks, but they do not run. */\r
949                 taskENTER_CRITICAL();\r
950                 {\r
951 /* Because the interrupt occurred the LP task manages to grab the data as the other two tasks are not yet running. */\r
952                         if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
953                         {\r
954                                 /* Remember our read position in case we are just peeking. */\r
955                                 pcOriginalReadPosition = pxQueue->pcReadFrom;\r
956 \r
957                                 prvCopyDataFromQueue( pxQueue, pvBuffer );\r
958 \r
959                                 if( xJustPeeking == pdFALSE )\r
960                                 {\r
961                                         traceQUEUE_RECEIVE( pxQueue );\r
962 \r
963                                         /* We are actually removing data. */\r
964                                         --( pxQueue->uxMessagesWaiting );\r
965 \r
966                                         #if ( configUSE_MUTEXES == 1 )\r
967                                         {\r
968                                                 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
969                                                 {\r
970                                                         /* Record the information required to implement\r
971                                                         priority inheritance should it become necessary. */\r
972                                                         pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();\r
973                                                 }\r
974                                         }\r
975                                         #endif\r
976 \r
977                                         if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )\r
978                                         {\r
979                                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )\r
980                                                 {\r
981                                                         taskYIELD();\r
982                                                 }\r
983                                         }\r
984                                 }\r
985                                 else\r
986                                 {\r
987                                         traceQUEUE_PEEK( pxQueue );\r
988 \r
989                                         /* We are not removing the data, so reset our read\r
990                                         pointer. */\r
991                                         pxQueue->pcReadFrom = pcOriginalReadPosition;\r
992 \r
993                                         /* The data is being left in the queue, so see if there are\r
994                                         any other tasks waiting for the data. */\r
995                                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
996                                         {\r
997                                                 /* Tasks that are removed from the event list will get added to\r
998                                                 the pending ready list as the scheduler is still suspended. */\r
999                                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
1000                                                 {\r
1001                                                         /* The task waiting has a higher priority than this task. */\r
1002                                                         taskYIELD();\r
1003                                                 }\r
1004                                         }\r
1005 \r
1006                                 }\r
1007 \r
1008                                 xReturn = pdPASS;\r
1009                         }\r
1010                         else\r
1011                         {\r
1012                                 xReturn = errQUEUE_EMPTY;\r
1013                         }\r
1014                 }\r
1015                 taskEXIT_CRITICAL();\r
1016 \r
1017                 if( xReturn == errQUEUE_EMPTY )\r
1018                 {\r
1019                         if( xTicksToWait > ( portTickType ) 0 )\r
1020                         {\r
1021                                 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
1022                                 {\r
1023                                         xReturn = queueERRONEOUS_UNBLOCK;\r
1024                                 }\r
1025                                 else\r
1026                                 {\r
1027                                         traceQUEUE_RECEIVE_FAILED( pxQueue );\r
1028                                 }\r
1029                         }\r
1030                         else\r
1031                         {\r
1032                                 traceQUEUE_RECEIVE_FAILED( pxQueue );\r
1033                         }\r
1034                 }\r
1035 \r
1036         } while( xReturn == queueERRONEOUS_UNBLOCK );\r
1037 \r
1038         return xReturn;\r
1039 }\r
1040 /*-----------------------------------------------------------*/\r
1041 \r
1042 signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken )\r
1043 {\r
1044 signed portBASE_TYPE xReturn;\r
1045 unsigned portBASE_TYPE uxSavedInterruptStatus;\r
1046 \r
1047         uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();\r
1048         {\r
1049                 /* We cannot block from an ISR, so check there is data available. */\r
1050                 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
1051                 {\r
1052                         traceQUEUE_RECEIVE_FROM_ISR( pxQueue );\r
1053 \r
1054                         prvCopyDataFromQueue( pxQueue, pvBuffer );\r
1055                         --( pxQueue->uxMessagesWaiting );\r
1056 \r
1057                         /* If the queue is locked we will not modify the event list.  Instead\r
1058                         we update the lock count so the task that unlocks the queue will know\r
1059                         that an ISR has removed data while the queue was locked. */\r
1060                         if( pxQueue->xRxLock == queueUNLOCKED )\r
1061                         {\r
1062                                 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )\r
1063                                 {\r
1064                                         if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
1065                                         {\r
1066                                                 /* The task waiting has a higher priority than us so\r
1067                                                 force a context switch. */\r
1068                                                 *pxTaskWoken = pdTRUE;\r
1069                                         }\r
1070                                 }\r
1071                         }\r
1072                         else\r
1073                         {\r
1074                                 /* Increment the lock count so the task that unlocks the queue\r
1075                                 knows that data was removed while it was locked. */\r
1076                                 ++( pxQueue->xRxLock );\r
1077                         }\r
1078 \r
1079                         xReturn = pdPASS;\r
1080                 }\r
1081                 else\r
1082                 {\r
1083                         xReturn = pdFAIL;\r
1084                         traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue );\r
1085                 }\r
1086         }\r
1087         portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );\r
1088 \r
1089         return xReturn;\r
1090 }\r
1091 /*-----------------------------------------------------------*/\r
1092 \r
1093 unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle pxQueue )\r
1094 {\r
1095 unsigned portBASE_TYPE uxReturn;\r
1096 \r
1097         taskENTER_CRITICAL();\r
1098                 uxReturn = pxQueue->uxMessagesWaiting;\r
1099         taskEXIT_CRITICAL();\r
1100 \r
1101         return uxReturn;\r
1102 }\r
1103 /*-----------------------------------------------------------*/\r
1104 \r
1105 unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue )\r
1106 {\r
1107 unsigned portBASE_TYPE uxReturn;\r
1108 \r
1109         uxReturn = pxQueue->uxMessagesWaiting;\r
1110 \r
1111         return uxReturn;\r
1112 }\r
1113 /*-----------------------------------------------------------*/\r
1114 \r
1115 void vQueueDelete( xQueueHandle pxQueue )\r
1116 {\r
1117         traceQUEUE_DELETE( pxQueue );\r
1118         vQueueUnregisterQueue( pxQueue );\r
1119         vPortFree( pxQueue->pcHead );\r
1120         vPortFree( pxQueue );\r
1121 }\r
1122 /*-----------------------------------------------------------*/\r
1123 \r
1124 static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition )\r
1125 {\r
1126         if( pxQueue->uxItemSize == ( unsigned portBASE_TYPE ) 0 )\r
1127         {\r
1128                 #if ( configUSE_MUTEXES == 1 )\r
1129                 {\r
1130                         if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
1131                         {\r
1132                                 /* The mutex is no longer being held. */\r
1133                                 vTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder );\r
1134                 pxQueue->pxMutexHolder = NULL;\r
1135                         }\r
1136                 }\r
1137                 #endif\r
1138         }\r
1139         else if( xPosition == queueSEND_TO_BACK )\r
1140         {\r
1141                 memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );\r
1142                 pxQueue->pcWriteTo += pxQueue->uxItemSize;\r
1143                 if( pxQueue->pcWriteTo >= pxQueue->pcTail )\r
1144                 {\r
1145                         pxQueue->pcWriteTo = pxQueue->pcHead;\r
1146                 }\r
1147         }\r
1148         else\r
1149         {\r
1150                 memcpy( ( void * ) pxQueue->pcReadFrom, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );\r
1151                 pxQueue->pcReadFrom -= pxQueue->uxItemSize;\r
1152                 if( pxQueue->pcReadFrom < pxQueue->pcHead )\r
1153                 {\r
1154                         pxQueue->pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize );\r
1155                 }\r
1156         }\r
1157 \r
1158         ++( pxQueue->uxMessagesWaiting );\r
1159 }\r
1160 /*-----------------------------------------------------------*/\r
1161 \r
1162 static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer )\r
1163 {\r
1164         if( pxQueue->uxQueueType != queueQUEUE_IS_MUTEX )\r
1165         {\r
1166                 pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
1167                 if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
1168                 {\r
1169                         pxQueue->pcReadFrom = pxQueue->pcHead;\r
1170                 }\r
1171                 memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
1172         }\r
1173 }\r
1174 /*-----------------------------------------------------------*/\r
1175 \r
1176 static void prvUnlockQueue( xQueueHandle pxQueue )\r
1177 {\r
1178         /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */\r
1179 \r
1180         /* The lock counts contains the number of extra data items placed or\r
1181         removed from the queue while the queue was locked.  When a queue is\r
1182         locked items can be added or removed, but the event lists cannot be\r
1183         updated. */\r
1184         taskENTER_CRITICAL();\r
1185         {\r
1186                 /* See if data was added to the queue while it was locked. */\r
1187                 while( pxQueue->xTxLock > queueLOCKED_UNMODIFIED )\r
1188                 {\r
1189                         /* Data was posted while the queue was locked.  Are any tasks\r
1190                         blocked waiting for data to become available? */\r
1191                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
1192                         {\r
1193                                 /* Tasks that are removed from the event list will get added to\r
1194                                 the pending ready list as the scheduler is still suspended. */\r
1195                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
1196                                 {\r
1197                                         /* The task waiting has a higher priority so record that a\r
1198                                         context switch is required. */\r
1199                                         vTaskMissedYield();\r
1200                                 }\r
1201 \r
1202                                 --( pxQueue->xTxLock );\r
1203                         }\r
1204                         else\r
1205                         {\r
1206                                 break;\r
1207                         }\r
1208                 }\r
1209 \r
1210                 pxQueue->xTxLock = queueUNLOCKED;\r
1211         }\r
1212         taskEXIT_CRITICAL();\r
1213 \r
1214         /* Do the same for the Rx lock. */\r
1215         taskENTER_CRITICAL();\r
1216         {\r
1217                 while( pxQueue->xRxLock > queueLOCKED_UNMODIFIED )\r
1218                 {\r
1219                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )\r
1220                         {\r
1221                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
1222                                 {\r
1223                                         vTaskMissedYield();\r
1224                                 }\r
1225 \r
1226                                 --( pxQueue->xRxLock );\r
1227                         }\r
1228                         else\r
1229                         {\r
1230                                 break;\r
1231                         }\r
1232                 }\r
1233 \r
1234                 pxQueue->xRxLock = queueUNLOCKED;\r
1235         }\r
1236         taskEXIT_CRITICAL();\r
1237 }\r
1238 /*-----------------------------------------------------------*/\r
1239 \r
1240 static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue )\r
1241 {\r
1242 signed portBASE_TYPE xReturn;\r
1243 \r
1244         taskENTER_CRITICAL();\r
1245                 xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );\r
1246         taskEXIT_CRITICAL();\r
1247 \r
1248         return xReturn;\r
1249 }\r
1250 /*-----------------------------------------------------------*/\r
1251 \r
1252 signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue )\r
1253 {\r
1254 signed portBASE_TYPE xReturn;\r
1255 \r
1256         xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );\r
1257 \r
1258         return xReturn;\r
1259 }\r
1260 /*-----------------------------------------------------------*/\r
1261 \r
1262 static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue )\r
1263 {\r
1264 signed portBASE_TYPE xReturn;\r
1265 \r
1266         taskENTER_CRITICAL();\r
1267                 xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );\r
1268         taskEXIT_CRITICAL();\r
1269 \r
1270         return xReturn;\r
1271 }\r
1272 /*-----------------------------------------------------------*/\r
1273 \r
1274 signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue )\r
1275 {\r
1276 signed portBASE_TYPE xReturn;\r
1277 \r
1278         xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );\r
1279 \r
1280         return xReturn;\r
1281 }\r
1282 /*-----------------------------------------------------------*/\r
1283 \r
1284 #if configUSE_CO_ROUTINES == 1\r
1285 signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )\r
1286 {\r
1287 signed portBASE_TYPE xReturn;\r
1288 \r
1289         /* If the queue is already full we may have to block.  A critical section\r
1290         is required to prevent an interrupt removing something from the queue\r
1291         between the check to see if the queue is full and blocking on the queue. */\r
1292         portDISABLE_INTERRUPTS();\r
1293         {\r
1294                 if( prvIsQueueFull( pxQueue ) )\r
1295                 {\r
1296                         /* The queue is full - do we want to block or just leave without\r
1297                         posting? */\r
1298                         if( xTicksToWait > ( portTickType ) 0 )\r
1299                         {\r
1300                                 /* As this is called from a coroutine we cannot block directly, but\r
1301                                 return indicating that we need to block. */\r
1302                                 vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToSend ) );\r
1303                                 portENABLE_INTERRUPTS();\r
1304                                 return errQUEUE_BLOCKED;\r
1305                         }\r
1306                         else\r
1307                         {\r
1308                                 portENABLE_INTERRUPTS();\r
1309                                 return errQUEUE_FULL;\r
1310                         }\r
1311                 }\r
1312         }\r
1313         portENABLE_INTERRUPTS();\r
1314 \r
1315         portNOP();\r
1316 \r
1317         portDISABLE_INTERRUPTS();\r
1318         {\r
1319                 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
1320                 {\r
1321                         /* There is room in the queue, copy the data into the queue. */\r
1322                         prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );\r
1323                         xReturn = pdPASS;\r
1324 \r
1325                         /* Were any co-routines waiting for data to become available? */\r
1326                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
1327                         {\r
1328                                 /* In this instance the co-routine could be placed directly\r
1329                                 into the ready list as we are within a critical section.\r
1330                                 Instead the same pending ready list mechanism is used as if\r
1331                                 the event were caused from within an interrupt. */\r
1332                                 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
1333                                 {\r
1334                                         /* The co-routine waiting has a higher priority so record\r
1335                                         that a yield might be appropriate. */\r
1336                                         xReturn = errQUEUE_YIELD;\r
1337                                 }\r
1338                         }\r
1339                 }\r
1340                 else\r
1341                 {\r
1342                         xReturn = errQUEUE_FULL;\r
1343                 }\r
1344         }\r
1345         portENABLE_INTERRUPTS();\r
1346 \r
1347         return xReturn;\r
1348 }\r
1349 #endif\r
1350 /*-----------------------------------------------------------*/\r
1351 \r
1352 #if configUSE_CO_ROUTINES == 1\r
1353 signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait )\r
1354 {\r
1355 signed portBASE_TYPE xReturn;\r
1356 \r
1357         /* If the queue is already empty we may have to block.  A critical section\r
1358         is required to prevent an interrupt adding something to the queue\r
1359         between the check to see if the queue is empty and blocking on the queue. */\r
1360         portDISABLE_INTERRUPTS();\r
1361         {\r
1362                 if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 )\r
1363                 {\r
1364                         /* There are no messages in the queue, do we want to block or just\r
1365                         leave with nothing? */\r
1366                         if( xTicksToWait > ( portTickType ) 0 )\r
1367                         {\r
1368                                 /* As this is a co-routine we cannot block directly, but return\r
1369                                 indicating that we need to block. */\r
1370                                 vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToReceive ) );\r
1371                                 portENABLE_INTERRUPTS();\r
1372                                 return errQUEUE_BLOCKED;\r
1373                         }\r
1374                         else\r
1375                         {\r
1376                                 portENABLE_INTERRUPTS();\r
1377                                 return errQUEUE_FULL;\r
1378                         }\r
1379                 }\r
1380         }\r
1381         portENABLE_INTERRUPTS();\r
1382 \r
1383         portNOP();\r
1384 \r
1385         portDISABLE_INTERRUPTS();\r
1386         {\r
1387                 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
1388                 {\r
1389                         /* Data is available from the queue. */\r
1390                         pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
1391                         if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
1392                         {\r
1393                                 pxQueue->pcReadFrom = pxQueue->pcHead;\r
1394                         }\r
1395                         --( pxQueue->uxMessagesWaiting );\r
1396                         memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
1397 \r
1398                         xReturn = pdPASS;\r
1399 \r
1400                         /* Were any co-routines waiting for space to become available? */\r
1401                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )\r
1402                         {\r
1403                                 /* In this instance the co-routine could be placed directly\r
1404                                 into the ready list as we are within a critical section.\r
1405                                 Instead the same pending ready list mechanism is used as if\r
1406                                 the event were caused from within an interrupt. */\r
1407                                 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
1408                                 {\r
1409                                         xReturn = errQUEUE_YIELD;\r
1410                                 }\r
1411                         }\r
1412                 }\r
1413                 else\r
1414                 {\r
1415                         xReturn = pdFAIL;\r
1416                 }\r
1417         }\r
1418         portENABLE_INTERRUPTS();\r
1419 \r
1420         return xReturn;\r
1421 }\r
1422 #endif\r
1423 /*-----------------------------------------------------------*/\r
1424 \r
1425 \r
1426 \r
1427 #if configUSE_CO_ROUTINES == 1\r
1428 signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken )\r
1429 {\r
1430         /* Cannot block within an ISR so if there is no space on the queue then\r
1431         exit without doing anything. */\r
1432         if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
1433         {\r
1434                 prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );\r
1435 \r
1436                 /* We only want to wake one co-routine per ISR, so check that a\r
1437                 co-routine has not already been woken. */\r
1438                 if( !xCoRoutinePreviouslyWoken )\r
1439                 {\r
1440                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
1441                         {\r
1442                                 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
1443                                 {\r
1444                                         return pdTRUE;\r
1445                                 }\r
1446                         }\r
1447                 }\r
1448         }\r
1449 \r
1450         return xCoRoutinePreviouslyWoken;\r
1451 }\r
1452 #endif\r
1453 /*-----------------------------------------------------------*/\r
1454 \r
1455 #if configUSE_CO_ROUTINES == 1\r
1456 signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxCoRoutineWoken )\r
1457 {\r
1458 signed portBASE_TYPE xReturn;\r
1459 \r
1460         /* We cannot block from an ISR, so check there is data available. If\r
1461         not then just leave without doing anything. */\r
1462         if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
1463         {\r
1464                 /* Copy the data from the queue. */\r
1465                 pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
1466                 if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
1467                 {\r
1468                         pxQueue->pcReadFrom = pxQueue->pcHead;\r
1469                 }\r
1470                 --( pxQueue->uxMessagesWaiting );\r
1471                 memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
1472 \r
1473                 if( !( *pxCoRoutineWoken ) )\r
1474                 {\r
1475                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )\r
1476                         {\r
1477                                 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
1478                                 {\r
1479                                         *pxCoRoutineWoken = pdTRUE;\r
1480                                 }\r
1481                         }\r
1482                 }\r
1483 \r
1484                 xReturn = pdPASS;\r
1485         }\r
1486         else\r
1487         {\r
1488                 xReturn = pdFAIL;\r
1489         }\r
1490 \r
1491         return xReturn;\r
1492 }\r
1493 #endif\r
1494 /*-----------------------------------------------------------*/\r
1495 \r
1496 #if configQUEUE_REGISTRY_SIZE > 0\r
1497 \r
1498         void vQueueAddToRegistry( xQueueHandle xQueue, signed portCHAR *pcQueueName )\r
1499         {\r
1500         unsigned portBASE_TYPE ux;\r
1501 \r
1502                 /* See if there is an empty space in the registry.  A NULL name denotes\r
1503                 a free slot. */\r
1504                 for( ux = 0; ux < configQUEUE_REGISTRY_SIZE; ux++ )\r
1505                 {\r
1506                         if( xQueueRegistry[ ux ].pcQueueName == NULL )\r
1507                         {\r
1508                                 /* Store the information on this queue. */\r
1509                                 xQueueRegistry[ ux ].pcQueueName = pcQueueName;\r
1510                                 xQueueRegistry[ ux ].xHandle = xQueue;\r
1511                                 break;\r
1512                         }\r
1513                 }\r
1514         }\r
1515 \r
1516 #endif\r
1517         /*-----------------------------------------------------------*/\r
1518 \r
1519 #if configQUEUE_REGISTRY_SIZE > 0\r
1520 \r
1521         static void vQueueUnregisterQueue( xQueueHandle xQueue )\r
1522         {\r
1523         unsigned portBASE_TYPE ux;\r
1524 \r
1525                 /* See if the handle of the queue being unregistered in actually in the\r
1526                 registry. */\r
1527                 for( ux = 0; ux < configQUEUE_REGISTRY_SIZE; ux++ )\r
1528                 {\r
1529                         if( xQueueRegistry[ ux ].xHandle == xQueue )\r
1530                         {\r
1531                                 /* Set the name to NULL to show that this slot if free again. */\r
1532                                 xQueueRegistry[ ux ].pcQueueName = NULL;\r
1533                                 break;\r
1534                         }\r
1535                 }\r
1536         }\r
1537 \r
1538 #endif\r
1539 \r