root/Examples_CP-JR_ARM7_LPC2368/FreeRTOS_Book/Source-Code-For-Examples/FreeRTOS_Source/queue.c

Revision 36, 48.6 kB (checked in by phil, 15 years ago)

added purchased FreeRTOS book

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