Project

General

Profile

Download (31.4 KB) Statistics
| Branch: | Tag: | Revision:
1
/*
2
	FreeRTOS.org V4.2.1 - 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
	Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
32
	with commercial development and support options.
33
	***************************************************************************
34
*/
35

    
36
/*
37
Changes from V1.01
38

    
39
	+ More use of 8bit data types.
40
	+ Function name prefixes changed where the data type returned has changed.
41

    
42
Changed from V2.0.0
43

    
44
	+ Added the queue locking mechanism and make more use of the scheduler
45
	  suspension feature to minimise the time interrupts have to be disabled
46
	  when accessing a queue.
47

    
48
Changed from V2.2.0
49

    
50
	+ Explicit use of 'signed' qualifier on portCHAR types added.
51

    
52
Changes from V3.0.0
53

    
54
	+ API changes as described on the FreeRTOS.org WEB site.
55

    
56
Changes from V3.2.3
57

    
58
	+ Added the queue functions that can be used from co-routines.
59

    
60
Changes from V4.0.5
61

    
62
	+ Added a loop within xQueueSend() and xQueueReceive() to prevent the
63
	  functions exiting when a block time remains and the function has
64
	  not completed.
65

    
66
Changes from V4.1.2:
67

    
68
	+ BUG FIX:  Removed the call to prvIsQueueEmpty from within xQueueCRReceive
69
	  as it exited with interrupts enabled.  Thanks Paul Katz.
70

    
71
Changes from V4.1.3:
72

    
73
	+ Modified xQueueSend() and xQueueReceive() to handle the (very unlikely) 
74
	case whereby a task unblocking due to a temporal event can remove/send an 
75
	item from/to a queue when a higher priority task is	still blocked on the 
76
	queue.  This modification is a result of the SafeRTOS testing.
77
*/
78

    
79
#include <stdlib.h>
80
#include <string.h>
81
#include "FreeRTOS.h"
82
#include "task.h"
83
#include "croutine.h"
84

    
85
/*-----------------------------------------------------------
86
 * PUBLIC LIST API documented in list.h
87
 *----------------------------------------------------------*/
88

    
89
/* Constants used with the cRxLock and cTxLock structure members. */
90
#define queueUNLOCKED	( ( signed portBASE_TYPE ) -1 )
91
#define queueERRONEOUS_UNBLOCK					( -1 )
92

    
93
/*
94
 * Definition of the queue used by the scheduler.
95
 * Items are queued by copy, not reference.
96
 */
97
typedef struct QueueDefinition
98
{
99
  signed portCHAR *pcHead;	/*< Points to the beginning of the queue storage area. */
100
  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. */
101

    
102
  signed portCHAR *pcWriteTo;	/*< Points to the free next place in the storage area. */
103
  signed portCHAR *pcReadFrom;	/*< Points to the last place that a queued item was read from. */
104

    
105
  xList xTasksWaitingToSend;	/*< List of tasks that are blocked waiting to post onto this queue.  Stored in priority order. */
106
  xList xTasksWaitingToReceive;	/*< List of tasks that are blocked waiting to read from this queue.  Stored in priority order. */
107

    
108
  unsigned portBASE_TYPE uxMessagesWaiting;	/*< The number of items currently in the queue. */
109
  unsigned portBASE_TYPE uxLength;	/*< The length of the queue defined as the number of items it will hold, not the number of bytes. */
110
  unsigned portBASE_TYPE uxItemSize;	/*< The size of each items that the queue will hold. */
111

    
112
  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. */
113
  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. */
114
} xQUEUE;
115
/*-----------------------------------------------------------*/
116

    
117
/*
118
 * Inside this file xQueueHandle is a pointer to a xQUEUE structure.
119
 * To keep the definition private the API header file defines it as a
120
 * pointer to void.
121
 */
122
typedef xQUEUE *xQueueHandle;
123

    
124
/*
125
 * Prototypes for public functions are included here so we don't have to
126
 * include the API header file (as it defines xQueueHandle differently).  These
127
 * functions are documented in the API header file.
128
 */
129
xQueueHandle xQueueCreate (unsigned portBASE_TYPE uxQueueLength,
130
			   unsigned portBASE_TYPE uxItemSize);
131
signed portBASE_TYPE xQueueSend (xQueueHandle xQueue,
132
				 const void *pvItemToQueue,
133
				 portTickType xTicksToWait);
134
unsigned portBASE_TYPE uxQueueMessagesWaiting (xQueueHandle pxQueue);
135
void vQueueDelete (xQueueHandle xQueue);
136
signed portBASE_TYPE xQueueSendFromISR (xQueueHandle pxQueue,
137
					const void *pvItemToQueue,
138
					signed portBASE_TYPE
139
					xTaskPreviouslyWoken);
140
signed portBASE_TYPE xQueueReceive (xQueueHandle pxQueue, void *pvBuffer,
141
				    portTickType xTicksToWait);
