Project

General

Profile

Download (58.6 KB) Statistics
| Branch: | Tag: | Revision:
1 633c646a henryk
/*
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 development and support options.
33
	***************************************************************************
34
*/
35
36
/*
37
Changes from V1.00:
38
	
39
	+ Call to portRESTORE_CONTEXT has been removed.  The first context
40
	  switch is now performed within sPortStartScheduler().
41
42
Changes from V1.01:
43
44
	+ More use of 8bit data types.
45
	+ Function name prefixes changed where the data type returned has changed.
46
	+ configUSE_TRACE_FACILITY is no longer defined by default.
47
48
Changes from V1.2.0
49
50
	+ Introduced ucTopReadyPriority.  This tracks the highest priority ready
51
	  queue that contains a valid TCB and thus makes the context switch
52
	  slightly faster.
53
54
	+ prvAddTaskToReadyQueue() has been made a macro.
55
56
Changes from V1.2.6
57
58
	+ Added conditional compilation directives.
59
	+ Extended API.
60
	+ Rearranged function order.
61
	+ Creating a task now causes a context switch if the task being created
62
	  has a higher priority than the calling task - assuming the kernel is
63
	  running.
64
	+ vTaskDelete() now only causes a context switch if the calling task is
65
	  the task being deleted.
66
67
Changes from V2.0.0
68
69
	+ Allow the type of the tick count to be 16 or 32 bits.
70
	+ Introduce xPendingReadyList feature to allow the time interrupts have to
71
	  be disabled to be minimised.
72
	+ Remove the #if( INCLUDE_vTaskSuspendAll ) statements.  vTaskSuspendAll()
73
	  is now always included as it is used by the scheduler itself.
74
75
Changes from V2.1.0
76
77
	+ Bug fix - pxCurrentTCB is now initialised before the call to
78
	  prvInitializeTaskLists().  Previously pxCurrentTCB could be accessed
79
	  while null.
80
81
Changed from V2.1.1
82
83
	+ Change to where lStackSize is declared within sTaskCreate() to prevent
84
	  compiler warnings with 8051 port.
85
86
Changes from V2.2.0
87
88
	+ Explicit use of 'signed' qualifier on portCHAR types added.
89
	+ Changed odd calculation of initial pxTopOfStack value when
90
	  portSTACK_GROWTH < 0.
91
	+ Removed pcVersionNumber definition.
92
93
Changes from V2.5.3
94
95
	+ cTaskResumeAll() modified to ensure it can be called prior to the task
96
	  lists being initialised.
97
98
Changes from V2.5.5
99
100
	+ Added API function vTaskDelayUntil().
101
	+ Added INCLUDE_vTaskDelay conditional compilation.
102
103
Changes from V2.6.0
104
105
 	+ Updated the vWriteTraceToBuffer macro to always be 4 byte aligned so it
106
	  can be used on ARM architectures.
107
	+ tskMAX_TASK_NAME_LEN definition replaced with the port specific
108
	  configMAX_TASK_NAME_LEN definition.
109
	+ Removed the call to strcpy when copying across the task name into the
110
	  TCB.
111
	+ Added ucTasksDeleted variable to prevent vTaskSuspendAll() being called
112
	  too often in the idle task.
113
114
Changes between V3.0.0 and V2.6.1
115
116
	+ When resuming the scheduler a yield is performed if either a tick has
117
	  been missed, or a task is moved from the pending ready list into a ready
118
	  list.  Previously a yield was not performed on this second condition.
119
	+ Introduced the type portBASE_TYPE.  This necessitates several API
120
	  changes.
121
	+ Removed the sUsingPreemption variable.  The constant defined in
122
	  portmacro.h is now used directly.
123
	+ The idle task can now include an optional hook function - and no longer
124
	  completes its time slice if other tasks with equal priority to it are
125
	  ready to run.
126
	+ See the FreeRTOS.org documentation for more information on V2.x.x to
127
	  V3.x.x modifications.
128
129
Changes from V3.1.1
130
131
	+ Modified vTaskPrioritySet() and vTaskResume() to allow these functions to
132
	  be called while the scheduler is suspended.
133
	+ Corrected the task ordering within event lists.
134
135
Changes from V3.2.0
136
137
	+ Added function xTaskGetCurrentTaskHandle().
138
139
Changes from V3.2.4
140
141
	+ Changed the volatile declarations on some variables to reflect the 
142
	  changes to the list definitions.
143
	+ Changed the order of the TCB definition so there is commonality between
144
	  the task control block and a co-routine control block.
145
	+ Allow the scheduler to be started even if no tasks other than the idle
146
	  task has been created.  This allows co-routines to run even when no tasks
147
	  have been created.
148
	+ The need for a context switch is now signalled if a task woken by an 
149
	  event has a priority greater or equal to the currently running task.
150
	  Previously this was only greater than.
151
152
Changes from V4.0.0
153
154
	+ Added the xMissedYield handling.
155
156
Changes from V4.0.1
157
158
	+ The function vTaskList() now suspends the scheduler rather than disabling
159
	  interrupts during the creation of the task list.  
160
	+ Allow a task to delete itself by passing in its own handle.  Previously 
161
	  this could only be done by passing in NULL.
162
	+ The tick hook function is now called only within a tick isr.  Previously
163
	  it was also called when the tick function was called during the scheduler
164
	  unlocking process.
165
166
Changes from V4.0.3
167
168
	+ Extra checks have been placed in vTaskPrioritySet() to avoid unnecessary
169
	  yields.
170
171
Changed from V4.0.4
172
173
	+ Bug fix:  The 'value' of the event list item is updated when the priority
174
	  of a task is changed.  Previously only the priority of the TCB itself was
175
	  changed.
176
	+ When resuming a task a check is first made to see if the task is actually
177
	  suspended.
178
	+ vTaskPrioritySet() and vTaskResume() no longer use the event list item.
179
	  This has not been necessary since V4.0.1 when the xMissedYield handling
180
	  was added.
181
	+ Implement xTaskResumeFromISR().
182
183
Changes from V4.0.5
184
185
	+ Added utility functions and xOverflowCount variable to facilitate the
186
	  queue.c changes.
187
188
Changes from V4.1.2
189
	
190
	+ Tasks that block on events with a timeout of portMAX_DELAY are now
191
	  blocked indefinitely if configINCLUDE_vTaskSuspend is defined. 
192
	  Previously portMAX_DELAY was just the longest block time possible.
193
194
Changes from V4.1.3
195
196
	+ Very small change made to xTaskCheckForTimeout() as a result of the 
197
	SafeRTOS testing.  This corrects the case where the function can return an
198
	invalid value - but only in an extremely unlikely scenario.
199
*/
200
201
#include <stdio.h>
202
#include <stdlib.h>
203
#include <string.h>
204
205
#include "FreeRTOS.h"
206
#include "task.h"
207
208
/*
209
 * Macro to define the amount of stack available to the idle task.
210
 */
211
#define tskIDLE_STACK_SIZE	configMINIMAL_STACK_SIZE
212
213
214
/*
215
 * Default a definitions for backwards compatibility with old
216
 * portmacro.h files.
217
 */
218
#ifndef configMAX_TASK_NAME_LEN
219
#define configMAX_TASK_NAME_LEN 16
220
#endif
221
222
#ifndef INCLUDE_xTaskGetCurrentTaskHandle
223
#define INCLUDE_xTaskGetCurrentTaskHandle 0
224
#endif
225
226
#ifndef configIDLE_SHOULD_YIELD
227
#define configIDLE_SHOULD_YIELD		1
228
#endif
229
230
#if configMAX_TASK_NAME_LEN < 1
231
#undef configMAX_TASK_NAME_LEN
232
#define configMAX_TASK_NAME_LEN 1
233
#endif
234
235
#ifndef INCLUDE_xTaskResumeFromISR
236
#define INCLUDE_xTaskResumeFromISR 1
237
#endif
238
239
/*
240
 * Task control block.  A task control block (TCB) is allocated to each task,
241
 * and stores the context of the task.
242
 */
243
typedef struct tskTaskControlBlock
244
{
245
  volatile portSTACK_TYPE *pxTopOfStack;	/*< Points to the location of the last item placed on the tasks stack.  THIS MUST BE THE FIRST MEMBER OF THE STRUCT. */
246
  xListItem xGenericListItem;	/*< List item used to place the TCB in ready and blocked queues. */
247
  xListItem xEventListItem;	/*< List item used to place the TCB in event lists. */
248
  unsigned portBASE_TYPE uxPriority;	/*< The priority of the task where 0 is the lowest priority. */
249
  portSTACK_TYPE *pxStack;	/*< Points to the start of the stack. */
250
  unsigned portBASE_TYPE uxTCBNumber;	/*< This is used for tracing the scheduler and making debugging easier only. */
251
  signed portCHAR pcTaskName[configMAX_TASK_NAME_LEN];	/*< Descriptive name given to the task when created.  Facilitates debugging only. */
252
  unsigned portSHORT usStackDepth;	/*< Total depth of the stack (when empty).  This is defined as the number of variables the stack can hold, not the number of bytes. */
253
} tskTCB;
254
255
/*lint -e956 */
256
257
tskTCB *volatile pxCurrentTCB = NULL;
258
259
/* Lists for ready and blocked tasks. --------------------*/
260
261
static xList pxReadyTasksLists[configMAX_PRIORITIES];	/*< Prioritised ready tasks. */
262
static xList xDelayedTaskList1;	/*< Delayed tasks. */
263
static xList xDelayedTaskList2;	/*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
264
static xList *volatile pxDelayedTaskList;	/*< Points to the delayed task list currently being used. */
265
static xList *volatile pxOverflowDelayedTaskList;	/*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
266
static xList xPendingReadyList;	/*< Tasks that have been readied while the scheduler was suspended.  They will be moved to the ready queue when the scheduler is resumed. */
267
268
#if ( INCLUDE_vTaskDelete == 1 )
269
270
static volatile xList xTasksWaitingTermination;	/*< Tasks that have been deleted - but the their memory not yet freed. */
271
static volatile unsigned portBASE_TYPE uxTasksDeleted =
272
  (unsigned portBASE_TYPE) 0;
