]> git.sur5r.net Git - freertos/blob - Source/queue.c
Changes from V4.1.2
[freertos] / Source / queue.c
1 /*\r
2         FreeRTOS.org V4.1.2 - Copyright (C) 2003-2006 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         See http://www.FreeRTOS.org for documentation, latest information, license\r
28         and contact details.  Please ensure to read the configuration and relevant\r
29         port sections of the online documentation.\r
30         ***************************************************************************\r
31 */\r
32 \r
33 /*\r
34 Changes from V1.01\r
35 \r
36         + More use of 8bit data types.\r
37         + Function name prefixes changed where the data type returned has changed.\r
38 \r
39 Changed from V2.0.0\r
40 \r
41         + Added the queue locking mechanism and make more use of the scheduler\r
42           suspension feature to minimise the time interrupts have to be disabled\r
43           when accessing a queue.\r
44 \r
45 Changed from V2.2.0\r
46 \r
47         + Explicit use of 'signed' qualifier on portCHAR types added.\r
48 \r
49 Changes from V3.0.0\r
50 \r
51         + API changes as described on the FreeRTOS.org WEB site.\r
52 \r
53 Changes from V3.2.3\r
54 \r
55         + Added the queue functions that can be used from co-routines.\r
56 \r
57 Changes from V4.0.5\r
58 \r
59         + Added a loop within xQueueSend() and xQueueReceive() to prevent the\r
60           functions exiting when a block time remains and the function has\r
61           not completed.\r
62 \r
63 */\r
64 \r
65 #include <stdlib.h>\r
66 #include <string.h>\r
67 #include "FreeRTOS.h"\r
68 #include "task.h"\r
69 #include "croutine.h"\r
70 \r
71 /*-----------------------------------------------------------\r
72  * PUBLIC LIST API documented in list.h\r
73  *----------------------------------------------------------*/\r
74 \r
75 /* Constants used with the cRxLock and cTxLock structure members. */\r
76 #define queueUNLOCKED   ( ( signed portBASE_TYPE ) -1 )\r
77 #define queueERRONEOUS_UNBLOCK                                  ( -1 )\r
78 \r
79 /*\r
80  * Definition of the queue used by the scheduler.\r
81  * Items are queued by copy, not reference.\r
82  */\r
83 typedef struct QueueDefinition\r
84 {\r
85         signed portCHAR *pcHead;                                /*< Points to the beginning of the queue storage area. */\r
86         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
87 \r
88         signed portCHAR *pcWriteTo;                             /*< Points to the free next place in the storage area. */\r
89         signed portCHAR *pcReadFrom;                    /*< Points to the last place that a queued item was read from. */\r
90 \r
91         xList xTasksWaitingToSend;                              /*< List of tasks that are blocked waiting to post onto this queue.  Stored in priority order. */\r
92         xList xTasksWaitingToReceive;                   /*< List of tasks that are blocked waiting to read from this queue.  Stored in priority order. */\r
93 \r
94         unsigned portBASE_TYPE uxMessagesWaiting;/*< The number of items currently in the queue. */\r
95         unsigned portBASE_TYPE uxLength;                /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */\r
96         unsigned portBASE_TYPE uxItemSize;              /*< The size of each items that the queue will hold. */\r
97 \r
98         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
99         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
100 } xQUEUE;\r
101 /*-----------------------------------------------------------*/\r
102 \r
103 /*\r
104  * Inside this file xQueueHandle is a pointer to a xQUEUE structure.\r
105  * To keep the definition private the API header file defines it as a\r
106  * pointer to void.\r
107  */\r
108 typedef xQUEUE * xQueueHandle;\r
109 \r
110 /*\r
111  * Prototypes for public functions are included here so we don't have to\r
112  * include the API header file (as it defines xQueueHandle differently).  These\r
113  * functions are documented in the API header file.\r
114  */\r
115 xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize );\r
116 signed portBASE_TYPE xQueueSend( xQueueHandle xQueue, const void * pvItemToQueue, portTickType xTicksToWait );\r
117 unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle pxQueue );\r
118 void vQueueDelete( xQueueHandle xQueue );\r
119 signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken );\r
120 signed portBASE_TYPE xQueueReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait );\r
121 signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );\r
122 \r
123 #if configUSE_CO_ROUTINES == 1\r
124         signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken );\r
125         signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );\r
126         signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait );\r
127         signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait );\r
128 #endif\r
129 \r
130 /*\r
131  * Unlocks a queue locked by a call to prvLockQueue.  Locking a queue does not\r
132  * prevent an ISR from adding or removing items to the queue, but does prevent\r
133  * an ISR from removing tasks from the queue event lists.  If an ISR finds a\r
134  * queue is locked it will instead increment the appropriate queue lock count\r
135  * to indicate that a task may require unblocking.  When the queue in unlocked\r
136  * these lock counts are inspected, and the appropriate action taken.\r
137  */\r
138 static void prvUnlockQueue( xQueueHandle pxQueue );\r
139 \r
140 /*\r
141  * Uses a critical section to determine if there is any data in a queue.\r
142  *\r
143  * @return pdTRUE if the queue contains no items, otherwise pdFALSE.\r
144  */\r
145 static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue );\r
146 \r
147 /*\r
148  * Uses a critical section to determine if there is any space in a queue.\r
149  *\r
150  * @return pdTRUE if there is no space, otherwise pdFALSE;\r
151  */\r
152 static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue );\r
153 \r
154 /*\r
155  * Macro that copies an item into the queue.  This is done by copying the item\r
156  * byte for byte, not by reference.  Updates the queue state to ensure it's\r
157  * integrity after the copy.\r
158  */\r
159 #define prvCopyQueueData( pxQueue, pvItemToQueue )                                                                                              \\r
160 {                                                                                                                                                                                               \\r
161         memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );       \\r
162         ++( pxQueue->uxMessagesWaiting );                                                                                                                       \\r
163         pxQueue->pcWriteTo += pxQueue->uxItemSize;                                                                                                      \\r
164         if( pxQueue->pcWriteTo >= pxQueue->pcTail )                                                                                                     \\r
165         {                                                                                                                                                                                       \\r
166                 pxQueue->pcWriteTo = pxQueue->pcHead;                                                                                                   \\r
167         }                                                                                                                                                                                       \\r
168 }\r
169 /*-----------------------------------------------------------*/\r
170 \r
171 /*\r
172  * Macro to mark a queue as locked.  Locking a queue prevents an ISR from\r
173  * accessing the queue event lists.\r
174  */\r
175 #define prvLockQueue( pxQueue )                 \\r
176 {                                                                               \\r
177         taskENTER_CRITICAL();                           \\r
178                 ++( pxQueue->xRxLock );                 \\r
179                 ++( pxQueue->xTxLock );                 \\r
180         taskEXIT_CRITICAL();                            \\r
181 }\r
182 /*-----------------------------------------------------------*/\r
183 \r
184 \r
185 /*-----------------------------------------------------------\r
186  * PUBLIC QUEUE MANAGEMENT API documented in queue.h\r
187  *----------------------------------------------------------*/\r
188 \r
189 xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize )\r
190 {\r
191 xQUEUE *pxNewQueue;\r
192 size_t xQueueSizeInBytes;\r
193 \r
194         /* Allocate the new queue structure. */\r
195         if( uxQueueLength > ( unsigned portBASE_TYPE ) 0 )\r
196         {\r
197                 pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );\r
198                 if( pxNewQueue != NULL )\r
199                 {\r
200                         /* Create the list of pointers to queue items.  The queue is one byte\r
201                         longer than asked for to make wrap checking easier/faster. */\r
202                         xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ) + ( size_t ) 1;\r
203 \r
204                         pxNewQueue->pcHead = ( signed portCHAR * ) pvPortMalloc( xQueueSizeInBytes );\r
205                         if( pxNewQueue->pcHead != NULL )\r
206                         {\r
207                                 /* Initialise the queue members as described above where the\r
208                                 queue type is defined. */\r
209                                 pxNewQueue->pcTail = pxNewQueue->pcHead + ( uxQueueLength * uxItemSize );\r
210                                 pxNewQueue->uxMessagesWaiting = 0;\r
211                                 pxNewQueue->pcWriteTo = pxNewQueue->pcHead;\r
212                                 pxNewQueue->pcReadFrom = pxNewQueue->pcHead + ( ( uxQueueLength - 1 ) * uxItemSize );\r
213                                 pxNewQueue->uxLength = uxQueueLength;\r
214                                 pxNewQueue->uxItemSize = uxItemSize;\r
215                                 pxNewQueue->xRxLock = queueUNLOCKED;\r
216                                 pxNewQueue->xTxLock = queueUNLOCKED;\r
217 \r
218                                 /* Likewise ensure the event queues start with the correct state. */\r
219                                 vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );\r
220                                 vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );\r
221 \r
222                                 return  pxNewQueue;\r
223                         }\r
224                         else\r
225                         {\r
226                                 vPortFree( pxNewQueue );\r
227                         }\r
228                 }\r
229         }\r
230 \r
231         /* Will only reach here if we could not allocate enough memory or no memory\r
232         was required. */\r
233         return NULL;\r
234 }\r
235 /*-----------------------------------------------------------*/\r
236 \r
237 signed portBASE_TYPE xQueueSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )\r
238 {\r
239 signed portBASE_TYPE xReturn;\r
240 xTimeOutType xTimeOut;\r
241 \r
242         /* Make sure other tasks do not access the queue. */\r
243         vTaskSuspendAll();\r
244 \r
245         /* Capture the current time status for future reference. */\r
246         vTaskSetTimeOutState( &xTimeOut );\r
247 \r
248         /* It is important that this is the only thread/ISR that modifies the\r
249         ready or delayed lists until xTaskResumeAll() is called.  Places where\r
250         the ready/delayed lists are modified include:\r
251 \r
252                 + vTaskDelay() -  Nothing can call vTaskDelay as the scheduler is\r
253                   suspended, vTaskDelay() cannot be called from an ISR.\r
254                 + vTaskPrioritySet() - Has a critical section around the access.\r
255                 + vTaskSwitchContext() - This will not get executed while the scheduler\r
256                   is suspended.\r
257                 + prvCheckDelayedTasks() - This will not get executed while the\r
258                   scheduler is suspended.\r
259                 + xTaskCreate() - Has a critical section around the access.\r
260                 + vTaskResume() - Has a critical section around the access.\r
261                 + xTaskResumeAll() - Has a critical section around the access.\r
262                 + xTaskRemoveFromEventList - Checks to see if the scheduler is\r
263                   suspended.  If so then the TCB being removed from the event is\r
264                   removed from the event and added to the xPendingReadyList.\r
265         */\r
266 \r
267         /* Make sure interrupts do not access the queue event list. */\r
268         prvLockQueue( pxQueue );\r
269 \r
270         /* It is important that interrupts to not access the event list of the\r
271         queue being modified here.  Places where the event list is modified\r
272         include:\r
273 \r
274                 + xQueueSendFromISR().  This checks the lock on the queue to see if\r
275                   it has access.  If the queue is locked then the Tx lock count is\r
276                   incremented to signify that a task waiting for data can be made ready\r
277                   once the queue lock is removed.  If the queue is not locked then\r
278                   a task can be moved from the event list, but will not be removed\r
279                   from the delayed list or placed in the ready list until the scheduler\r
280                   is unlocked.\r
281 \r
282                 + xQueueReceiveFromISR().  As per xQueueSendFromISR().\r
283         */\r
284                 \r
285         /* If the queue is already full we may have to block. */\r
286         do\r
287         {\r
288                 if( prvIsQueueFull( pxQueue ) )\r
289                 {\r
290                         /* The queue is full - do we want to block or just leave without\r
291                         posting? */\r
292                         if( xTicksToWait > ( portTickType ) 0 )\r
293                         {\r
294                                 /* We are going to place ourselves on the xTasksWaitingToSend event\r
295                                 list, and will get woken should the delay expire, or space become\r
296                                 available on the queue.\r
297                                 \r
298                                 As detailed above we do not require mutual exclusion on the event\r
299                                 list as nothing else can modify it or the ready lists while we\r
300                                 have the scheduler suspended and queue locked.\r
301                                 \r
302                                 It is possible that an ISR has removed data from the queue since we\r
303                                 checked if any was available.  If this is the case then the data\r
304                                 will have been copied from the queue, and the queue variables\r
305                                 updated, but the event list will not yet have been checked to see if\r
306                                 anything is waiting as the queue is locked. */\r
307                                 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );\r
308         \r
309                                 /* Force a context switch now as we are blocked.  We can do\r
310                                 this from within a critical section as the task we are\r
311                                 switching to has its own context.  When we return here (i.e. we\r
312                                 unblock) we will leave the critical section as normal.\r
313                                 \r
314                                 It is possible that an ISR has caused an event on an unrelated and\r
315                                 unlocked queue.  If this was the case then the event list for that\r
316                                 queue will have been updated but the ready lists left unchanged -\r
317                                 instead the readied task will have been added to the pending ready\r
318                                 list. */\r
319                                 taskENTER_CRITICAL();\r
320                                 {\r
321                                         /* We can safely unlock the queue and scheduler here as\r
322                                         interrupts are disabled.  We must not yield with anything\r
323                                         locked, but we can yield from within a critical section.\r
324                                         \r
325                                         Tasks that have been placed on the pending ready list cannot\r
326                                         be tasks that are waiting for events on this queue.  See\r
327                                         in comment xTaskRemoveFromEventList(). */\r
328                                         prvUnlockQueue( pxQueue );\r
329         \r
330                                         /* Resuming the scheduler may cause a yield.  If so then there\r
331                                         is no point yielding again here. */\r
332                                         if( !xTaskResumeAll() )\r
333                                         {\r
334                                                 taskYIELD();\r
335                                         }\r
336         \r
337                                         /* Before leaving the critical section we have to ensure\r
338                                         exclusive access again. */\r
339                                         vTaskSuspendAll();\r
340                                         prvLockQueue( pxQueue );                                \r
341                                 }\r
342                                 taskEXIT_CRITICAL();\r
343                         }\r
344                 }\r
345                         \r
346                 /* When we are here it is possible that we unblocked as space became\r
347                 available on the queue.  It is also possible that an ISR posted to the\r
348                 queue since we left the critical section, so it may be that again there\r
349                 is no space.  This would only happen if a task and ISR post onto the\r
350                 same queue. */\r
351                 taskENTER_CRITICAL();\r
352                 {\r
353                         if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
354                         {\r
355                                 /* There is room in the queue, copy the data into the queue. */                 \r
356                                 prvCopyQueueData( pxQueue, pvItemToQueue );             \r
357                                 xReturn = pdPASS;\r
358         \r
359                                 /* Update the TxLock count so prvUnlockQueue knows to check for\r
360                                 tasks waiting for data to become available in the queue. */\r
361                                 ++( pxQueue->xTxLock );\r
362                         }\r
363                         else\r
364                         {\r
365                                 xReturn = errQUEUE_FULL;\r
366                         }\r
367                 }\r
368                 taskEXIT_CRITICAL();\r
369 \r
370                 if( xReturn == errQUEUE_FULL )\r
371                 {\r
372                         if( xTicksToWait > 0 )\r
373                         {\r
374                                 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
375                                 {\r
376                                         xReturn = queueERRONEOUS_UNBLOCK;\r
377                                 }\r
378                         }\r
379                 }\r
380         }\r
381         while( xReturn == queueERRONEOUS_UNBLOCK );\r
382 \r
383         prvUnlockQueue( pxQueue );\r
384         xTaskResumeAll();\r
385 \r
386         return xReturn;\r
387 }\r
388 /*-----------------------------------------------------------*/\r
389 \r
390 signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken )\r
391 {\r
392         /* Similar to xQueueSend, except we don't block if there is no room in the\r
393         queue.  Also we don't directly wake a task that was blocked on a queue\r
394         read, instead we return a flag to say whether a context switch is required\r
395         or not (i.e. has a task with a higher priority than us been woken by this\r
396         post). */\r
397         if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
398         {\r
399                 prvCopyQueueData( pxQueue, pvItemToQueue );\r
400 \r
401                 /* If the queue is locked we do not alter the event list.  This will\r
402                 be done when the queue is unlocked later. */\r
403                 if( pxQueue->xTxLock == queueUNLOCKED )\r
404                 {\r
405                         /* We only want to wake one task per ISR, so check that a task has\r
406                         not already been woken. */\r
407                         if( !xTaskPreviouslyWoken )             \r
408                         {\r
409                                 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
410                                 {\r
411                                         if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
412                                         {\r
413                                                 /* The task waiting has a higher priority so record that a\r
414                                                 context switch is required. */\r
415                                                 return pdTRUE;\r
416                                         }\r
417                                 }\r
418                         }\r
419                 }\r
420                 else\r
421                 {\r
422                         /* Increment the lock count so the task that unlocks the queue\r
423                         knows that data was posted while it was locked. */\r
424                         ++( pxQueue->xTxLock );\r
425                 }\r
426         }\r
427 \r
428         return xTaskPreviouslyWoken;\r
429 }\r
430 /*-----------------------------------------------------------*/\r
431 \r
432 signed portBASE_TYPE xQueueReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait )\r
433 {\r
434 signed portBASE_TYPE xReturn;\r
435 xTimeOutType xTimeOut;\r
436 \r
437         /* This function is very similar to xQueueSend().  See comments within\r
438         xQueueSend() for a more detailed explanation.\r
439 \r
440         Make sure other tasks do not access the queue. */\r
441         vTaskSuspendAll();\r
442 \r
443         /* Capture the current time status for future reference. */\r
444         vTaskSetTimeOutState( &xTimeOut );\r
445 \r
446         /* Make sure interrupts do not access the queue. */\r
447         prvLockQueue( pxQueue );\r
448 \r
449         do\r
450         {\r
451                 /* If there are no messages in the queue we may have to block. */\r
452                 if( prvIsQueueEmpty( pxQueue ) )\r
453                 {\r
454                         /* There are no messages in the queue, do we want to block or just\r
455                         leave with nothing? */                  \r
456                         if( xTicksToWait > ( portTickType ) 0 )\r
457                         {\r
458                                 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );\r
459                                 taskENTER_CRITICAL();\r
460                                 {\r
461                                         prvUnlockQueue( pxQueue );\r
462                                         if( !xTaskResumeAll() )\r
463                                         {\r
464                                                 taskYIELD();\r
465                                         }\r
466         \r
467                                         vTaskSuspendAll();\r
468                                         prvLockQueue( pxQueue );\r
469                                 }\r
470                                 taskEXIT_CRITICAL();\r
471                         }\r
472                 }\r
473         \r
474                 taskENTER_CRITICAL();\r
475                 {\r
476                         if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
477                         {\r
478                                 pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
479                                 if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
480                                 {\r
481                                         pxQueue->pcReadFrom = pxQueue->pcHead;\r
482                                 }\r
483                                 --( pxQueue->uxMessagesWaiting );\r
484                                 memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
485         \r
486                                 /* Increment the lock count so prvUnlockQueue knows to check for\r
487                                 tasks waiting for space to become available on the queue. */\r
488                                 ++( pxQueue->xRxLock );\r
489                                 xReturn = pdPASS;\r
490                         }\r
491                         else\r
492                         {\r
493                                 xReturn = errQUEUE_EMPTY;\r
494                         }\r
495                 }\r
496                 taskEXIT_CRITICAL();\r
497 \r
498                 if( xReturn == errQUEUE_EMPTY )\r
499                 {\r
500                         if( xTicksToWait > 0 )\r
501                         {\r
502                                 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
503                                 {\r
504                                         xReturn = queueERRONEOUS_UNBLOCK;\r
505                                 }\r
506                         }\r
507                 }\r
508         } while( xReturn == queueERRONEOUS_UNBLOCK );\r
509 \r
510         /* We no longer require exclusive access to the queue. */\r
511         prvUnlockQueue( pxQueue );\r
512         xTaskResumeAll();\r
513 \r
514         return xReturn;\r
515 }\r
516 /*-----------------------------------------------------------*/\r
517 \r
518 signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken )\r
519 {\r
520 signed portBASE_TYPE xReturn;\r
521 \r
522         /* We cannot block from an ISR, so check there is data available. */\r
523         if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
524         {\r
525                 /* Copy the data from the queue. */\r
526                 pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
527                 if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
528                 {\r
529                         pxQueue->pcReadFrom = pxQueue->pcHead;\r
530                 }\r
531                 --( pxQueue->uxMessagesWaiting );\r
532                 memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
533 \r
534                 /* If the queue is locked we will not modify the event list.  Instead\r
535                 we update the lock count so the task that unlocks the queue will know\r
536                 that an ISR has removed data while the queue was locked. */\r
537                 if( pxQueue->xRxLock == queueUNLOCKED )\r
538                 {\r
539                         /* We only want to wake one task per ISR, so check that a task has\r
540                         not already been woken. */\r
541                         if( !( *pxTaskWoken ) )\r
542                         {\r
543                                 if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )\r
544                                 {\r
545                                         if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
546                                         {\r
547                                                 /* The task waiting has a higher priority than us so\r
548                                                 force a context switch. */\r
549                                                 *pxTaskWoken = pdTRUE;\r
550                                         }\r
551                                 }\r
552                         }\r
553                 }\r
554                 else\r
555                 {\r
556                         /* Increment the lock count so the task that unlocks the queue\r
557                         knows that data was removed while it was locked. */\r
558                         ++( pxQueue->xRxLock );\r
559                 }\r
560 \r
561                 xReturn = pdPASS;\r
562         }\r
563         else\r
564         {\r
565                 xReturn = pdFAIL;\r
566         }\r
567 \r
568         return xReturn;\r
569 }\r
570 /*-----------------------------------------------------------*/\r
571 \r
572 unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle pxQueue )\r
573 {\r
574 unsigned portBASE_TYPE uxReturn;\r
575 \r
576         taskENTER_CRITICAL();\r
577                 uxReturn = pxQueue->uxMessagesWaiting;\r
578         taskEXIT_CRITICAL();\r
579 \r
580         return uxReturn;\r
581 }\r
582 /*-----------------------------------------------------------*/\r
583 \r
584 void vQueueDelete( xQueueHandle pxQueue )\r
585 {\r
586         vPortFree( pxQueue->pcHead );\r
587         vPortFree( pxQueue );\r
588 }\r
589 /*-----------------------------------------------------------*/\r
590 \r
591 static void prvUnlockQueue( xQueueHandle pxQueue )\r
592 {\r
593         /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */\r
594 \r
595         /* The lock counts contains the number of extra data items placed or\r
596         removed from the queue while the queue was locked.  When a queue is\r
597         locked items can be added or removed, but the event lists cannot be\r
598         updated. */\r
599         taskENTER_CRITICAL();\r
600         {\r
601                 --( pxQueue->xTxLock );\r
602 \r
603                 /* See if data was added to the queue while it was locked. */\r
604                 if( pxQueue->xTxLock > queueUNLOCKED )\r
605                 {\r
606                         pxQueue->xTxLock = queueUNLOCKED;\r
607 \r
608                         /* Data was posted while the queue was locked.  Are any tasks\r
609                         blocked waiting for data to become available? */\r
610                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
611                         {\r
612                                 /* Tasks that are removed from the event list will get added to\r
613                                 the pending ready list as the scheduler is still suspended. */\r
614                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
615                                 {\r
616                                         /* The task waiting has a higher priority so record that a\r
617                                         context switch is required. */\r
618                                         vTaskMissedYield();\r
619                                 }\r
620                         }                       \r
621                 }\r
622         }\r
623         taskEXIT_CRITICAL();\r
624 \r
625         /* Do the same for the Rx lock. */\r
626         taskENTER_CRITICAL();\r
627         {\r
628                 --( pxQueue->xRxLock );\r
629 \r
630                 if( pxQueue->xRxLock > queueUNLOCKED )\r
631                 {\r
632                         pxQueue->xRxLock = queueUNLOCKED;\r
633 \r
634                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )\r
635                         {\r
636                                 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
637                                 {\r
638                                         vTaskMissedYield();\r
639                                 }\r
640                         }                       \r
641                 }\r
642         }\r
643         taskEXIT_CRITICAL();\r
644 }\r
645 /*-----------------------------------------------------------*/\r
646 \r
647 static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue )\r
648 {\r
649 signed portBASE_TYPE xReturn;\r
650 \r
651         taskENTER_CRITICAL();\r
652                 xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );\r
653         taskEXIT_CRITICAL();\r
654 \r
655         return xReturn;\r
656 }\r
657 /*-----------------------------------------------------------*/\r
658 \r
659 static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue )\r
660 {\r
661 signed portBASE_TYPE xReturn;\r
662 \r
663         taskENTER_CRITICAL();\r
664                 xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );\r
665         taskEXIT_CRITICAL();\r
666 \r
667         return xReturn;\r
668 }\r
669 /*-----------------------------------------------------------*/\r
670 \r
671 #if configUSE_CO_ROUTINES == 1\r
672 signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )\r
673 {\r
674 signed portBASE_TYPE xReturn;\r
675                 \r
676         /* If the queue is already full we may have to block.  A critical section\r
677         is required to prevent an interrupt removing something from the queue \r
678         between the check to see if the queue is full and blocking on the queue. */\r
679         portDISABLE_INTERRUPTS();\r
680         {\r
681                 if( prvIsQueueFull( pxQueue ) )\r
682                 {\r
683                         /* The queue is full - do we want to block or just leave without\r
684                         posting? */\r
685                         if( xTicksToWait > ( portTickType ) 0 )\r
686                         {\r
687                                 /* As this is called from a coroutine we cannot block directly, but\r
688                                 return indicating that we need to block. */\r
689                                 vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToSend ) );                          \r
690                                 portENABLE_INTERRUPTS();\r
691                                 return errQUEUE_BLOCKED;\r
692                         }\r
693                         else\r
694                         {\r
695                                 portENABLE_INTERRUPTS();\r
696                                 return errQUEUE_FULL;\r
697                         }\r
698                 }\r
699         }\r
700         portENABLE_INTERRUPTS();\r
701                 \r
702         portNOP();\r
703 \r
704         portDISABLE_INTERRUPTS();\r
705         {\r
706                 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
707                 {\r
708                         /* There is room in the queue, copy the data into the queue. */                 \r
709                         prvCopyQueueData( pxQueue, pvItemToQueue );             \r
710                         xReturn = pdPASS;\r
711 \r
712                         /* Were any co-routines waiting for data to become available? */\r
713                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
714                         {\r
715                                 /* In this instance the co-routine could be placed directly \r
716                                 into the ready list as we are within a critical section.  \r
717                                 Instead the same pending ready list mechansim is used as if\r
718                                 the event were caused from within an interrupt. */\r
719                                 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
720                                 {\r
721                                         /* The co-routine waiting has a higher priority so record \r
722                                         that a yield might be appropriate. */\r
723                                         xReturn = errQUEUE_YIELD;\r
724                                 }\r
725                         }\r
726                 }\r
727                 else\r
728                 {\r
729                         xReturn = errQUEUE_FULL;\r
730                 }\r
731         }\r
732         portENABLE_INTERRUPTS();\r
733 \r
734         return xReturn;\r
735 }\r
736 #endif\r
737 /*-----------------------------------------------------------*/\r
738 \r
739 #if configUSE_CO_ROUTINES == 1\r
740 signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait )\r
741 {\r
742 signed portBASE_TYPE xReturn;\r
743 \r
744         /* If the queue is already empty we may have to block.  A critical section\r
745         is required to prevent an interrupt adding something to the queue \r
746         between the check to see if the queue is empty and blocking on the queue. */\r
747         portDISABLE_INTERRUPTS();\r
748         {\r
749                 if( prvIsQueueEmpty( pxQueue ) )\r
750                 {\r
751                         /* There are no messages in the queue, do we want to block or just\r
752                         leave with nothing? */                  \r
753                         if( xTicksToWait > ( portTickType ) 0 )\r
754                         {\r
755                                 /* As this is a co-routine we cannot block directly, but return\r
756                                 indicating that we need to block. */\r
757                                 vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToReceive ) );\r
758                                 portENABLE_INTERRUPTS();\r
759                                 return errQUEUE_BLOCKED;\r
760                         }\r
761                         else\r
762                         {\r
763                                 portENABLE_INTERRUPTS();\r
764                                 return errQUEUE_FULL;\r
765                         }\r
766                 }\r
767         }\r
768         portENABLE_INTERRUPTS();\r
769 \r
770         portNOP();\r
771 \r
772         portDISABLE_INTERRUPTS();\r
773         {\r
774                 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
775                 {\r
776                         /* Data is available from the queue. */\r
777                         pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
778                         if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
779                         {\r
780                                 pxQueue->pcReadFrom = pxQueue->pcHead;\r
781                         }\r
782                         --( pxQueue->uxMessagesWaiting );\r
783                         memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
784 \r
785                         xReturn = pdPASS;\r
786 \r
787                         /* Were any co-routines waiting for space to become available? */\r
788                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )\r
789                         {\r
790                                 /* In this instance the co-routine could be placed directly \r
791                                 into the ready list as we are within a critical section.  \r
792                                 Instead the same pending ready list mechansim is used as if\r
793                                 the event were caused from within an interrupt. */\r
794                                 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
795                                 {\r
796                                         xReturn = errQUEUE_YIELD;\r
797                                 }\r
798                         }       \r
799                 }\r
800                 else\r
801                 {\r
802                         xReturn = pdFAIL;\r
803                 }\r
804         }\r
805         portENABLE_INTERRUPTS();\r
806 \r
807         return xReturn;\r
808 }\r
809 #endif\r
810 /*-----------------------------------------------------------*/\r
811 \r
812 \r
813 \r
814 #if configUSE_CO_ROUTINES == 1\r
815 signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken )\r
816 {\r
817         /* Cannot block within an ISR so if there is no space on the queue then\r
818         exit without doing anything. */\r
819         if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
820         {\r
821                 prvCopyQueueData( pxQueue, pvItemToQueue );\r
822 \r
823                 /* We only want to wake one co-routine per ISR, so check that a \r
824                 co-routine has not already been woken. */\r
825                 if( !xCoRoutinePreviouslyWoken )                \r
826                 {\r
827                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
828                         {\r
829                                 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
830                                 {\r
831                                         return pdTRUE;\r
832                                 }\r
833                         }\r
834                 }\r
835         }\r
836 \r
837         return xCoRoutinePreviouslyWoken;\r
838 }\r
839 #endif\r
840 /*-----------------------------------------------------------*/\r
841 \r
842 #if configUSE_CO_ROUTINES == 1\r
843 signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxCoRoutineWoken )\r
844 {\r
845 signed portBASE_TYPE xReturn;\r
846 \r
847         /* We cannot block from an ISR, so check there is data available. If\r
848         not then just leave without doing anything. */\r
849         if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
850         {\r
851                 /* Copy the data from the queue. */\r
852                 pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
853                 if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
854                 {\r
855                         pxQueue->pcReadFrom = pxQueue->pcHead;\r
856                 }\r
857                 --( pxQueue->uxMessagesWaiting );\r
858                 memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
859 \r
860                 if( !( *pxCoRoutineWoken ) )\r
861                 {\r
862                         if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )\r
863                         {\r
864                                 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
865                                 {\r
866                                         *pxCoRoutineWoken = pdTRUE;\r
867                                 }\r
868                         }\r
869                 }\r
870 \r
871                 xReturn = pdPASS;\r
872         }\r
873         else\r
874         {\r
875                 xReturn = pdFAIL;\r
876         }\r
877 \r
878         return xReturn;\r
879 }\r
880 #endif\r
881 /*-----------------------------------------------------------*/\r
882 \r