142
signed portBASE_TYPE xQueueReceiveFromISR (xQueueHandle pxQueue,
143
					   void *pvBuffer,
144
					   signed portBASE_TYPE *
145
					   pxTaskWoken);
146

    
147
#if configUSE_CO_ROUTINES == 1
148
signed portBASE_TYPE xQueueCRSendFromISR (xQueueHandle pxQueue,
149
					  const void *pvItemToQueue,
150
					  signed portBASE_TYPE
151
					  xCoRoutinePreviouslyWoken);
152
signed portBASE_TYPE xQueueCRReceiveFromISR (xQueueHandle pxQueue,
153
					     void *pvBuffer,
154
					     signed portBASE_TYPE *
155
					     pxTaskWoken);
156
signed portBASE_TYPE xQueueCRSend (xQueueHandle pxQueue,
157
				   const void *pvItemToQueue,
158
				   portTickType xTicksToWait);
159
signed portBASE_TYPE xQueueCRReceive (xQueueHandle pxQueue, void *pvBuffer,
160
				      portTickType xTicksToWait);
161
#endif
162

    
163
/*
164
 * Unlocks a queue locked by a call to prvLockQueue.  Locking a queue does not
165
 * prevent an ISR from adding or removing items to the queue, but does prevent
166
 * an ISR from removing tasks from the queue event lists.  If an ISR finds a
167
 * queue is locked it will instead increment the appropriate queue lock count
168
 * to indicate that a task may require unblocking.  When the queue in unlocked
169
 * these lock counts are inspected, and the appropriate action taken.
170
 */
171
static void prvUnlockQueue (xQueueHandle pxQueue);
172

    
173
/*
174
 * Uses a critical section to determine if there is any data in a queue.
175
 *
176
 * @return pdTRUE if the queue contains no items, otherwise pdFALSE.
177
 */
178
static signed portBASE_TYPE prvIsQueueEmpty (const xQueueHandle pxQueue);
179

    
180
/*
181
 * Uses a critical section to determine if there is any space in a queue.
182
 *
183
 * @return pdTRUE if there is no space, otherwise pdFALSE;
184
 */
185
static signed portBASE_TYPE prvIsQueueFull (const xQueueHandle pxQueue);
186

    
187
/*
188
 * Macro that copies an item into the queue.  This is done by copying the item
189
 * byte for byte, not by reference.  Updates the queue state to ensure it's
190
 * integrity after the copy.
191
 */
192
#define prvCopyQueueData( pxQueue, pvItemToQueue )												\
193
{																								\
194
	memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );	\
195
	++( pxQueue->uxMessagesWaiting );															\
196
	pxQueue->pcWriteTo += pxQueue->uxItemSize;													\
197
	if( pxQueue->pcWriteTo >= pxQueue->pcTail )													\
198
	{																							\
199
		pxQueue->pcWriteTo = pxQueue->pcHead;													\
200
	}																							\
201
}
202
/*-----------------------------------------------------------*/
203

    
204
/*
205
 * Macro to mark a queue as locked.  Locking a queue prevents an ISR from
206
 * accessing the queue event lists.
207
 */
208
#define prvLockQueue( pxQueue )			\
209
{										\
210
	taskENTER_CRITICAL();				\
211
		++( pxQueue->xRxLock );			\
212
		++( pxQueue->xTxLock );			\
213
	taskEXIT_CRITICAL();				\
214
}
215
/*-----------------------------------------------------------*/
216

    
217

    
218
/*-----------------------------------------------------------
219
 * PUBLIC QUEUE MANAGEMENT API documented in queue.h
220
 *----------------------------------------------------------*/
221

    
222
xQueueHandle
223
xQueueCreate (unsigned portBASE_TYPE uxQueueLength,
224
	      unsigned portBASE_TYPE uxItemSize)