273
274
#endif
275
276
#if ( INCLUDE_vTaskSuspend == 1 )
277
278
static xList xSuspendedTaskList;	/*< Tasks that are currently suspended. */
279
280
#endif
281
282
/* File private variables. --------------------------------*/
283
static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks =
284
  (unsigned portBASE_TYPE) 0;
285
static volatile portTickType xTickCount = (portTickType) 0;
286
static unsigned portBASE_TYPE uxTopUsedPriority = tskIDLE_PRIORITY;
287
static volatile unsigned portBASE_TYPE uxTopReadyPriority = tskIDLE_PRIORITY;
288
static volatile signed portBASE_TYPE xSchedulerRunning = pdFALSE;
289
static volatile unsigned portBASE_TYPE uxSchedulerSuspended =
290
  (unsigned portBASE_TYPE) pdFALSE;
291
static volatile unsigned portBASE_TYPE uxMissedTicks =
292
  (unsigned portBASE_TYPE) 0;
293
static volatile portBASE_TYPE xMissedYield = (portBASE_TYPE) pdFALSE;
294
static volatile portBASE_TYPE xNumOfOverflows = (portBASE_TYPE) 0;
295
/* Debugging and trace facilities private variables and macros. ------------*/
296
297
/*
298
 * The value used to fill the stack of a task when the task is created.  This
299
 * is used purely for checking the high water mark for tasks.
300
 */
301
#define tskSTACK_FILL_BYTE	( 0xa5 )
302
303
/*
304
 * Macros used by vListTask to indicate which state a task is in.
305
 */
306
#define tskBLOCKED_CHAR		( ( signed portCHAR ) 'B' )
307
#define tskREADY_CHAR		( ( signed portCHAR ) 'R' )
308
#define tskDELETED_CHAR		( ( signed portCHAR ) 'D' )
309
#define tskSUSPENDED_CHAR	( ( signed portCHAR ) 'S' )
310
311
/*
312
 * Macros and private variables used by the trace facility.
313
 */
314
#if ( configUSE_TRACE_FACILITY == 1 )
315
316
#define tskSIZE_OF_EACH_TRACE_LINE			( ( unsigned portLONG ) ( sizeof( unsigned portLONG ) + sizeof( unsigned portLONG ) ) )
317
static volatile signed portCHAR *volatile pcTraceBuffer;
318
static signed portCHAR *pcTraceBufferStart;
319
static signed portCHAR *pcTraceBufferEnd;
320
static signed portBASE_TYPE xTracing = pdFALSE;
321
322
#endif
323
324
/*
325
 * Macro that writes a trace of scheduler activity to a buffer.  This trace
326
 * shows which task is running when and is very useful as a debugging tool.
327
 * As this macro is called each context switch it is a good idea to undefine
328
 * it if not using the facility.
329
 */
330
#if ( configUSE_TRACE_FACILITY == 1 )
331
332
#define vWriteTraceToBuffer()																	\
333
	{																								\
334
		if( xTracing )																				\
335
		{																							\
336
			static unsigned portBASE_TYPE uxPreviousTask = 255;										\
337
																									\
338
			if( uxPreviousTask != pxCurrentTCB->uxTCBNumber )										\
339
			{																						\
340
				if( ( pcTraceBuffer + tskSIZE_OF_EACH_TRACE_LINE ) < pcTraceBufferEnd )				\
341
				{																					\
342
					uxPreviousTask = pxCurrentTCB->uxTCBNumber;										\
343
					*( unsigned portLONG * ) pcTraceBuffer = ( unsigned portLONG ) xTickCount;		\
344
					pcTraceBuffer += sizeof( unsigned portLONG );									\
345
					*( unsigned portLONG * ) pcTraceBuffer = ( unsigned portLONG ) uxPreviousTask;	\
346
					pcTraceBuffer += sizeof( unsigned portLONG );									\
347
				}																					\
348
				else																				\
349
				{																					\
350
					xTracing = pdFALSE;																\
351
				}																					\
352
			}																						\
353
		}																							\
354
	}
355
356
#else
357
358
#define vWriteTraceToBuffer()
359
360
#endif
361
362
363
/*
364
 * Place the task represented by pxTCB into the appropriate ready queue for
365
 * the task.  It is inserted at the end of the list.  One quirk of this is
366
 * that if the task being inserted is at the same priority as the currently
367
 * executing task, then it will only be rescheduled after the currently
368
 * executing task has been rescheduled.
369
 */
370
#define prvAddTaskToReadyQueue( pxTCB )																			\
371
{																												\
372
	if( pxTCB->uxPriority > uxTopReadyPriority )																\
373
	{																											\
374
		uxTopReadyPriority = pxTCB->uxPriority;																	\
375
	}																											\
376
	vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) );	\
377
}
378
379
/*
380
 * Macro that looks at the list of tasks that are currently delayed to see if
381
 * any require waking.
382
 *
383
 * Tasks are stored in the queue in the order of their wake time - meaning
384
 * once one tasks has been found whose timer has not expired we need not look
385
 * any further down the list.
386
 */
387
#define prvCheckDelayedTasks()																						\
388
{																													\
389
register tskTCB *pxTCB;																								\
390
																													\
391
	while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ) ) != NULL )						\
392
	{																												\
393
		if( xTickCount < listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ) )									\
394
		{																											\
395
			break;																									\
396
		}																											\
397
		vListRemove( &( pxTCB->xGenericListItem ) );																\
398
		/* Is the task waiting on an event also? */																	\
399
		if( pxTCB->xEventListItem.pvContainer )																		\
400
		{																											\
401
			vListRemove( &( pxTCB->xEventListItem ) );																\
402
		}																											\
403
		prvAddTaskToReadyQueue( pxTCB );														\
404
	}																												\
405
}
406
407
/*
408
 * Several functions take an xTaskHandle parameter that can optionally be NULL,
409
 * where NULL is used to indicate that the handle of the currently executing
410
 * task should be used in place of the parameter.  This macro simply checks to
411
 * see if the parameter is NULL and returns a pointer to the appropriate TCB.
412
 */
413
#define prvGetTCBFromHandle( pxHandle ) ( ( pxHandle == NULL ) ? ( tskTCB * ) pxCurrentTCB : ( tskTCB * ) pxHandle )
414
415
416
/* File private functions. --------------------------------*/
417
418
/*
419
 * Utility to ready a TCB for a given task.  Mainly just copies the parameters
420
 * into the TCB structure.
421
 */
422
static void prvInitialiseTCBVariables (tskTCB * pxTCB,
423
				       unsigned portSHORT usStackDepth,
424
				       const signed portCHAR * const pcName,
425
				       unsigned portBASE_TYPE uxPriority);
426
427
/*
428
 * Utility to ready all the lists used by the scheduler.  This is called
429
 * automatically upon the creation of the first task.
430
 */
431
static void prvInitialiseTaskLists (void);
432
433
/*
434
 * The idle task, which as all tasks is implemented as a never ending loop.
435
 * The idle task is automatically created and added to the ready lists upon
436
 * creation of the first user task.
437
 *
438
 * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific
439
 * language extensions.  The equivalent prototype for this function is:
440
 *
441
 * void prvIdleTask( void *pvParameters );
442
 *
443
 */
444
static portTASK_FUNCTION_PROTO (prvIdleTask, pvParameters);
445
446
/*
447
 * Utility to free all memory allocated by the scheduler to hold a TCB,
448
 * including the stack pointed to by the TCB.
449
 *
450
 * This does not free memory allocated by the task itself (i.e. memory
451
 * allocated by calls to pvPortMalloc from within the tasks application code).
452
 */
453
#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
454
static void prvDeleteTCB (tskTCB * pxTCB);
455
#endif
456
457
/*
458
 * Used only by the idle task.  This checks to see if anything has been placed
459
 * in the list of tasks waiting to be deleted.  If so the task is cleaned up
460
 * and its TCB deleted.
461
 */
462
static void prvCheckTasksWaitingTermination (void);
463
464
/*
465
 * Allocates memory from the heap for a TCB and associated stack.  Checks the
466
 * allocation was successful.
467
 */
468
static tskTCB *prvAllocateTCBAndStack (unsigned portSHORT usStackDepth);
469
470
/*
471
 * Called from vTaskList.  vListTasks details all the tasks currently under
472
 * control of the scheduler.  The tasks may be in one of a number of lists.
473
 * prvListTaskWithinSingleList accepts a list and details the tasks from
474
 * within just that list.
475
 *
476
 * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM
477
 * NORMAL APPLICATION CODE.
478
 */
