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