225
{
226
  xQUEUE *pxNewQueue;
227
  size_t xQueueSizeInBytes;
228

    
229
  /* Allocate the new queue structure. */
230
  if (uxQueueLength > (unsigned portBASE_TYPE) 0)
231
    {
232
      pxNewQueue = (xQUEUE *) pvPortMalloc (sizeof (xQUEUE));
233
      if (pxNewQueue != NULL)
234
	{
235
	  /* Create the list of pointers to queue items.  The queue is one byte
236
	     longer than asked for to make wrap checking easier/faster. */
237
	  xQueueSizeInBytes =
238
	    (size_t) (uxQueueLength * uxItemSize) + (size_t) 1;
239

    
240
	  pxNewQueue->pcHead =
241
	    (signed portCHAR *) pvPortMalloc (xQueueSizeInBytes);
242
	  if (pxNewQueue->pcHead != NULL)
243
	    {
244
	      /* Initialise the queue members as described above where the
245
	         queue type is defined. */
246
	      pxNewQueue->pcTail =
247
		pxNewQueue->pcHead + (uxQueueLength * uxItemSize);
248
	      pxNewQueue->uxMessagesWaiting = 0;
249
	      pxNewQueue->pcWriteTo = pxNewQueue->pcHead;
250
	      pxNewQueue->pcReadFrom =
251
		pxNewQueue->pcHead + ((uxQueueLength - 1) * uxItemSize);
252
	      pxNewQueue->uxLength = uxQueueLength;
253
	      pxNewQueue->uxItemSize = uxItemSize;
254
	      pxNewQueue->xRxLock = queueUNLOCKED;
255
	      pxNewQueue->xTxLock = queueUNLOCKED;
256

    
257
	      /* Likewise ensure the event queues start with the correct state. */
258
	      vListInitialise (&(pxNewQueue->xTasksWaitingToSend));
259
	      vListInitialise (&(pxNewQueue->xTasksWaitingToReceive));
260

    
261
	      return pxNewQueue;
262
	    }
263
	  else
264
	    {
265
	      vPortFree (pxNewQueue);
266
	    }
267
	}
268
    }
269

    
270
  /* Will only reach here if we could not allocate enough memory or no memory
271
     was required. */
272
  return NULL;
273
}
274

    
275
/*-----------------------------------------------------------*/
276

    
277
signed portBASE_TYPE
278
xQueueSend (xQueueHandle pxQueue, const void *pvItemToQueue,
279
	    portTickType xTicksToWait)