479
#if ( configUSE_TRACE_FACILITY == 1 )
480
481
static void prvListTaskWithinSingleList (signed portCHAR * pcWriteBuffer,
482
					 xList * pxList,
483
					 signed portCHAR cStatus);
484
485
#endif
486
487
/*
488
 * When a task is created, the stack of the task is filled with a known value.
489
 * This function determines the 'high water mark' of the task stack by
490
 * determining how much of the stack remains at the original preset value.
491
 */
492
#if ( configUSE_TRACE_FACILITY == 1 )
493
494
unsigned portSHORT usTaskCheckFreeStackSpace (const unsigned portCHAR *
495
					      pucStackByte);
496
497
#endif
498
499
/*lint +e956 */
500
501
502
503
504
505
/*-----------------------------------------------------------
506
 * TASK CREATION API documented in task.h
507
 *----------------------------------------------------------*/
508
509
signed portBASE_TYPE
510
xTaskCreate (pdTASK_CODE pvTaskCode, const signed portCHAR * const pcName,
511
	     unsigned portSHORT usStackDepth, void *pvParameters,
512
	     unsigned portBASE_TYPE uxPriority, xTaskHandle * pxCreatedTask)
513
{
514
  signed portBASE_TYPE xReturn;
515
  tskTCB *pxNewTCB;
516
  static unsigned portBASE_TYPE uxTaskNumber = 0;	/*lint !e956 Static is deliberate - this is guarded before use. */
517
518
  /* Allocate the memory required by the TCB and stack for the new task.
519
     checking that the allocation was successful. */
520
  pxNewTCB = prvAllocateTCBAndStack (usStackDepth);
521
522
  if (pxNewTCB != NULL)
523
    {
524
      portSTACK_TYPE *pxTopOfStack;
525
526
      /* Setup the newly allocated TCB with the initial state of the task. */
527
      prvInitialiseTCBVariables (pxNewTCB, usStackDepth, pcName, uxPriority);
528
529
      /* Calculate the top of stack address.  This depends on whether the
530
         stack grows from high memory to low (as per the 80x86) or visa versa.
531
         portSTACK_GROWTH is used to make the result positive or negative as
532
         required by the port. */
533
#if portSTACK_GROWTH < 0
534
      {
535
	pxTopOfStack = pxNewTCB->pxStack + (pxNewTCB->usStackDepth - 1);
536
      }
537
#else
538
      {
539
	pxTopOfStack = pxNewTCB->pxStack;
540
      }
541
#endif
542
543
      /* Initialize the TCB stack to look as if the task was already running,
544
         but had been interrupted by the scheduler.  The return address is set
545
         to the start of the task function. Once the stack has been initialised
546
         the  top of stack variable is updated. */
547
      pxNewTCB->pxTopOfStack =
548
	pxPortInitialiseStack (pxTopOfStack, pvTaskCode, pvParameters);
549
550
      /* We are going to manipulate the task queues to add this task to a
551
         ready list, so must make sure no interrupts occur. */
552
      portENTER_CRITICAL ();
553
      {
554
	uxCurrentNumberOfTasks++;
555
	if (uxCurrentNumberOfTasks == (unsigned portBASE_TYPE) 1)
556
	  {
557
	    /* As this is the first task it must also be the current task. */
558
	    pxCurrentTCB = pxNewTCB;
559
560
	    /* This is the first task to be created so do the preliminary
561
	       initialisation required.  We will not recover if this call
562
	       fails, but we will report the failure. */
563
	    prvInitialiseTaskLists ();
564
	  }
565
	else
566
	  {
567
	    /* If the scheduler is not already running, make this task the
568
	       current task if it is the highest priority task to be created
569
	       so far. */
570
	    if (xSchedulerRunning == pdFALSE)
571
	      {
572
		if (pxCurrentTCB->uxPriority <= uxPriority)
573
		  {
574
		    pxCurrentTCB = pxNewTCB;
575
		  }
576
	      }
577
	  }
578
579
	/* Remember the top priority to make context switching faster.  Use
580
	   the priority in pxNewTCB as this has been capped to a valid value. */
581
	if (pxNewTCB->uxPriority > uxTopUsedPriority)
582
	  {
583
	    uxTopUsedPriority = pxNewTCB->uxPriority;
584
	  }
585
586
	/* Add a counter into the TCB for tracing only. */
587
	pxNewTCB->uxTCBNumber = uxTaskNumber;
588
	uxTaskNumber++;
589
590
	prvAddTaskToReadyQueue (pxNewTCB);
591
592
	xReturn = pdPASS;
593
      }
594
      portEXIT_CRITICAL ();
595
    }
596
  else
597
    {
598
      xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
599
    }
600
601
  if (xReturn == pdPASS)
602
    {
603
      if ((void *) pxCreatedTask != NULL)
604
	{
605
	  /* Pass the TCB out - in an anonymous way.  The calling function/
606
	     task can use this as a handle to delete the task later if
607
	     required. */
608
	  *pxCreatedTask = (xTaskHandle) pxNewTCB;
609
	}
610
611
      if (xSchedulerRunning != pdFALSE)
612
	{
613
	  /* If the created task is of a higher priority than the current task
614
	     then it should run now. */
615
	  if (pxCurrentTCB->uxPriority < uxPriority)
616
	    {
617
	      taskYIELD ();
618
	    }
619
	}
620
    }
621
622
  return xReturn;
623
}
624
625
/*-----------------------------------------------------------*/
626
627
#if ( INCLUDE_vTaskDelete == 1 )
628
629
void
630
vTaskDelete (xTaskHandle pxTaskToDelete)
631
{
632
  tskTCB *pxTCB;
633
634
  taskENTER_CRITICAL ();
635
  {
636
    /* Ensure a yield is performed if the current task is being 
637
       deleted. */
638
    if (pxTaskToDelete == pxCurrentTCB)
639
      {
640
	pxTaskToDelete = NULL;
641
      }
642
643
    /* If null is passed in here then we are deleting ourselves. */
644
    pxTCB = prvGetTCBFromHandle (pxTaskToDelete);
645
646
    /* Remove task from the ready list and place in the     termination list.
647
       This will stop the task from be scheduled.  The idle task will check
648
       the termination list and free up any memory allocated by the
649
       scheduler for the TCB and stack. */
650
    vListRemove (&(pxTCB->xGenericListItem));
651
652
    /* Is the task waiting on an event also? */
653
    if (pxTCB->xEventListItem.pvContainer)
654
      {
655
	vListRemove (&(pxTCB->xEventListItem));
656
      }
657
658
    vListInsertEnd ((xList *) & xTasksWaitingTermination,
659
		    &(pxTCB->xGenericListItem));
660
661
    /* Increment the ucTasksDeleted variable so the idle task knows
662
       there is a task that has been deleted and that it should therefore
663
       check the xTasksWaitingTermination list. */
664
    ++uxTasksDeleted;
665
  }
666
  taskEXIT_CRITICAL ();
667
668
  /* Force a reschedule if we have just deleted the current task. */
669
  if (xSchedulerRunning != pdFALSE)
670
    {
671
      if ((void *) pxTaskToDelete == NULL)
672
	{
673
	  taskYIELD ();
674
	}
675
    }
676
}
677
678
#endif
679
680
681
682
683
684
685
/*-----------------------------------------------------------
686
 * TASK CONTROL API documented in task.h
687
 *----------------------------------------------------------*/
688
689
#if ( INCLUDE_vTaskDelayUntil == 1 )
690
691
void
692
vTaskDelayUntil (portTickType * pxPreviousWakeTime,
693
		 portTickType xTimeIncrement)
