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

Subversion Repositories openfire2

[/] [openfire2/] [trunk/] [sw/] [freertos/] [tasks.c] - Blame information for rev 4

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

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

powered by: WebSVN 2.1.0

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