280
{
281
  signed portBASE_TYPE xReturn = pdPASS;
282
  xTimeOutType xTimeOut;
283

    
284
  /* Make sure other tasks do not access the queue. */
285
  vTaskSuspendAll ();
286

    
287
  /* Capture the current time status for future reference. */
288
  vTaskSetTimeOutState (&xTimeOut);
289

    
290
  /* It is important that this is the only thread/ISR that modifies the
291
     ready or delayed lists until xTaskResumeAll() is called.  Places where
292
     the ready/delayed lists are modified include:
293

    
294
     + vTaskDelay() -  Nothing can call vTaskDelay as the scheduler is
295
     suspended, vTaskDelay() cannot be called from an ISR.
296
     + vTaskPrioritySet() - Has a critical section around the access.
297
     + vTaskSwitchContext() - This will not get executed while the scheduler
298
     is suspended.
299
     + prvCheckDelayedTasks() - This will not get executed while the
300
     scheduler is suspended.
301
     + xTaskCreate() - Has a critical section around the access.
302
     + vTaskResume() - Has a critical section around the access.
303
     + xTaskResumeAll() - Has a critical section around the access.
304
     + xTaskRemoveFromEventList - Checks to see if the scheduler is
305
     suspended.  If so then the TCB being removed from the event is
306
     removed from the event and added to the xPendingReadyList.
307
   */
308

    
309
  /* Make sure interrupts do not access the queue event list. */
310
  prvLockQueue (pxQueue);
311

    
312
  /* It is important that interrupts to not access the event list of the
313
     queue being modified here.  Places where the event list is modified
314
     include:
315

    
316
     + xQueueSendFromISR().  This checks the lock on the queue to see if
317
     it has access.  If the queue is locked then the Tx lock count is
318
     incremented to signify that a task waiting for data can be made ready
319
     once the queue lock is removed.  If the queue is not locked then
320
     a task can be moved from the event list, but will not be removed
321
     from the delayed list or placed in the ready list until the scheduler
322
     is unlocked.
323

    
324
     + xQueueReceiveFromISR().  As per xQueueSendFromISR().
325
   */
326

    
327
  /* If the queue is already full we may have to block. */
328
  do
329
    {
330
      if (prvIsQueueFull (pxQueue))
331
	{
332
	  /* The queue is full - do we want to block or just leave without
333
	     posting? */
334
	  if (xTicksToWait > (portTickType) 0)
335
	    {
336
	      /* We are going to place ourselves on the xTasksWaitingToSend event
337
	         list, and will get woken should the delay expire, or space become
338
	         available on the queue.
339

    
340
	         As detailed above we do not require mutual exclusion on the event
341
	         list as nothing else can modify it or the ready lists while we
342
	         have the scheduler suspended and queue locked.
343

    
344
	         It is possible that an ISR has removed data from the queue since we
345
	         checked if any was available.  If this is the case then the data
346
	         will have been copied from the queue, and the queue variables
347
	         updated, but the event list will not yet have been checked to see if
348
	         anything is waiting as the queue is locked. */
349
	      vTaskPlaceOnEventList (&(pxQueue->xTasksWaitingToSend),
350
				     xTicksToWait);
351

    
352
	      /* Force a context switch now as we are blocked.  We can do
353
	         this from within a critical section as the task we are
354
	         switching to has its own context.  When we return here (i.e. we
355
	         unblock) we will leave the critical section as normal.
356

    
357
	         It is possible that an ISR has caused an event on an unrelated and
358
	         unlocked queue.  If this was the case then the event list for that
359
	         queue will have been updated but the ready lists left unchanged -
360
	         instead the readied task will have been added to the pending ready
361
	         list. */
362
	      taskENTER_CRITICAL ();
363
	      {
364
		/* We can safely unlock the queue and scheduler here as
365
		   interrupts are disabled.  We must not yield with anything
366
		   locked, but we can yield from within a critical section.
367

    
368
		   Tasks that have been placed on the pending ready list cannot
369
		   be tasks that are waiting for events on this queue.  See
370
		   in comment xTaskRemoveFromEventList(). */
371
		prvUnlockQueue (pxQueue);
372

    
373
		/* Resuming the scheduler may cause a yield.  If so then there
374
		   is no point yielding again here. */
375
		if (!xTaskResumeAll ())
376
		  {
377
		    taskYIELD ();
378
		  }
379

    
380
		/* We want to check to see if the queue is still full
381
		   before leaving the critical section.  This is to prevent
382
		   this task placing an item into the queue due to an
383
		   interrupt making space on the queue between critical
384
		   sections (when there might be a higher priority task
385
		   blocked on the queue that cannot run yet because the
386
		   scheduler gets suspended). */
387
		if (pxQueue->uxMessagesWaiting == pxQueue->uxLength)
388
		  {
389
		    /* We unblocked but there is no space in the queue,
390
		       we probably timed out. */
391
		    xReturn = errQUEUE_FULL;
392
		  }
393

    
394
		/* Before leaving the critical section we have to ensure
395
		   exclusive access again. */
396
		vTaskSuspendAll ();
397
		prvLockQueue (pxQueue);
398
	      }
399
	      taskEXIT_CRITICAL ();
400
	    }
401
	}
402

    
403
      /* If xReturn is errQUEUE_FULL then we unblocked when the queue
404
         was still full.  Don't check it again now as it is possible that
405
         an interrupt has removed an item from the queue since we left the
406
         critical section and we don't want to write to the queue in case
407
         there is a task of higher priority blocked waiting for space to
408
         be available on the queue.  If this is the case the higher priority
409
         task will execute when the scheduler is unsupended. */
410
      if (xReturn != errQUEUE_FULL)
411
	{
412
	  /* When we are here it is possible that we unblocked as space became
413
	     available on the queue.  It is also possible that an ISR posted to the
414
	     queue since we left the critical section, so it may be that again there
415
	     is no space.  This would only happen if a task and ISR post onto the
416
	     same queue. */
417
	  taskENTER_CRITICAL ();
418
	  {
419
	    if (pxQueue->uxMessagesWaiting < pxQueue->uxLength)
420
	      {
421
		/* There is room in the queue, copy the data into the queue. */
422
		prvCopyQueueData (pxQueue, pvItemToQueue);
423
		xReturn = pdPASS;
424

    
425
		/* Update the TxLock count so prvUnlockQueue knows to check for
426
		   tasks waiting for data to become available in the queue. */
427
		++(pxQueue->xTxLock);
428
	      }
429
	    else
430
	      {
431
		xReturn = errQUEUE_FULL;
432
	      }
433
	  }
434
	  taskEXIT_CRITICAL ();
435
	}
436

    
437
      if (xReturn == errQUEUE_FULL)
438
	{
439
	  if (xTicksToWait > 0)
440
	    {
441
	      if (xTaskCheckForTimeOut (&xTimeOut, &xTicksToWait) == pdFALSE)
442
		{
443
		  xReturn = queueERRONEOUS_UNBLOCK;
444
		}
445
	    }
446
	}
447
    }
448
  while (xReturn == queueERRONEOUS_UNBLOCK);
449

    
450
  prvUnlockQueue (pxQueue);
451
  xTaskResumeAll ();
452

    
453
  return xReturn;
454
}
455

    
456
/*-----------------------------------------------------------*/
457

    
458
signed portBASE_TYPE
459
xQueueSendFromISR (xQueueHandle pxQueue, const void *pvItemToQueue,
460
		   signed portBASE_TYPE xTaskPreviouslyWoken)
461
{
462
  /* Similar to xQueueSend, except we don't block if there is no room in the
463
     queue.  Also we don't directly wake a task that was blocked on a queue
464
     read, instead we return a flag to say whether a context switch is required
465
     or not (i.e. has a task with a higher priority than us been woken by this
466
     post). */
467
  if (pxQueue->uxMessagesWaiting < pxQueue->uxLength)
468
    {
469
      prvCopyQueueData (pxQueue, pvItemToQueue);
470

    
471
      /* If the queue is locked we do not alter the event list.  This will
472
         be done when the queue is unlocked later. */
473
      if (pxQueue->xTxLock == queueUNLOCKED)
474
	{
475
	  /* We only want to wake one task per ISR, so check that a task has
476
	     not already been woken. */
477
	  if (!xTaskPreviouslyWoken)
478
	    {
479
	      if (!listLIST_IS_EMPTY (&(pxQueue->xTasksWaitingToReceive)))
480
		{
481
		  if (xTaskRemoveFromEventList
482
		      (&(pxQueue->xTasksWaitingToReceive)) != pdFALSE)
483
		    {
484
		      /* The task waiting has a higher priority so record that a
485
		         context      switch is required. */
486
		      return pdTRUE;
487
		    }
488
		}
489
	    }
490
	}
491
      else
492
	{
493
	  /* Increment the lock count so the task that unlocks the queue
494
	     knows that data was posted while it was locked. */
495
	  ++(pxQueue->xTxLock);
496
	}
497
    }
498

    
499
  return xTaskPreviouslyWoken;
500
}
501

    
502
/*-----------------------------------------------------------*/
503

    
504
signed portBASE_TYPE
505
xQueueReceive (xQueueHandle pxQueue, void *pvBuffer,
506
	       portTickType xTicksToWait)