694
{
695
  portTickType xTimeToWake;
696
  portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE;
697
698
  vTaskSuspendAll ();
699
  {
700
    /* Generate the tick time at which the task wants to wake. */
701
    xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
702
703
    if (xTickCount < *pxPreviousWakeTime)
704
      {
705
	/* The tick count has overflowed since this function was
706
	   lasted called.  In this case the only time we should ever
707
	   actually delay is if the wake time has also  overflowed,
708
	   and the wake time is greater than the tick time.  When this
709
	   is the case it is as if neither time had overflowed. */
710
	if ((xTimeToWake < *pxPreviousWakeTime) && (xTimeToWake > xTickCount))
711
	  {
712
	    xShouldDelay = pdTRUE;
713
	  }
714
      }
715
    else
716
      {
717
	/* The tick time has not overflowed.  In this case we will
718
	   delay if either the wake time has overflowed, and/or the
719
	   tick time is less than the wake time. */
720
	if ((xTimeToWake < *pxPreviousWakeTime) || (xTimeToWake > xTickCount))
721
	  {
722
	    xShouldDelay = pdTRUE;
723
	  }
724
      }
725
726
    /* Update the wake time ready for the next call. */
727
    *pxPreviousWakeTime = xTimeToWake;
728
729
    if (xShouldDelay)
730
      {
731
	/* We must remove ourselves from the ready list before adding
732
	   ourselves to the blocked list as the same list item is used for
733
	   both lists. */
734
	vListRemove ((xListItem *) & (pxCurrentTCB->xGenericListItem));
735
736
	/* The list item will be inserted in wake time order. */
737
	listSET_LIST_ITEM_VALUE (&(pxCurrentTCB->xGenericListItem),
738
				 xTimeToWake);
739
740
	if (xTimeToWake < xTickCount)
741
	  {
742
	    /* Wake time has overflowed.  Place this item in the
743
	       overflow list. */
744
	    vListInsert ((xList *) pxOverflowDelayedTaskList,
745
			 (xListItem *) & (pxCurrentTCB->xGenericListItem));
746
	  }
747
	else
748
	  {
749
	    /* The wake time has not overflowed, so we can use the
750
	       current block list. */
751
	    vListInsert ((xList *) pxDelayedTaskList,
752
			 (xListItem *) & (pxCurrentTCB->xGenericListItem));
753
	  }
754
      }
755
  }
756
  xAlreadyYielded = xTaskResumeAll ();
757
758
  /* Force a reschedule if xTaskResumeAll has not already done so, we may
759
     have put ourselves to sleep. */
760
  if (!xAlreadyYielded)
761
    {
762
      taskYIELD ();
763
    }
764
}
765
766
#endif
767
/*-----------------------------------------------------------*/
768
769
#if ( INCLUDE_vTaskDelay == 1 )
770
771
void
772
vTaskDelay (portTickType xTicksToDelay)
773
{
774
  portTickType xTimeToWake;
775
  signed portBASE_TYPE xAlreadyYielded = pdFALSE;
776
777
  /* A delay time of zero just forces a reschedule. */
778
  if (xTicksToDelay > (portTickType) 0)
779
    {
780
      vTaskSuspendAll ();
781
      {
782
	/* A task that is removed from the event list while the
783
	   scheduler is suspended will not get placed in the ready
784
	   list or removed from the blocked list until the scheduler
785
	   is resumed.
786
787
	   This task cannot be in an event list as it is the currently
788
	   executing task. */
789
790
	/* Calculate the time to wake - this may overflow but this is
791
	   not a problem. */
792
	xTimeToWake = xTickCount + xTicksToDelay;
793
794
	/* We must remove ourselves from the ready list before adding
795
	   ourselves to the blocked list as the same list item is used for
796
	   both lists. */
797
	vListRemove ((xListItem *) & (pxCurrentTCB->xGenericListItem));
798
799
	/* The list item will be inserted in wake time order. */
800
	listSET_LIST_ITEM_VALUE (&(pxCurrentTCB->xGenericListItem),
801
				 xTimeToWake);
802
803
	if (xTimeToWake < xTickCount)
804
	  {
805
	    /* Wake time has overflowed.  Place this item in the
806
	       overflow list. */
807
	    vListInsert ((xList *) pxOverflowDelayedTaskList,
808
			 (xListItem *) & (pxCurrentTCB->xGenericListItem));
809
	  }
810
	else
811
	  {
812
	    /* The wake time has not overflowed, so we can use the
813
	       current block list. */
814
	    vListInsert ((xList *) pxDelayedTaskList,
815
			 (xListItem *) & (pxCurrentTCB->xGenericListItem));
816
	  }
817
      }
818
      xAlreadyYielded = xTaskResumeAll ();
819
    }
820
821
  /* Force a reschedule if xTaskResumeAll has not already done so, we may
822
     have put ourselves to sleep. */
823
  if (!xAlreadyYielded)
824
    {
825
      taskYIELD ();
826
    }
827
}
828
829
#endif
830
/*-----------------------------------------------------------*/
831
832
#if ( INCLUDE_uxTaskPriorityGet == 1 )
833
834
unsigned portBASE_TYPE
835
uxTaskPriorityGet (xTaskHandle pxTask)
836
{
837
  tskTCB *pxTCB;
838
  unsigned portBASE_TYPE uxReturn;
839
840
  taskENTER_CRITICAL ();
841
  {
842
    /* If null is passed in here then we are changing the
843
       priority of the calling function. */
844
    pxTCB = prvGetTCBFromHandle (pxTask);
845
    uxReturn = pxTCB->uxPriority;
846
  }
847
  taskEXIT_CRITICAL ();
848
849
  return uxReturn;
850
}
851
852
#endif
853
/*-----------------------------------------------------------*/
854
855
#if ( INCLUDE_vTaskPrioritySet == 1 )
856
857
void
858
vTaskPrioritySet (xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority)
859
{
860
  tskTCB *pxTCB;
861
  unsigned portBASE_TYPE uxCurrentPriority, xYieldRequired = pdFALSE;
862
863
  /* Ensure the new priority is valid. */
864
  if (uxNewPriority >= configMAX_PRIORITIES)
865
    {
866
      uxNewPriority = configMAX_PRIORITIES - 1;
867
    }
868
869
  taskENTER_CRITICAL ();
870
  {
871
    /* If null is passed in here then we are changing the
872
       priority of the calling function. */
873
    pxTCB = prvGetTCBFromHandle (pxTask);
874
    uxCurrentPriority = pxTCB->uxPriority;
875
876
    if (uxCurrentPriority != uxNewPriority)
877
      {
878
	/* The priority change may have readied a task of higher
879
	   priority than the calling task. */
880
	if (uxNewPriority > pxCurrentTCB->uxPriority)
881
	  {
882
	    if (pxTask != NULL)
883
	      {
884
		/* The priority of another task is being raised.  If we
885
		   were raising the priority of the currently running task
886
		   there would be no need to switch as it must have already
887
		   been the highest priority task. */
888
		xYieldRequired = pdTRUE;
889
	      }
890
	  }
891
	else if (pxTask == NULL)
892
	  {
893
	    /* Setting our own priority down means there may now be another
894
	       task of higher priority that is ready to execute. */
895
	    xYieldRequired = pdTRUE;
896
	  }
897
898
	pxTCB->uxPriority = uxNewPriority;
899
	listSET_LIST_ITEM_VALUE (&(pxTCB->xEventListItem),
900
				 configMAX_PRIORITIES -
901
				 (portTickType) uxNewPriority);
902
903
	/* If the task is in the blocked or suspended list we need do
904
	   nothing more than change it's priority variable. However, if
905
	   the task is in a ready list it needs to be removed and placed
906
	   in the queue appropriate to its new priority. */
907
	if (listIS_CONTAINED_WITHIN
908
	    (&(pxReadyTasksLists[uxCurrentPriority]),
909
	     &(pxTCB->xGenericListItem)))
910
	  {
911
	    /* The task is currently in its ready list - remove before adding
912
	       it to it's new ready list.  As we are in a critical section we
913
	       can do this even if the scheduler is suspended. */
914
	    vListRemove (&(pxTCB->xGenericListItem));
915
	    prvAddTaskToReadyQueue (pxTCB);
916
	  }
917
918
	if (xYieldRequired == pdTRUE)
919
	  {
920
	    taskYIELD ();
921
	  }
922
      }
923
  }
924
  taskEXIT_CRITICAL ();
925
}
926
927
#endif
928
/*-----------------------------------------------------------*/
929
930
#if ( INCLUDE_vTaskSuspend == 1 )
931
932
void
933
vTaskSuspend (xTaskHandle pxTaskToSuspend)
934
{
935
  tskTCB *pxTCB;
936
937
  taskENTER_CRITICAL ();
938
  {
939
    /* Ensure a yield is performed if the current task is being 
940
       suspended. */
941
    if (pxTaskToSuspend == pxCurrentTCB)
942
      {
943
	pxTaskToSuspend = NULL;
944
      }
945
946
    /* If null is passed in here then we are suspending ourselves. */
947
    pxTCB = prvGetTCBFromHandle (pxTaskToSuspend);
948
949
    /* Remove task from the ready/delayed list and place in the     suspended list. */
950
    vListRemove (&(pxTCB->xGenericListItem));
951
952
    /* Is the task waiting on an event also? */
953
    if (pxTCB->xEventListItem.pvContainer)
954
      {
955
	vListRemove (&(pxTCB->xEventListItem));
956
      }
957
958
    vListInsertEnd ((xList *) & xSuspendedTaskList,
959
		    &(pxTCB->xGenericListItem));
960
  }
961
  taskEXIT_CRITICAL ();
962
963
  /* We may have just suspended the current task. */
964
  if ((void *) pxTaskToSuspend == NULL)
965
    {
966
      taskYIELD ();
967
    }
968
}
969
970
#endif
971
/*-----------------------------------------------------------*/
972
973
#if ( INCLUDE_vTaskSuspend == 1 )
974
975
void
976
vTaskResume (xTaskHandle pxTaskToResume)
977
{
978
  tskTCB *pxTCB;
979
980
  /* Remove the task from whichever list it is currently in, and place
981
     it in the ready list. */
982
  pxTCB = (tskTCB *) pxTaskToResume;
983
984
  /* The parameter cannot be NULL as it is impossible to resume the
985
     currently executing task. */
986
  if (pxTCB != NULL)
987
    {
988
      taskENTER_CRITICAL ();
989
      {
990
	/* Is the task we are attempting to resume actually suspended? */
991
	if (listIS_CONTAINED_WITHIN
992
	    (&xSuspendedTaskList, &(pxTCB->xGenericListItem)) != pdFALSE)
993
	  {
994
	    /* Has the task already been resumed from within an ISR? */
995
	    if (listIS_CONTAINED_WITHIN
996
		(&xPendingReadyList, &(pxTCB->xEventListItem)) != pdTRUE)
997
	      {
998
		/* As we are in a critical section we can access the ready 
999
		   lists even if the scheduler is suspended. */
1000
		vListRemove (&(pxTCB->xGenericListItem));
1001
		prvAddTaskToReadyQueue (pxTCB);
1002
1003
		/* We may have just resumed a higher priority task. */
1004
		if (pxTCB->uxPriority >= pxCurrentTCB->uxPriority)
1005
		  {
1006
		    /* This yield may not cause the task just resumed to run, but
1007
		       will leave the lists in the correct state for the next yield. */
1008
		    taskYIELD ();
1009
		  }
1010
	      }
1011
	  }
1012
      }
1013
      taskEXIT_CRITICAL ();
1014
    }
1015
}
1016
1017
#endif
1018
1019
/*-----------------------------------------------------------*/
1020
1021
#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
1022
1023
portBASE_TYPE
1024
xTaskResumeFromISR (xTaskHandle pxTaskToResume)
1025
{
1026
  portBASE_TYPE xYieldRequired = pdFALSE;
1027
  tskTCB *pxTCB;
1028
1029
  pxTCB = (tskTCB *) pxTaskToResume;
1030
1031
  /* Is the task we are attempting to resume actually suspended? */
1032
  if (listIS_CONTAINED_WITHIN
1033
      (&xSuspendedTaskList, &(pxTCB->xGenericListItem)) != pdFALSE)
1034
    {
1035
      /* Has the task already been resumed from within an ISR? */
1036
      if (listIS_CONTAINED_WITHIN
1037
	  (&xPendingReadyList, &(pxTCB->xEventListItem)) != pdTRUE)
1038
	{
1039
	  if (uxSchedulerSuspended == (unsigned portBASE_TYPE) pdFALSE)
1040
	    {
1041
	      xYieldRequired =
1042
		(pxTCB->uxPriority >= pxCurrentTCB->uxPriority);
1043
	      vListRemove (&(pxTCB->xGenericListItem));
1044
	      prvAddTaskToReadyQueue (pxTCB);
1045
	    }
1046
	  else
1047
	    {
1048
	      /* We cannot access the delayed or ready lists, so will hold this
1049
	         task pending until the scheduler is resumed, at which point a 
1050
	         yield will be preformed if necessary. */
1051
	      vListInsertEnd ((xList *) & (xPendingReadyList),
1052
			      &(pxTCB->xEventListItem));
1053
	    }
1054
	}
1055
    }
1056
1057
  return xYieldRequired;
1058
}
1059
1060
#endif
1061
1062
1063
1064
1065
/*-----------------------------------------------------------
1066
 * PUBLIC SCHEDULER CONTROL documented in task.h
1067
 *----------------------------------------------------------*/
