root/webserver/example/freeRTOS/Source/queue.c

Revision 14, 45.2 kB (checked in by phil, 15 years ago)

added unmodified FreeRTOS package V5.4.1 with only web srv demo source for LPC2368 for CrossWorks?

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