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

Subversion Repositories openfire2

[/] [openfire2/] [trunk/] [sw/] [freertos/] [queue.c] - Blame information for rev 6

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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