1068
1069
1070
void
1071
vTaskStartScheduler (void)
1072
{
1073
  portBASE_TYPE xReturn;
1074
1075
  /* Add the idle task at the lowest priority. */
1076
  xReturn =
1077
    xTaskCreate (prvIdleTask, (signed portCHAR *) "IDLE", tskIDLE_STACK_SIZE,
1078
		 (void *) NULL, tskIDLE_PRIORITY, (xTaskHandle *) NULL);
1079
1080
  if (xReturn == pdPASS)
1081
    {
1082
      /* Interrupts are turned off here, to ensure a tick does not occur
1083
         before or during the call to xPortStartScheduler().  The stacks of
1084
         the created tasks contain a status word with interrupts switched on
1085
         so interrupts will automatically get re-enabled when the first task
1086
         starts to run.
1087
1088
         STEPPING THROUGH HERE USING A DEBUGGER CAN CAUSE BIG PROBLEMS IF THE
1089
         DEBUGGER ALLOWS INTERRUPTS TO BE PROCESSED. */
1090
      portDISABLE_INTERRUPTS ();
1091
1092
      xSchedulerRunning = pdTRUE;
1093
      xTickCount = (portTickType) 0;
1094
1095
      /* Setting up the timer tick is hardware specific and thus in the
1096
         portable interface. */
1097
      if (xPortStartScheduler ())
1098
	{
1099
	  /* Should not reach here as if the scheduler is running the
1100
	     function will not return. */
1101
	}
1102
      else
1103
	{
1104
	  /* Should only reach here if a task calls xTaskEndScheduler(). */
1105
	}
1106
    }
1107
}
1108
1109
/*-----------------------------------------------------------*/
1110
1111
void
1112
vTaskEndScheduler (void)
1113
{
1114
  /* Stop the scheduler interrupts and call the portable scheduler end
1115
     routine so the original ISRs can be restored if necessary.  The port
1116
     layer must ensure interrupts enable  bit is left in the correct state. */
1117
  portDISABLE_INTERRUPTS ();
1118
  xSchedulerRunning = pdFALSE;
1119
  vPortEndScheduler ();
1120
}
1121
1122
/*----------------------------------------------------------*/
1123
1124
void
1125
vTaskSuspendAll (void)
1126
{
1127
  portENTER_CRITICAL ();
1128
  ++uxSchedulerSuspended;
1129
  portEXIT_CRITICAL ();
1130
}
1131
1132
/*----------------------------------------------------------*/
1133
1134
signed portBASE_TYPE
1135
xTaskResumeAll (void)
1136
{
1137
  register tskTCB *pxTCB;
1138
  signed portBASE_TYPE xAlreadyYielded = pdFALSE;
1139
1140
  /* It is possible that an ISR caused a task to be removed from an event
1141
     list while the scheduler was suspended.  If this was the case then the
1142
     removed task will have been added to the xPendingReadyList.  Once the
1143
     scheduler has been resumed it is safe to move all the pending ready
1144
     tasks from this list into their appropriate ready list. */
1145
  portENTER_CRITICAL ();
1146
  {
1147
    --uxSchedulerSuspended;
1148
1149
    if (uxSchedulerSuspended == (unsigned portBASE_TYPE) pdFALSE)
1150
      {
1151
	if (uxCurrentNumberOfTasks > (unsigned portBASE_TYPE) 0)
1152
	  {
1153
	    portBASE_TYPE xYieldRequired = pdFALSE;
1154
1155
	    /* Move any readied tasks from the pending list into the
1156
	       appropriate ready list. */
1157
	    while ((pxTCB =
1158
		    (tskTCB *)
1159
		    listGET_OWNER_OF_HEAD_ENTRY (((xList *) &
1160
						  xPendingReadyList))) !=
1161
		   NULL)
1162
	      {
1163
		vListRemove (&(pxTCB->xEventListItem));
1164
		vListRemove (&(pxTCB->xGenericListItem));
1165
		prvAddTaskToReadyQueue (pxTCB);
1166
1167
		/* If we have moved a task that has a priority higher than
1168
		   the current task then we should yield. */
1169
		if (pxTCB->uxPriority >= pxCurrentTCB->uxPriority)
1170
		  {
1171
		    xYieldRequired = pdTRUE;
1172
		  }
1173
	      }
1174
1175
	    /* If any ticks occurred while the scheduler was suspended then
1176
	       they should be processed now.  This ensures the tick count does not
1177
	       slip, and that any delayed tasks are resumed at the correct time. */
1178
	    if (uxMissedTicks > (unsigned portBASE_TYPE) 0)
1179
	      {
1180
		while (uxMissedTicks > (unsigned portBASE_TYPE) 0)
1181
		  {
1182
		    vTaskIncrementTick ();
1183
		    --uxMissedTicks;
1184
		  }
1185
1186
		/* As we have processed some ticks it is appropriate to yield
1187
		   to ensure the highest priority task that is ready to run is
1188
		   the task actually running. */
1189
		xYieldRequired = pdTRUE;
1190
	      }
1191
1192
	    if ((xYieldRequired == pdTRUE) || (xMissedYield == pdTRUE))
1193
	      {
1194
		xAlreadyYielded = pdTRUE;
1195
		xMissedYield = pdFALSE;
1196
		taskYIELD ();
1197
	      }
1198
	  }
1199
      }
1200
  }
1201
  portEXIT_CRITICAL ();
1202
1203
  return xAlreadyYielded;
1204
}
1205
1206
1207
1208
1209
1210
1211
/*-----------------------------------------------------------
1212
 * PUBLIC TASK UTILITIES documented in task.h
1213
 *----------------------------------------------------------*/