507
{
508
  signed portBASE_TYPE xReturn = pdTRUE;
509
  xTimeOutType xTimeOut;
510

    
511
  /* This function is very similar to xQueueSend().  See comments within
512
     xQueueSend() for a more detailed explanation.
513

    
514
     Make sure other tasks do not access the queue. */
515
  vTaskSuspendAll ();
516

    
517
  /* Capture the current time status for future reference. */
518
  vTaskSetTimeOutState (&xTimeOut);
519

    
520
  /* Make sure interrupts do not access the queue. */
521
  prvLockQueue (pxQueue);
522

    
523
  do
524
    {
525
      /* If there are no messages in the queue we may have to block. */
526
      if (prvIsQueueEmpty (pxQueue))
527
	{
528
	  /* There are no messages in the queue, do we want to block or just
529
	     leave with nothing? */
530
	  if (xTicksToWait > (portTickType) 0)
531
	    {
532
	      vTaskPlaceOnEventList (&(pxQueue->xTasksWaitingToReceive),
533
				     xTicksToWait);
534
	      taskENTER_CRITICAL ();
535
	      {
536
		prvUnlockQueue (pxQueue);
537
		if (!xTaskResumeAll ())
538
		  {
539
		    taskYIELD ();
540
		  }
541

    
542
		if (pxQueue->uxMessagesWaiting == (unsigned portBASE_TYPE) 0)
543
		  {
544
		    /* We unblocked but the queue is empty.  We probably
545
		       timed out. */
546
		    xReturn = errQUEUE_EMPTY;
547
		  }
548

    
549
		vTaskSuspendAll ();
550
		prvLockQueue (pxQueue);
551
	      }
552
	      taskEXIT_CRITICAL ();
553
	    }
554
	}
555

    
556
      if (xReturn != errQUEUE_EMPTY)
557
	{
558
	  taskENTER_CRITICAL ();
559
	  {
560
	    if (pxQueue->uxMessagesWaiting > (unsigned portBASE_TYPE) 0)
561
	      {
562
		pxQueue->pcReadFrom += pxQueue->uxItemSize;
563
		if (pxQueue->pcReadFrom >= pxQueue->pcTail)
564
		  {
565
		    pxQueue->pcReadFrom = pxQueue->pcHead;
566
		  }
567
		--(pxQueue->uxMessagesWaiting);
568
		memcpy ((void *) pvBuffer, (void *) pxQueue->pcReadFrom,
569
			(unsigned) pxQueue->uxItemSize);
570

    
571
		/* Increment the lock count so prvUnlockQueue knows to check for
572
		   tasks waiting for space to become available on the queue. */
573
		++(pxQueue->xRxLock);
574
		xReturn = pdPASS;
575
	      }
576
	    else
577
	      {
578
		xReturn = errQUEUE_EMPTY;
579
	      }
580
	  }
581
	  taskEXIT_CRITICAL ();
582
	}
583

    
584
      if (xReturn == errQUEUE_EMPTY)
585
	{
586
	  if (xTicksToWait > 0)
587
	    {
588
	      if (xTaskCheckForTimeOut (&xTimeOut, &xTicksToWait) == pdFALSE)
589
		{
590
		  xReturn = queueERRONEOUS_UNBLOCK;
591
		}
592
	    }
593
	}
594
    }
595
  while (xReturn == queueERRONEOUS_UNBLOCK);
596

    
597
  /* We no longer require exclusive access to the queue. */
598
  prvUnlockQueue (pxQueue);
599
  xTaskResumeAll ();
600

    
601
  return xReturn;
602
}
603

    
604
/*-----------------------------------------------------------*/
605

    
606
signed portBASE_TYPE
607
xQueueReceiveFromISR (xQueueHandle pxQueue, void *pvBuffer,
608
		      signed portBASE_TYPE * pxTaskWoken)
