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