1214
1215
1216
1217
portTickType
1218
xTaskGetTickCount (void)
1219
{
1220
  portTickType xTicks;
1221
1222
  /* Critical section required if running on a 16 bit processor. */
1223
  taskENTER_CRITICAL ();
1224
  {
1225
    xTicks = xTickCount;
1226
  }
1227
  taskEXIT_CRITICAL ();
1228
1229
  return xTicks;
1230
}
1231
1232
/*-----------------------------------------------------------*/
1233
1234
unsigned portBASE_TYPE
1235
uxTaskGetNumberOfTasks (void)
1236
{
1237
  unsigned portBASE_TYPE uxNumberOfTasks;
1238
1239
  taskENTER_CRITICAL ();
1240
  uxNumberOfTasks = uxCurrentNumberOfTasks;
1241
  taskEXIT_CRITICAL ();
1242
1243
  return uxNumberOfTasks;
1244
}
1245
1246
/*-----------------------------------------------------------*/
1247
1248
#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_vTaskDelete == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
1249
1250
void
1251
vTaskList (signed portCHAR * pcWriteBuffer)
1252
{
1253
  unsigned portBASE_TYPE uxQueue;
1254
1255
  /* This is a VERY costly function that should be used for debug only.
1256
     It leaves interrupts disabled for a LONG time. */
1257
1258
  vTaskSuspendAll ();
1259
  {
1260
    /* Run through all the lists that could potentially contain a TCB and
1261
       report the task name, state and stack high water mark. */
1262
1263
    pcWriteBuffer[0] = (signed portCHAR) 0x00;
1264
    strcat ((portCHAR *) pcWriteBuffer, (const portCHAR *) "\r\n");
1265
1266
    uxQueue = uxTopUsedPriority + 1;
1267
1268
    do
1269
      {
1270
	uxQueue--;
1271
1272
	if (!listLIST_IS_EMPTY (&(pxReadyTasksLists[uxQueue])))
1273
	  {
1274
	    prvListTaskWithinSingleList (pcWriteBuffer,
1275
					 (xList *) &
1276
					 (pxReadyTasksLists[uxQueue]),
1277
					 tskREADY_CHAR);
1278
	  }
1279
      }
1280
    while (uxQueue > (unsigned portSHORT) tskIDLE_PRIORITY);
1281
1282
    if (!listLIST_IS_EMPTY (pxDelayedTaskList))
1283
      {
1284
	prvListTaskWithinSingleList (pcWriteBuffer,
1285
				     (xList *) pxDelayedTaskList,
1286
				     tskBLOCKED_CHAR);
1287
      }
1288
1289
    if (!listLIST_IS_EMPTY (pxOverflowDelayedTaskList))
1290
      {
1291
	prvListTaskWithinSingleList (pcWriteBuffer,
1292
				     (xList *) pxOverflowDelayedTaskList,
1293
				     tskBLOCKED_CHAR);
1294
      }
1295
1296
    if (!listLIST_IS_EMPTY (&xTasksWaitingTermination))
1297
      {
1298
	prvListTaskWithinSingleList (pcWriteBuffer,
1299
				     (xList *) & xTasksWaitingTermination,
1300
				     tskDELETED_CHAR);
1301
      }
1302
1303
    if (!listLIST_IS_EMPTY (&xSuspendedTaskList))
1304
      {
1305
	prvListTaskWithinSingleList (pcWriteBuffer,
1306
				     (xList *) & xSuspendedTaskList,
1307
				     tskSUSPENDED_CHAR);
1308
      }
1309
  }
1310
  xTaskResumeAll ();
1311
}
1312
1313
#endif
1314
/*----------------------------------------------------------*/
1315
1316
#if ( configUSE_TRACE_FACILITY == 1 )
1317
1318
void
1319
vTaskStartTrace (signed portCHAR * pcBuffer, unsigned portLONG ulBufferSize)
1320
{
1321
  portENTER_CRITICAL ();
1322
  {
1323
    pcTraceBuffer = (volatile signed portCHAR * volatile) pcBuffer;
1324
    pcTraceBufferStart = pcBuffer;
1325
    pcTraceBufferEnd = pcBuffer + (ulBufferSize - tskSIZE_OF_EACH_TRACE_LINE);
1326
    xTracing = pdTRUE;
1327
  }
1328
  portEXIT_CRITICAL ();
1329
}
1330
1331
#endif
1332
/*----------------------------------------------------------*/
1333
1334
#if ( configUSE_TRACE_FACILITY == 1 )
1335
1336
unsigned portLONG
1337
ulTaskEndTrace (void)
1338
{
1339
  unsigned portLONG ulBufferLength;
1340
1341
  portENTER_CRITICAL ();
1342
  xTracing = pdFALSE;
1343
  portEXIT_CRITICAL ();
1344
1345
  ulBufferLength = (unsigned portLONG) (pcTraceBuffer - pcTraceBufferStart);
1346
1347
  return ulBufferLength;
1348
}
1349
1350
#endif
1351
1352
1353
1354
/*-----------------------------------------------------------
1355
 * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES
1356
 * documented in task.h
1357
 *----------------------------------------------------------*/