609
{
610
  signed portBASE_TYPE xReturn;
611

    
612
  /* We cannot block from an ISR, so check there is data available. */
613
  if (pxQueue->uxMessagesWaiting > (unsigned portBASE_TYPE) 0)
614
    {
615
      /* Copy the data from the queue. */
616
      pxQueue->pcReadFrom += pxQueue->uxItemSize;
617
      if (pxQueue->pcReadFrom >= pxQueue->pcTail)
618
	{
619
	  pxQueue->pcReadFrom = pxQueue->pcHead;
620
	}
621
      --(pxQueue->uxMessagesWaiting);
622
      memcpy ((void *) pvBuffer, (void *) pxQueue->pcReadFrom,
623
	      (unsigned) pxQueue->uxItemSize);
624

    
625
      /* If the queue is locked we will not modify the event list.  Instead
626
         we update the lock count so the task that unlocks the queue will know
627
         that an ISR has removed data while the queue was locked. */
628
      if (pxQueue->xRxLock == queueUNLOCKED)
629
	{
630
	  /* We only want to wake one task per ISR, so check that a task has
631
	     not already been woken. */
632
	  if (!(*pxTaskWoken))
633
	    {
634
	      if (!listLIST_IS_EMPTY (&(pxQueue->xTasksWaitingToSend)))
635
		{
636
		  if (xTaskRemoveFromEventList
637
		      (&(pxQueue->xTasksWaitingToSend)) != pdFALSE)
638
		    {
639
		      /* The task waiting has a higher priority than us so
640
		         force a context switch. */
641
		      *pxTaskWoken = pdTRUE;
642
		    }
643
		}
644
	    }
645
	}
646
      else
647
	{
648
	  /* Increment the lock count so the task that unlocks the queue
649
	     knows that data was removed while it was locked. */
650
	  ++(pxQueue->xRxLock);
651
	}
652

    
653
      xReturn = pdPASS;
654
    }
655
  else
656
    {
657
      xReturn = pdFAIL;
658
    }
659

    
660
  return xReturn;
661
}
662

    
663
/*-----------------------------------------------------------*/
664

    
665
unsigned portBASE_TYPE
666
uxQueueMessagesWaiting (xQueueHandle pxQueue)
667
{
668
  unsigned portBASE_TYPE uxReturn;
669

    
670
  taskENTER_CRITICAL ();
671
  uxReturn = pxQueue->uxMessagesWaiting;
672
  taskEXIT_CRITICAL ();
673

    
674
  return uxReturn;
675
}
676

    
677
/*-----------------------------------------------------------*/
678

    
679
void
680
vQueueDelete (xQueueHandle pxQueue)
681
{
682
  vPortFree (pxQueue->pcHead);
683
  vPortFree (pxQueue);
684
}
685

    
686
/*-----------------------------------------------------------*/
687

    
688
static void
689
prvUnlockQueue (xQueueHandle pxQueue)
690
{
691
  /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */
692

    
693
  /* The lock counts contains the number of extra data items placed or
694
     removed from the queue while the queue was locked.  When a queue is
695
     locked items can be added or removed, but the event lists cannot be
696
     updated. */
697
  taskENTER_CRITICAL ();
698
  {
699
    --(pxQueue->xTxLock);
700

    
701
    /* See if data was added to the queue while it was locked. */
702
    if (pxQueue->xTxLock > queueUNLOCKED)
703
      {
704
	pxQueue->xTxLock = queueUNLOCKED;
705

    
706
	/* Data was posted while the queue was locked.  Are any tasks
707
	   blocked waiting for data to become available? */
708
	if (!listLIST_IS_EMPTY (&(pxQueue->xTasksWaitingToReceive)))
709
	  {
710
	    /* Tasks that are removed from the event list will get added to
711
	       the pending ready list as the scheduler is still suspended. */
712
	    if (xTaskRemoveFromEventList (&(pxQueue->xTasksWaitingToReceive))
713
		!= pdFALSE)
714
	      {
715
		/* The task waiting has a higher priority so record that a
716
		   context      switch is required. */
717
		vTaskMissedYield ();
718
	      }
719
	  }
720
      }
721
  }
722
  taskEXIT_CRITICAL ();
723

    
724
  /* Do the same for the Rx lock. */
725
  taskENTER_CRITICAL ();
726
  {
727
    --(pxQueue->xRxLock);
728

    
729
    if (pxQueue->xRxLock > queueUNLOCKED)
730
      {
731
	pxQueue->xRxLock = queueUNLOCKED;
732

    
733
	if (!listLIST_IS_EMPTY (&(pxQueue->xTasksWaitingToSend)))
734
	  {
735
	    if (xTaskRemoveFromEventList (&(pxQueue->xTasksWaitingToSend)) !=
736
		pdFALSE)
737
	      {
738
		vTaskMissedYield ();
739
	      }
740
	  }
741
      }
742
  }
743
  taskEXIT_CRITICAL ();
744
}
745

    
746
/*-----------------------------------------------------------*/
747

    
748
static signed portBASE_TYPE
749
prvIsQueueEmpty (const xQueueHandle pxQueue)
750
{
751
  signed portBASE_TYPE xReturn;
752

    
753
  taskENTER_CRITICAL ();
754
  xReturn = (pxQueue->uxMessagesWaiting == (unsigned portBASE_TYPE) 0);
755
  taskEXIT_CRITICAL ();
756

    
757
  return xReturn;
758
}
759

    
760
/*-----------------------------------------------------------*/
761

    
762
static signed portBASE_TYPE
763
prvIsQueueFull (const xQueueHandle pxQueue)
764
{
765
  signed portBASE_TYPE xReturn;
766

    
767
  taskENTER_CRITICAL ();
768
  xReturn = (pxQueue->uxMessagesWaiting == pxQueue->uxLength);
769
  taskEXIT_CRITICAL ();
770

    
771
  return xReturn;
772
}
773

    
774
/*-----------------------------------------------------------*/
775

    
776
#if configUSE_CO_ROUTINES == 1
777
signed portBASE_TYPE
778
xQueueCRSend (xQueueHandle pxQueue, const void *pvItemToQueue,
779
	      portTickType xTicksToWait)
