OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Source/] [queue.c] - Blame information for rev 609

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.