1358
1359
1360
inline void
1361
vTaskIncrementTick (void)
1362
{
1363
  /* Called by the portable layer each time a tick interrupt occurs.
1364
     Increments the tick then checks to see if the new tick value will cause any
1365
     tasks to be unblocked. */
1366
  if (uxSchedulerSuspended == (unsigned portBASE_TYPE) pdFALSE)
1367
    {
1368
      ++xTickCount;
1369
      if (xTickCount == (portTickType) 0)
1370
	{
1371
	  xList *pxTemp;
1372
1373
	  /* Tick count has overflowed so we need to swap the delay lists.  
1374
	     If there are any items in pxDelayedTaskList here then there is 
1375
	     an error! */
1376
	  pxTemp = pxDelayedTaskList;
1377
	  pxDelayedTaskList = pxOverflowDelayedTaskList;
1378
	  pxOverflowDelayedTaskList = pxTemp;
1379
	  xNumOfOverflows++;
1380
	}
1381
1382
      /* See if this tick has made a timeout expire. */
1383
      prvCheckDelayedTasks ();
1384
    }
1385
  else
1386
    {
1387
      ++uxMissedTicks;
1388
1389
      /* The tick hook gets called at regular intervals, even if the 
1390
         scheduler is locked. */
1391
#if ( configUSE_TICK_HOOK == 1 )
1392
      {
1393
	extern void vApplicationTickHook (void);
1394
1395
	vApplicationTickHook ();
1396
      }
1397
#endif
1398
    }
1399
1400
#if ( configUSE_TICK_HOOK == 1 )
1401
  {
1402
    extern void vApplicationTickHook (void);
1403
1404
    /* Guard against the tick hook being called when the missed tick
1405
       count is being unwound (when the scheduler is being unlocked. */
1406
    if (uxMissedTicks == 0)
1407
      {
1408
	vApplicationTickHook ();
1409
      }
1410
  }
1411
#endif
1412
}
1413
1414
/*-----------------------------------------------------------*/
1415
1416
#if ( ( INCLUDE_vTaskCleanUpResources == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
1417
1418
void
1419
vTaskCleanUpResources (void)
1420
{
1421
  unsigned portSHORT usQueue;
1422
  volatile tskTCB *pxTCB;
1423
1424
  usQueue = (unsigned portSHORT) uxTopUsedPriority + (unsigned portSHORT) 1;
1425
1426
  /* Remove any TCB's from the ready queues. */
1427
  do
1428
    {
1429
      usQueue--;
1430
1431
      while (!listLIST_IS_EMPTY (&(pxReadyTasksLists[usQueue])))
1432
	{
1433
	  listGET_OWNER_OF_NEXT_ENTRY (pxTCB, &(pxReadyTasksLists[usQueue]));
1434
	  vListRemove ((xListItem *) & (pxTCB->xGenericListItem));
1435
1436
	  prvDeleteTCB ((tskTCB *) pxTCB);
1437
	}
1438
    }
1439
  while (usQueue > (unsigned portSHORT) tskIDLE_PRIORITY);
1440
1441
  /* Remove any TCB's from the delayed queue. */
1442
  while (!listLIST_IS_EMPTY (&xDelayedTaskList1))
1443
    {
1444
      listGET_OWNER_OF_NEXT_ENTRY (pxTCB, &xDelayedTaskList1);
1445
      vListRemove ((xListItem *) & (pxTCB->xGenericListItem));
1446
1447
      prvDeleteTCB ((tskTCB *) pxTCB);
1448
    }
1449
1450
  /* Remove any TCB's from the overflow delayed queue. */
1451
  while (!listLIST_IS_EMPTY (&xDelayedTaskList2))
1452
    {
1453
      listGET_OWNER_OF_NEXT_ENTRY (pxTCB, &xDelayedTaskList2);
1454
      vListRemove ((xListItem *) & (pxTCB->xGenericListItem));
1455
1456
      prvDeleteTCB ((tskTCB *) pxTCB);
1457
    }
1458
1459
  while (!listLIST_IS_EMPTY (&xSuspendedTaskList))
1460
    {
1461
      listGET_OWNER_OF_NEXT_ENTRY (pxTCB, &xSuspendedTaskList);
1462
      vListRemove ((xListItem *) & (pxTCB->xGenericListItem));
1463
1464
      prvDeleteTCB ((tskTCB *) pxTCB);
1465
    }
1466
1467
  while (!listLIST_IS_EMPTY (&xPendingReadyList))
1468
    {
1469
      listGET_OWNER_OF_NEXT_ENTRY (pxTCB, &xPendingReadyList);
1470
      vListRemove ((xListItem *) & (pxTCB->xGenericListItem));
1471
1472
      prvDeleteTCB ((tskTCB *) pxTCB);
1473
    }
1474
}
1475
1476
#endif
1477
/*-----------------------------------------------------------*/
1478
1479
void
1480
vTaskSwitchContext (void)
1481
{
1482
  if (uxSchedulerSuspended != (unsigned portBASE_TYPE) pdFALSE)
1483
    {
1484
      /* The scheduler is currently suspended - do not allow a context
1485
         switch. */
1486
      xMissedYield = pdTRUE;
1487
      return;
1488
    }
1489
1490
  /* Find the highest priority queue that contains ready tasks. */
1491
  while (listLIST_IS_EMPTY (&(pxReadyTasksLists[uxTopReadyPriority])))
1492
    {
1493
      --uxTopReadyPriority;
1494
    }
1495
1496
  /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the tasks of the
1497
     same priority get an equal share of the processor time. */
1498
  listGET_OWNER_OF_NEXT_ENTRY (pxCurrentTCB,
1499
			       &(pxReadyTasksLists[uxTopReadyPriority]));
1500
  vWriteTraceToBuffer ();
1501
}
1502
1503
/*-----------------------------------------------------------*/
1504
1505
void
1506
vTaskPlaceOnEventList (xList * pxEventList, portTickType xTicksToWait)
1507
{
1508
  portTickType xTimeToWake;
1509
1510
  /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
1511
     SCHEDULER SUSPENDED. */
1512
1513
  /* Place the event list item of the TCB in the appropriate event list.
1514
     This is placed in the list in priority order so the highest priority task
1515
     is the first to be woken by the event. */
1516
  vListInsert ((xList *) pxEventList,
1517
	       (xListItem *) & (pxCurrentTCB->xEventListItem));
1518
1519
  /* We must remove ourselves from the ready list before adding ourselves
1520
     to the blocked list as the same list item is used for both lists.  We have
1521
     exclusive access to the ready lists as the scheduler is locked. */
1522
  vListRemove ((xListItem *) & (pxCurrentTCB->xGenericListItem));
1523
1524
1525
#if ( INCLUDE_vTaskSuspend == 1 )
1526
  {
1527
    if (xTicksToWait == portMAX_DELAY)
1528
      {
1529
	/* Add ourselves to the suspended task list instead of a delayed task
1530
	   list to ensure we are not woken by a timing event.  We will block
1531
	   indefinitely. */
1532
	vListInsertEnd ((xList *) & xSuspendedTaskList,
1533
			(xListItem *) & (pxCurrentTCB->xGenericListItem));
1534
      }
1535
    else
1536
      {
1537
	/* Calculate the time at which the task should be woken if the event does
1538
	   not occur.  This may overflow but this doesn't matter. */
1539
	xTimeToWake = xTickCount + xTicksToWait;
1540
1541
	listSET_LIST_ITEM_VALUE (&(pxCurrentTCB->xGenericListItem),
1542
				 xTimeToWake);
1543
1544
	if (xTimeToWake < xTickCount)
1545
	  {
1546
	    /* Wake time has overflowed.  Place this item in the overflow list. */
1547
	    vListInsert ((xList *) pxOverflowDelayedTaskList,
1548
			 (xListItem *) & (pxCurrentTCB->xGenericListItem));
1549
	  }
1550
	else
1551
	  {
1552
	    /* The wake time has not overflowed, so we can use the current block list. */
1553
	    vListInsert ((xList *) pxDelayedTaskList,
1554
			 (xListItem *) & (pxCurrentTCB->xGenericListItem));
1555
	  }
1556
      }
1557
  }
1558
#else
1559
  {
1560
    /* Calculate the time at which the task should be woken if the event does
1561
       not occur.  This may overflow but this doesn't matter. */
1562
    xTimeToWake = xTickCount + xTicksToWait;
1563
1564
    listSET_LIST_ITEM_VALUE (&(pxCurrentTCB->xGenericListItem), xTimeToWake);
1565
1566
    if (xTimeToWake < xTickCount)
1567
      {
1568
	/* Wake time has overflowed.  Place this item in the overflow list. */
1569
	vListInsert ((xList *) pxOverflowDelayedTaskList,
1570
		     (xListItem *) & (pxCurrentTCB->xGenericListItem));
1571
      }
1572
    else
1573
      {
1574
	/* The wake time has not overflowed, so we can use the current block list. */
1575
	vListInsert ((xList *) pxDelayedTaskList,
1576
		     (xListItem *) & (pxCurrentTCB->xGenericListItem));
1577
      }
1578
  }
1579
#endif
1580
}
1581
1582
/*-----------------------------------------------------------*/
1583
1584
signed portBASE_TYPE
1585
xTaskRemoveFromEventList (const xList * pxEventList)
1586
{
1587
  tskTCB *pxUnblockedTCB;
1588
  portBASE_TYPE xReturn;
1589
1590
  /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
1591
     SCHEDULER SUSPENDED.  It can also be called from within an ISR. */
1592
1593
  /* The event list is sorted in priority order, so we can remove the
1594
     first in the list, remove the TCB from the delayed list, and add
1595
     it to the ready list.
1596
1597
     If an event is for a queue that is locked then this function will never
1598
     get called - the lock count on the queue will get modified instead.  This
1599
     means we can always expect exclusive access to the event list here. */
1600
  pxUnblockedTCB = (tskTCB *) listGET_OWNER_OF_HEAD_ENTRY (pxEventList);
1601
  vListRemove (&(pxUnblockedTCB->xEventListItem));
1602
1603
  if (uxSchedulerSuspended == (unsigned portBASE_TYPE) pdFALSE)
1604
    {
1605
      vListRemove (&(pxUnblockedTCB->xGenericListItem));
1606
      prvAddTaskToReadyQueue (pxUnblockedTCB);
1607
    }
1608
  else
1609
    {
1610
      /* We cannot access the delayed or ready lists, so will hold this
1611
         task pending until the scheduler is resumed. */
1612
      vListInsertEnd ((xList *) & (xPendingReadyList),
1613
		      &(pxUnblockedTCB->xEventListItem));
1614
    }
1615
1616
  if (pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority)
1617
    {
1618
      /* Return true if the task removed from the event list has
1619
         a higher priority than the calling task.  This allows
1620
         the calling task to know if it should force a context
1621
         switch now. */
1622
      xReturn = pdTRUE;
1623
    }
1624
  else
1625
    {
1626
      xReturn = pdFALSE;
1627
    }
1628
1629
  return xReturn;
1630
}
1631
1632
/*-----------------------------------------------------------*/
1633
1634
void
1635
vTaskSetTimeOutState (xTimeOutType * pxTimeOut)
1636
{
1637
  pxTimeOut->xOverflowCount = xNumOfOverflows;
1638
  pxTimeOut->xTimeOnEntering = xTickCount;
1639
}
1640
1641
/*-----------------------------------------------------------*/
1642
1643
portBASE_TYPE
1644
xTaskCheckForTimeOut (xTimeOutType * pxTimeOut, portTickType * pxTicksToWait)
1645
{
1646
  portBASE_TYPE xReturn;
1647
1648
  if ((xNumOfOverflows != pxTimeOut->xOverflowCount)
1649
      && (xTickCount >= pxTimeOut->xTimeOnEntering))
1650
    {
1651
      /* The tick count is greater than the time at which vTaskSetTimeout() 
1652
         was called, but has also overflowed since vTaskSetTimeOut() was called.
1653
         It must have wrapped all the way around and gone past us again. This
1654
         passed since vTaskSetTimeout() was called. */
1655
      xReturn = pdTRUE;
1656
    }
1657
  else if ((xTickCount - pxTimeOut->xTimeOnEntering) < *pxTicksToWait)
1658
    {
1659
      /* Not a genuine timeout. Adjust parameters for time remaining. */
1660
      *pxTicksToWait -= (xTickCount - pxTimeOut->xTimeOnEntering);
1661
      vTaskSetTimeOutState (pxTimeOut);
1662
      xReturn = pdFALSE;
1663
    }
1664
  else
1665
    {
1666
      xReturn = pdTRUE;
1667
    }
1668
1669
  return xReturn;
1670
}
1671
1672
/*-----------------------------------------------------------*/
1673
1674
void
1675
vTaskMissedYield (void)
1676
{
1677
  xMissedYield = pdTRUE;
1678
}
1679
1680
/*
1681
 * -----------------------------------------------------------
1682
 * The Idle task.
1683
 * ----------------------------------------------------------
1684
 *
1685
 * The portTASK_FUNCTION() macro is used to allow port/compiler specific
1686
 * language extensions.  The equivalent prototype for this function is:
1687
 *
1688
 * void prvIdleTask( void *pvParameters );
1689
 *
1690
 */
1691
static
1692
portTASK_FUNCTION (prvIdleTask, pvParameters)
1693
{
1694
  /* Stop warnings. */
1695
  (void) pvParameters;
1696
1697
  for (;;)
1698
    {
1699
      /* See if any tasks have been deleted. */
1700
      prvCheckTasksWaitingTermination ();
1701
1702
#if ( configUSE_PREEMPTION == 0 )
1703
      {
1704
	/* If we are not using preemption we keep forcing a task switch to
1705
	   see if any other task has become available.  If we are using
1706
	   preemption we don't need to do this as any task becoming available
1707
	   will automatically get the processor anyway. */
1708
	taskYIELD ();
1709
      }
1710
#endif
1711
1712
#if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
1713
      {
1714
	/* When using preemption tasks of equal priority will be
1715
	   timesliced.  If a task that is sharing the idle priority is ready
1716
	   to run then the idle task should yield before the end of the
1717
	   timeslice.
1718
1719
	   A critical region is not required here as we are just reading from
1720
	   the list, and an occasional incorrect value will not matter.  If
1721
	   the ready list at the idle priority contains more than one task
1722
	   then a task other than the idle task is ready to execute. */
1723
	if (listCURRENT_LIST_LENGTH (&(pxReadyTasksLists[tskIDLE_PRIORITY])) >
1724
	    (unsigned portBASE_TYPE) 1)
1725
	  {
1726
	    taskYIELD ();
1727
	  }
1728
      }
1729
#endif
1730
1731
#if ( configUSE_IDLE_HOOK == 1 )
1732
      {
1733
	extern void vApplicationIdleHook (void);
1734
1735
	/* Call the user defined function from within the idle task.  This
1736
	   allows the application designer to add background functionality
1737
	   without the overhead of a separate task.
1738
	   NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
1739
	   CALL A FUNCTION THAT MIGHT BLOCK. */
1740
	vApplicationIdleHook ();
1741
      }
1742
#endif
1743
    }
1744
}				/*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */
1745
1746
1747
1748
1749
1750
1751
1752
/*-----------------------------------------------------------
1753
 * File private functions documented at the top of the file.
1754
 *----------------------------------------------------------*/