780
{
781
  signed portBASE_TYPE xReturn;
782

    
783
  /* If the queue is already full we may have to block.  A critical section
784
     is required to prevent an interrupt removing something from the queue 
785
     between the check to see if the queue is full and blocking on the queue. */
786
  portDISABLE_INTERRUPTS ();
787
  {
788
    if (prvIsQueueFull (pxQueue))
789
      {
790
	/* The queue is full - do we want to block or just leave without
791
	   posting? */
792
	if (xTicksToWait > (portTickType) 0)
793
	  {
794
	    /* As this is called from a coroutine we cannot block directly, but
795
	       return indicating that we need to block. */
796
	    vCoRoutineAddToDelayedList (xTicksToWait,
797
					&(pxQueue->xTasksWaitingToSend));
798
	    portENABLE_INTERRUPTS ();
799
	    return errQUEUE_BLOCKED;
800
	  }
801
	else
802
	  {
803
	    portENABLE_INTERRUPTS ();
804
	    return errQUEUE_FULL;
805
	  }
806
      }
807
  }
808
  portENABLE_INTERRUPTS ();
809

    
810
  portNOP ();
811

    
812
  portDISABLE_INTERRUPTS ();
813
  {
814
    if (pxQueue->uxMessagesWaiting < pxQueue->uxLength)
815
      {
816
	/* There is room in the queue, copy the data into the queue. */
817
	prvCopyQueueData (pxQueue, pvItemToQueue);
818
	xReturn = pdPASS;
819

    
820
	/* Were any co-routines waiting for data to become available? */
821
	if (!listLIST_IS_EMPTY (&(pxQueue->xTasksWaitingToReceive)))
822
	  {
823
	    /* In this instance the co-routine could be placed directly 
824
	       into the ready list as we are within a critical section.  
825
	       Instead the same pending ready list mechansim is used as if
826
	       the event were caused from within an interrupt. */
827
	    if (xCoRoutineRemoveFromEventList
828
		(&(pxQueue->xTasksWaitingToReceive)) != pdFALSE)
829
	      {
830
		/* The co-routine waiting has a higher priority so record 
831
		   that a yield might be appropriate. */
832
		xReturn = errQUEUE_YIELD;
833
	      }
834
	  }
835
      }
836
    else
837
      {
838
	xReturn = errQUEUE_FULL;
839
      }
840
  }
841
  portENABLE_INTERRUPTS ();
842

    
843
  return xReturn;
844
}
845
#endif
846
/*-----------------------------------------------------------*/
847

    
848
#if configUSE_CO_ROUTINES == 1
849
signed portBASE_TYPE
850
xQueueCRReceive (xQueueHandle pxQueue, void *pvBuffer,
851
		 portTickType xTicksToWait)
