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