1755
1756
1757
1758
static void
1759
prvInitialiseTCBVariables (tskTCB * pxTCB, unsigned portSHORT usStackDepth,
1760
			   const signed portCHAR * const pcName,
1761
			   unsigned portBASE_TYPE uxPriority)
1762
{
1763
  pxTCB->usStackDepth = usStackDepth;
1764
1765
  /* Store the function name in the TCB. */
1766
  strncpy ((char *) pxTCB->pcTaskName, (const char *) pcName,
1767
	   (unsigned portSHORT) configMAX_TASK_NAME_LEN);
1768
  pxTCB->pcTaskName[(unsigned portSHORT) configMAX_TASK_NAME_LEN -
1769
		    (unsigned portSHORT) 1] = '\0';
1770
1771
  /* This is used as an array index so must ensure it's not too large. */
1772
  if (uxPriority >= configMAX_PRIORITIES)
1773
    {
1774
      uxPriority = configMAX_PRIORITIES - 1;
1775
    }
1776
1777
  pxTCB->uxPriority = uxPriority;
1778
1779
  vListInitialiseItem (&(pxTCB->xGenericListItem));
1780
  vListInitialiseItem (&(pxTCB->xEventListItem));
1781
1782
  /* Set the pxTCB as a link back from the xListItem.  This is so we can get
1783
     back to      the containing TCB from a generic item in a list. */
1784
  listSET_LIST_ITEM_OWNER (&(pxTCB->xGenericListItem), pxTCB);
1785
1786
  /* Event lists are always in priority order. */
1787
  listSET_LIST_ITEM_VALUE (&(pxTCB->xEventListItem),
1788
			   configMAX_PRIORITIES - (portTickType) uxPriority);
1789
  listSET_LIST_ITEM_OWNER (&(pxTCB->xEventListItem), pxTCB);
1790
}
1791
1792
/*-----------------------------------------------------------*/
1793
1794
static void
1795
prvInitialiseTaskLists (void)
1796
{
1797
  unsigned portBASE_TYPE uxPriority;
1798
1799
  for (uxPriority = 0; uxPriority < configMAX_PRIORITIES; uxPriority++)
1800
    {
1801
      vListInitialise ((xList *) & (pxReadyTasksLists[uxPriority]));
1802
    }
1803
1804
  vListInitialise ((xList *) & xDelayedTaskList1);
1805
  vListInitialise ((xList *) & xDelayedTaskList2);
1806
  vListInitialise ((xList *) & xPendingReadyList);
1807
1808
#if ( INCLUDE_vTaskDelete == 1 )
1809
  {
1810
    vListInitialise ((xList *) & xTasksWaitingTermination);
1811
  }
1812
#endif
1813
1814
#if ( INCLUDE_vTaskSuspend == 1 )
1815
  {
1816
    vListInitialise ((xList *) & xSuspendedTaskList);
1817
  }
1818
#endif
1819
1820
  /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
1821
     using list2. */
1822
  pxDelayedTaskList = &xDelayedTaskList1;
1823
  pxOverflowDelayedTaskList = &xDelayedTaskList2;
1824
}
1825
1826
/*-----------------------------------------------------------*/
1827
1828
static void
1829
prvCheckTasksWaitingTermination (void)
1830
{
1831
#if ( INCLUDE_vTaskDelete == 1 )
1832
  {
1833
    portBASE_TYPE xListIsEmpty;
1834
1835
    /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
1836
       too often in the idle task. */
1837
    if (uxTasksDeleted > (unsigned portBASE_TYPE) 0)
1838
      {
1839
	vTaskSuspendAll ();
1840
	xListIsEmpty = listLIST_IS_EMPTY (&xTasksWaitingTermination);
1841
	xTaskResumeAll ();
1842
1843
	if (!xListIsEmpty)
1844
	  {
1845
	    tskTCB *pxTCB;
1846
1847
	    portENTER_CRITICAL ();
1848
	    {
1849
	      pxTCB =
1850
		(tskTCB *)
1851
		listGET_OWNER_OF_HEAD_ENTRY (((xList *) &
1852
					      xTasksWaitingTermination));
1853
	      vListRemove (&(pxTCB->xGenericListItem));
1854
	      --uxCurrentNumberOfTasks;
1855
	      --uxTasksDeleted;
1856
	    }
1857
	    portEXIT_CRITICAL ();
1858
1859
	    prvDeleteTCB (pxTCB);
1860
	  }
1861
      }
1862
  }
1863
#endif
1864
}
1865
1866
/*-----------------------------------------------------------*/
1867
1868
static tskTCB *
1869
prvAllocateTCBAndStack (unsigned portSHORT usStackDepth)
1870
{
1871
  tskTCB *pxNewTCB;
1872
1873
  /* Allocate space for the TCB.  Where the memory comes from depends on
1874
     the implementation of the port malloc function. */
1875
  pxNewTCB = (tskTCB *) pvPortMalloc (sizeof (tskTCB));
1876
1877
  if (pxNewTCB != NULL)
1878
    {
1879
      /* Allocate space for the stack used by the task being created.
1880
         The base of the stack memory stored in the TCB so the task can
1881
         be deleted later if required. */
1882
      pxNewTCB->pxStack =
1883
	(portSTACK_TYPE *) pvPortMalloc (((size_t) usStackDepth) *
1884
					 sizeof (portSTACK_TYPE));
1885
1886
      if (pxNewTCB->pxStack == NULL)
1887
	{
1888
	  /* Could not allocate the stack.  Delete the allocated TCB. */
1889
	  vPortFree (pxNewTCB);
1890
	  pxNewTCB = NULL;
1891
	}
1892
      else
1893
	{
1894
	  /* Just to help debugging. */
1895
	  memset (pxNewTCB->pxStack, tskSTACK_FILL_BYTE,
1896
		  usStackDepth * sizeof (portSTACK_TYPE));
1897
	}
1898
    }
1899
1900
  return pxNewTCB;
1901
}
1902
1903
/*-----------------------------------------------------------*/
1904
1905
#if ( configUSE_TRACE_FACILITY == 1 )
1906
1907
static void
1908
prvListTaskWithinSingleList (signed portCHAR * pcWriteBuffer, xList * pxList,
1909
			     signed portCHAR cStatus)
1910
{
1911
  volatile tskTCB *pxNextTCB, *pxFirstTCB;
1912
  static portCHAR pcStatusString[50];
1913
  unsigned portSHORT usStackRemaining;
1914
1915
  /* Write the details of all the TCB's in pxList into the buffer. */
1916
  listGET_OWNER_OF_NEXT_ENTRY (pxFirstTCB, pxList);
1917
  do
1918
    {
1919
      listGET_OWNER_OF_NEXT_ENTRY (pxNextTCB, pxList);
1920
      usStackRemaining =
1921
	usTaskCheckFreeStackSpace ((unsigned portCHAR *) pxNextTCB->pxStack);
1922
      sprintf (pcStatusString, (portCHAR *) "%s\t\t%c\t%u\t%u\t%u\r\n",
1923
	       pxNextTCB->pcTaskName, cStatus,
1924
	       (unsigned int) pxNextTCB->uxPriority, usStackRemaining,
1925
	       (unsigned int) pxNextTCB->uxTCBNumber);
1926
      strcat ((portCHAR *) pcWriteBuffer, (portCHAR *) pcStatusString);
1927
1928
    }
1929
  while (pxNextTCB != pxFirstTCB);
1930
}
1931
1932
#endif
1933
/*-----------------------------------------------------------*/
1934
1935
#if ( configUSE_TRACE_FACILITY == 1 )
1936
unsigned portSHORT
1937
usTaskCheckFreeStackSpace (const unsigned portCHAR * pucStackByte)
1938
{
1939
  register unsigned portSHORT usCount = 0;
1940
1941
  while (*pucStackByte == tskSTACK_FILL_BYTE)
1942
    {
1943
      pucStackByte -= portSTACK_GROWTH;
1944
      usCount++;
1945
    }
1946
1947
  usCount /= sizeof (portSTACK_TYPE);
1948
1949
  return usCount;
1950
}
1951
#endif
1952
/*-----------------------------------------------------------*/
1953
1954
1955
1956
#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
1957
1958
static void
1959
prvDeleteTCB (tskTCB * pxTCB)
1960
{
1961
  /* Free up the memory allocated by the scheduler for the task.  It is up to
1962
     the task to free any memory allocated at the application level. */
1963
  vPortFree (pxTCB->pxStack);
1964
  vPortFree (pxTCB);
1965
}
1966
1967
#endif
1968
1969
1970
/*-----------------------------------------------------------*/
1971
1972
#if ( INCLUDE_xTaskGetCurrentTaskHandle == 1 )
1973
1974
xTaskHandle
1975
xTaskGetCurrentTaskHandle (void)
1976
{
1977
  xTaskHandle xReturn;
1978
1979
  portENTER_CRITICAL ();
1980
  {
1981
    xReturn = (xTaskHandle) pxCurrentTCB;
1982
  }
1983
  portEXIT_CRITICAL ();
1984
1985
  return xReturn;
1986
}
1987
1988
#endif
Add picture from clipboard (Maximum size: 48.8 MB)