852
{
853
  signed portBASE_TYPE xReturn;
854

    
855
  /* If the queue is already empty we may have to block.  A critical section
856
     is required to prevent an interrupt adding something to the queue 
857
     between the check to see if the queue is empty and blocking on the queue. */
858
  portDISABLE_INTERRUPTS ();
859
  {
860
    if (pxQueue->uxMessagesWaiting == (unsigned portBASE_TYPE) 0)
861
      {
862
	/* There are no messages in the queue, do we want to block or just
863
	   leave with nothing? */
864
	if (xTicksToWait > (portTickType) 0)
865
	  {
866
	    /* As this is a co-routine we cannot block directly, but return
867
	       indicating that we need to block. */
868
	    vCoRoutineAddToDelayedList (xTicksToWait,
869
					&(pxQueue->xTasksWaitingToReceive));
870
	    portENABLE_INTERRUPTS ();
871
	    return errQUEUE_BLOCKED;
872
	  }
873
	else
874
	  {
875
	    portENABLE_INTERRUPTS ();
876
	    return errQUEUE_FULL;
877
	  }
878
      }
879
  }
880
  portENABLE_INTERRUPTS ();
881

    
882
  portNOP ();
883

    
884
  portDISABLE_INTERRUPTS ();
885
  {
886
    if (pxQueue->uxMessagesWaiting > (unsigned portBASE_TYPE) 0)
887
      {
888
	/* Data is available from the queue. */
889
	pxQueue->pcReadFrom += pxQueue->uxItemSize;
890
	if (pxQueue->pcReadFrom >= pxQueue->pcTail)
891
	  {
892
	    pxQueue->pcReadFrom = pxQueue->pcHead;
893
	  }
894
	--(pxQueue->uxMessagesWaiting);
895
	memcpy ((void *) pvBuffer, (void *) pxQueue->pcReadFrom,
896
		(unsigned) pxQueue->uxItemSize);
897

    
898
	xReturn = pdPASS;
899

    
900
	/* Were any co-routines waiting for space to become available? */
901
	if (!listLIST_IS_EMPTY (&(pxQueue->xTasksWaitingToSend)))
902
	  {
903
	    /* In this instance the co-routine could be placed directly 
904
	       into the ready list as we are within a critical section.  
905
	       Instead the same pending ready list mechansim is used as if
906
	       the event were caused from within an interrupt. */
907
	    if (xCoRoutineRemoveFromEventList
908
		(&(pxQueue->xTasksWaitingToSend)) != pdFALSE)
909
	      {
910
		xReturn = errQUEUE_YIELD;
911
	      }
912
	  }
913
      }
914
    else
915
      {
916
	xReturn = pdFAIL;
917
      }
918
  }
919
  portENABLE_INTERRUPTS ();
920

    
921
  return xReturn;
922
}
923
#endif
924
/*-----------------------------------------------------------*/
925

    
926

    
927

    
928
#if configUSE_CO_ROUTINES == 1
929
signed portBASE_TYPE
930
xQueueCRSendFromISR (xQueueHandle pxQueue, const void *pvItemToQueue,
931
		     signed portBASE_TYPE xCoRoutinePreviouslyWoken)
932
{
933
  /* Cannot block within an ISR so if there is no space on the queue then
934
     exit without doing anything. */
935
  if (pxQueue->uxMessagesWaiting < pxQueue->uxLength)
936
    {
937
      prvCopyQueueData (pxQueue, pvItemToQueue);
938

    
939
      /* We only want to wake one co-routine per ISR, so check that a 
940
         co-routine has not already been woken. */
941
      if (!xCoRoutinePreviouslyWoken)
942
	{
943
	  if (!listLIST_IS_EMPTY (&(pxQueue->xTasksWaitingToReceive)))
944
	    {
945
	      if (xCoRoutineRemoveFromEventList
946
		  (&(pxQueue->xTasksWaitingToReceive)) != pdFALSE)
947
		{
948
		  return pdTRUE;
949
		}
950
	    }
951
	}
952
    }
953

    
954
  return xCoRoutinePreviouslyWoken;
955
}
956
#endif
957
/*-----------------------------------------------------------*/
958

    
959
#if configUSE_CO_ROUTINES == 1
960
signed portBASE_TYPE
961
xQueueCRReceiveFromISR (xQueueHandle pxQueue, void *pvBuffer,
962
			signed portBASE_TYPE * pxCoRoutineWoken)
963
{
964
  signed portBASE_TYPE xReturn;
965

    
966
  /* We cannot block from an ISR, so check there is data available. If
967
     not then just leave without doing anything. */
968
  if (pxQueue->uxMessagesWaiting > (unsigned portBASE_TYPE) 0)
969
    {
970
      /* Copy the data from the queue. */
971
      pxQueue->pcReadFrom += pxQueue->uxItemSize;
972
      if (pxQueue->pcReadFrom >= pxQueue->pcTail)
973
	{
974
	  pxQueue->pcReadFrom = pxQueue->pcHead;
975
	}
976
      --(pxQueue->uxMessagesWaiting);
977
      memcpy ((void *) pvBuffer, (void *) pxQueue->pcReadFrom,
978
	      (unsigned) pxQueue->uxItemSize);
979

    
980
      if (!(*pxCoRoutineWoken))
981
	{
982
	  if (!listLIST_IS_EMPTY (&(pxQueue->xTasksWaitingToSend)))
983
	    {
984
	      if (xCoRoutineRemoveFromEventList
985
		  (&(pxQueue->xTasksWaitingToSend)) != pdFALSE)
986
		{
987
		  *pxCoRoutineWoken = pdTRUE;
988
		}
989
	    }
990
	}
991

    
992
      xReturn = pdPASS;
993
    }
994
  else
995
    {
996
      xReturn = pdFAIL;
997
    }
998

    
999
  return xReturn;
1000
}
1001
#endif
1002
/*-----------------------------------------------------------*/
(2-2/3)
Add picture from clipboard (Maximum size: 48.8 MB)