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

Subversion Repositories openrisc

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

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

Line No. Rev Author Line
1 572 jeremybenn
/*
2
    FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd.
3
 
4
    ***************************************************************************
5
    *                                                                         *
6
    * If you are:                                                             *
7
    *                                                                         *
8
    *    + New to FreeRTOS,                                                   *
9
    *    + Wanting to learn FreeRTOS or multitasking in general quickly       *
10
    *    + Looking for basic training,                                        *
11
    *    + Wanting to improve your FreeRTOS skills and productivity           *
12
    *                                                                         *
13
    * then take a look at the FreeRTOS books - available as PDF or paperback  *
14
    *                                                                         *
15
    *        "Using the FreeRTOS Real Time Kernel - a Practical Guide"        *
16
    *                  http://www.FreeRTOS.org/Documentation                  *
17
    *                                                                         *
18
    * A pdf reference manual is also available.  Both are usually delivered   *
19
    * to your inbox within 20 minutes to two hours when purchased between 8am *
20
    * and 8pm GMT (although please allow up to 24 hours in case of            *
21
    * exceptional circumstances).  Thank you for your support!                *
22
    *                                                                         *
23
    ***************************************************************************
24
 
25
    This file is part of the FreeRTOS distribution.
26
 
27
    FreeRTOS is free software; you can redistribute it and/or modify it under
28
    the terms of the GNU General Public License (version 2) as published by the
29
    Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
30
    ***NOTE*** The exception to the GPL is included to allow you to distribute
31
    a combined work that includes FreeRTOS without being obliged to provide the
32
    source code for proprietary components outside of the FreeRTOS kernel.
33
    FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
34
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
35
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
36
    more details. You should have received a copy of the GNU General Public
37
    License and the FreeRTOS license exception along with FreeRTOS; if not it
38
    can be viewed here: http://www.freertos.org/a00114.html and also obtained
39
    by writing to Richard Barry, contact details for whom are available on the
40
    FreeRTOS WEB site.
41
 
42
    1 tab == 4 spaces!
43
 
44
    http://www.FreeRTOS.org - Documentation, latest information, license and
45
    contact details.
46
 
47
    http://www.SafeRTOS.com - A version that is certified for use in safety
48
    critical systems.
49
 
50
    http://www.OpenRTOS.com - Commercial support, development, porting,
51
    licensing and training services.
52
*/
53
 
54
 
55
#include <stdio.h>
56
#include <stdlib.h>
57
#include <string.h>
58
 
59
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
60
all the API functions to use the MPU wrappers.  That should only be done when
61
task.h is included from an application file. */
62
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
63
 
64
#include "FreeRTOS.h"
65
#include "task.h"
66
#include "StackMacros.h"
67
 
68
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
69
 
70
/*
71
 * Macro to define the amount of stack available to the idle task.
72
 */
73
#define tskIDLE_STACK_SIZE      configMINIMAL_STACK_SIZE
74
 
75
/*
76
 * Task control block.  A task control block (TCB) is allocated to each task,
77
 * and stores the context of the task.
78
 */
79
typedef struct tskTaskControlBlock
80
{
81
        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. */
82
 
83
        #if ( portUSING_MPU_WRAPPERS == 1 )
84
                xMPU_SETTINGS xMPUSettings;                             /*< The MPU settings are defined as part of the port layer.  THIS MUST BE THE SECOND MEMBER OF THE STRUCT. */
85
        #endif  
86
 
87
        xListItem                               xGenericListItem;       /*< List item used to place the TCB in ready and blocked queues. */
88
        xListItem                               xEventListItem;         /*< List item used to place the TCB in event lists. */
89
        unsigned portBASE_TYPE  uxPriority;                     /*< The priority of the task where 0 is the lowest priority. */
90
        portSTACK_TYPE                  *pxStack;                       /*< Points to the start of the stack. */
91
        signed char                             pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created.  Facilitates debugging only. */
92
 
93
        #if ( portSTACK_GROWTH > 0 )
94
                portSTACK_TYPE *pxEndOfStack;                   /*< Used for stack overflow checking on architectures where the stack grows up from low memory. */
95
        #endif
96
 
97
        #if ( portCRITICAL_NESTING_IN_TCB == 1 )
98
                unsigned portBASE_TYPE uxCriticalNesting;
99
        #endif
100
 
101
        #if ( configUSE_TRACE_FACILITY == 1 )
102
                unsigned portBASE_TYPE  uxTCBNumber;    /*< This is used for tracing the scheduler and making debugging easier only. */
103
        #endif
104
 
105
        #if ( configUSE_MUTEXES == 1 )
106
                unsigned portBASE_TYPE uxBasePriority;  /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
107
        #endif
108
 
109
        #if ( configUSE_APPLICATION_TASK_TAG == 1 )
110
                pdTASK_HOOK_CODE pxTaskTag;
111
        #endif
112
 
113
        #if ( configGENERATE_RUN_TIME_STATS == 1 )
114
                unsigned long ulRunTimeCounter;         /*< Used for calculating how much CPU time each task is utilising. */
115
        #endif
116
 
117
} tskTCB;
118
 
119
 
120
/*
121
 * Some kernel aware debuggers require data to be viewed to be global, rather
122
 * than file scope.
123
 */
124
#ifdef portREMOVE_STATIC_QUALIFIER
125
        #define static
126
#endif
127
 
128
/*lint -e956 */
129
PRIVILEGED_DATA tskTCB * volatile pxCurrentTCB = NULL;
130
 
131
/* Lists for ready and blocked tasks. --------------------*/
132
 
133
PRIVILEGED_DATA static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */
134
PRIVILEGED_DATA static xList xDelayedTaskList1;                                                 /*< Delayed tasks. */
135
PRIVILEGED_DATA static xList xDelayedTaskList2;                                                 /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
136
PRIVILEGED_DATA static xList * volatile pxDelayedTaskList ;                             /*< Points to the delayed task list currently being used. */
137
PRIVILEGED_DATA static xList * volatile pxOverflowDelayedTaskList;              /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
138
PRIVILEGED_DATA 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. */
139
 
140
#if ( INCLUDE_vTaskDelete == 1 )
141
 
142
        PRIVILEGED_DATA static volatile xList xTasksWaitingTermination;         /*< Tasks that have been deleted - but the their memory not yet freed. */
143
        PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTasksDeleted = ( unsigned portBASE_TYPE ) 0;
144
 
145
#endif
146
 
147
#if ( INCLUDE_vTaskSuspend == 1 )
148
 
149
        PRIVILEGED_DATA static xList xSuspendedTaskList;                                        /*< Tasks that are currently suspended. */
150
 
151
#endif
152
 
153
/* File private variables. --------------------------------*/
154
PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks   = ( unsigned portBASE_TYPE ) 0;
155
PRIVILEGED_DATA static volatile portTickType xTickCount                                                 = ( portTickType ) 0;
156
PRIVILEGED_DATA static unsigned portBASE_TYPE uxTopUsedPriority                                 = tskIDLE_PRIORITY;
157
PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTopReadyPriority               = tskIDLE_PRIORITY;
158
PRIVILEGED_DATA static volatile signed portBASE_TYPE xSchedulerRunning                  = pdFALSE;
159
PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxSchedulerSuspended             = ( unsigned portBASE_TYPE ) pdFALSE;
160
PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxMissedTicks                    = ( unsigned portBASE_TYPE ) 0;
161
PRIVILEGED_DATA static volatile portBASE_TYPE xMissedYield                                              = ( portBASE_TYPE ) pdFALSE;
162
PRIVILEGED_DATA static volatile portBASE_TYPE xNumOfOverflows                                   = ( portBASE_TYPE ) 0;
163
PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber                                              = ( unsigned portBASE_TYPE ) 0;
164
 
165
#if ( configGENERATE_RUN_TIME_STATS == 1 )
166
 
167
        PRIVILEGED_DATA static char pcStatsString[ 50 ] ;
168
        PRIVILEGED_DATA static unsigned long ulTaskSwitchedInTime = 0UL;        /*< Holds the value of a timer/counter the last time a task was switched in. */
169
        static void prvGenerateRunTimeStatsForTasksInList( const signed char *pcWriteBuffer, xList *pxList, unsigned long ulTotalRunTime ) PRIVILEGED_FUNCTION;
170
 
171
#endif
172
 
173
/* Debugging and trace facilities private variables and macros. ------------*/
174
 
175
/*
176
 * The value used to fill the stack of a task when the task is created.  This
177
 * is used purely for checking the high water mark for tasks.
178
 */
179
#define tskSTACK_FILL_BYTE      ( 0xa5 )
180
 
181
/*
182
 * Macros used by vListTask to indicate which state a task is in.
183
 */
184
#define tskBLOCKED_CHAR         ( ( signed char ) 'B' )
185
#define tskREADY_CHAR           ( ( signed char ) 'R' )
186
#define tskDELETED_CHAR         ( ( signed char ) 'D' )
187
#define tskSUSPENDED_CHAR       ( ( signed char ) 'S' )
188
 
189
/*
190
 * Macros and private variables used by the trace facility.
191
 */
192
#if ( configUSE_TRACE_FACILITY == 1 )
193
 
194
        #define tskSIZE_OF_EACH_TRACE_LINE                      ( ( unsigned long ) ( sizeof( unsigned long ) + sizeof( unsigned long ) ) )
195
        PRIVILEGED_DATA static volatile signed char * volatile pcTraceBuffer;
196
        PRIVILEGED_DATA static signed char *pcTraceBufferStart;
197
        PRIVILEGED_DATA static signed char *pcTraceBufferEnd;
198
        PRIVILEGED_DATA static signed portBASE_TYPE xTracing = pdFALSE;
199
        static unsigned portBASE_TYPE uxPreviousTask = 255;
200
        PRIVILEGED_DATA static char pcStatusString[ 50 ];
201
 
202
#endif
203
 
204
/*-----------------------------------------------------------*/
205
 
206
/*
207
 * Macro that writes a trace of scheduler activity to a buffer.  This trace
208
 * shows which task is running when and is very useful as a debugging tool.
209
 * As this macro is called each context switch it is a good idea to undefine
210
 * it if not using the facility.
211
 */
212
#if ( configUSE_TRACE_FACILITY == 1 )
213
 
214
        #define vWriteTraceToBuffer()                                                                                                                                   \
215
        {                                                                                                                                                                                               \
216
                if( xTracing )                                                                                                                                                          \
217
                {                                                                                                                                                                                       \
218
                        if( uxPreviousTask != pxCurrentTCB->uxTCBNumber )                                                                               \
219
                        {                                                                                                                                                                               \
220
                                if( ( pcTraceBuffer + tskSIZE_OF_EACH_TRACE_LINE ) < pcTraceBufferEnd )                         \
221
                                {                                                                                                                                                                       \
222
                                        uxPreviousTask = pxCurrentTCB->uxTCBNumber;                                                                             \
223
                                        *( unsigned long * ) pcTraceBuffer = ( unsigned long ) xTickCount;              \
224
                                        pcTraceBuffer += sizeof( unsigned long );                                                                       \
225
                                        *( unsigned long * ) pcTraceBuffer = ( unsigned long ) uxPreviousTask;  \
226
                                        pcTraceBuffer += sizeof( unsigned long );                                                                       \
227
                                }                                                                                                                                                                       \
228
                                else                                                                                                                                                            \
229
                                {                                                                                                                                                                       \
230
                                        xTracing = pdFALSE;                                                                                                                             \
231
                                }                                                                                                                                                                       \
232
                        }                                                                                                                                                                               \
233
                }                                                                                                                                                                                       \
234
        }
235
 
236
#else
237
 
238
        #define vWriteTraceToBuffer()
239
 
240
#endif
241
/*-----------------------------------------------------------*/
242
 
243
/*
244
 * Place the task represented by pxTCB into the appropriate ready queue for
245
 * the task.  It is inserted at the end of the list.  One quirk of this is
246
 * that if the task being inserted is at the same priority as the currently
247
 * executing task, then it will only be rescheduled after the currently
248
 * executing task has been rescheduled.
249
 */
250
#define prvAddTaskToReadyQueue( pxTCB )                                                                                                                                                 \
251
{                                                                                                                                                                                                                               \
252
        if( pxTCB->uxPriority > uxTopReadyPriority )                                                                                                                            \
253
        {                                                                                                                                                                                                                       \
254
                uxTopReadyPriority = pxTCB->uxPriority;                                                                                                                                 \
255
        }                                                                                                                                                                                                                       \
256
        vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) );        \
257
}
258
/*-----------------------------------------------------------*/
259
 
260
/*
261
 * Macro that looks at the list of tasks that are currently delayed to see if
262
 * any require waking.
263
 *
264
 * Tasks are stored in the queue in the order of their wake time - meaning
265
 * once one tasks has been found whose timer has not expired we need not look
266
 * any further down the list.
267
 */
268
#define prvCheckDelayedTasks()                                                                                                                                                                          \
269
{                                                                                                                                                                                                                                       \
270
register tskTCB *pxTCB;                                                                                                                                                                                         \
271
                                                                                                                                                                                                                                        \
272
        while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ) ) != NULL )                                              \
273
        {                                                                                                                                                                                                                               \
274
                if( xTickCount < listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ) )                                                                      \
275
                {                                                                                                                                                                                                                       \
276
                        break;                                                                                                                                                                                                  \
277
                }                                                                                                                                                                                                                       \
278
                vListRemove( &( pxTCB->xGenericListItem ) );                                                                                                                            \
279
                /* Is the task waiting on an event also? */                                                                                                                                     \
280
                if( pxTCB->xEventListItem.pvContainer )                                                                                                                                         \
281
                {                                                                                                                                                                                                                       \
282
                        vListRemove( &( pxTCB->xEventListItem ) );                                                                                                                              \
283
                }                                                                                                                                                                                                                       \
284
                prvAddTaskToReadyQueue( pxTCB );                                                                                                                                                        \
285
        }                                                                                                                                                                                                                               \
286
}
287
/*-----------------------------------------------------------*/
288
 
289
/*
290
 * Several functions take an xTaskHandle parameter that can optionally be NULL,
291
 * where NULL is used to indicate that the handle of the currently executing
292
 * task should be used in place of the parameter.  This macro simply checks to
293
 * see if the parameter is NULL and returns a pointer to the appropriate TCB.
294
 */
295
#define prvGetTCBFromHandle( pxHandle ) ( ( pxHandle == NULL ) ? ( tskTCB * ) pxCurrentTCB : ( tskTCB * ) pxHandle )
296
 
297
 
298
/* File private functions. --------------------------------*/
299
 
300
/*
301
 * Utility to ready a TCB for a given task.  Mainly just copies the parameters
302
 * into the TCB structure.
303
 */
304
static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth ) PRIVILEGED_FUNCTION;
305
 
306
/*
307
 * Utility to ready all the lists used by the scheduler.  This is called
308
 * automatically upon the creation of the first task.
309
 */
310
static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION;
311
 
312
/*
313
 * The idle task, which as all tasks is implemented as a never ending loop.
314
 * The idle task is automatically created and added to the ready lists upon
315
 * creation of the first user task.
316
 *
317
 * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific
318
 * language extensions.  The equivalent prototype for this function is:
319
 *
320
 * void prvIdleTask( void *pvParameters );
321
 *
322
 */
323
static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters );
324
 
325
/*
326
 * Utility to free all memory allocated by the scheduler to hold a TCB,
327
 * including the stack pointed to by the TCB.
328
 *
329
 * This does not free memory allocated by the task itself (i.e. memory
330
 * allocated by calls to pvPortMalloc from within the tasks application code).
331
 */
332
#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
333
 
334
        static void prvDeleteTCB( tskTCB *pxTCB ) PRIVILEGED_FUNCTION;
335
 
336
#endif
337
 
338
/*
339
 * Used only by the idle task.  This checks to see if anything has been placed
340
 * in the list of tasks waiting to be deleted.  If so the task is cleaned up
341
 * and its TCB deleted.
342
 */
343
static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION;
344
 
345
/*
346
 * Allocates memory from the heap for a TCB and associated stack.  Checks the
347
 * allocation was successful.
348
 */
349
static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer ) PRIVILEGED_FUNCTION;
350
 
351
/*
352
 * Called from vTaskList.  vListTasks details all the tasks currently under
353
 * control of the scheduler.  The tasks may be in one of a number of lists.
354
 * prvListTaskWithinSingleList accepts a list and details the tasks from
355
 * within just that list.
356
 *
357
 * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM
358
 * NORMAL APPLICATION CODE.
359
 */
360
#if ( configUSE_TRACE_FACILITY == 1 )
361
 
362
        static void prvListTaskWithinSingleList( const signed char *pcWriteBuffer, xList *pxList, signed char cStatus ) PRIVILEGED_FUNCTION;
363
 
364
#endif
365
 
366
/*
367
 * When a task is created, the stack of the task is filled with a known value.
368
 * This function determines the 'high water mark' of the task stack by
369
 * determining how much of the stack remains at the original preset value.
370
 */
371
#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
372
 
373
        static unsigned short usTaskCheckFreeStackSpace( const unsigned char * pucStackByte ) PRIVILEGED_FUNCTION;
374
 
375
#endif
376
 
377
 
378
/*lint +e956 */
379
 
380
 
381
 
382
/*-----------------------------------------------------------
383
 * TASK CREATION API documented in task.h
384
 *----------------------------------------------------------*/
385
 
386
signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion * const xRegions )
387
{
388
signed portBASE_TYPE xReturn;
389
tskTCB * pxNewTCB;
390
 
391
        /* Allocate the memory required by the TCB and stack for the new task,
392
        checking that the allocation was successful. */
393
        pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer );
394
 
395
        if( pxNewTCB != NULL )
396
        {
397
                portSTACK_TYPE *pxTopOfStack;
398
 
399
                #if( portUSING_MPU_WRAPPERS == 1 )
400
                        /* Should the task be created in privileged mode? */
401
                        portBASE_TYPE xRunPrivileged;
402
                        if( ( uxPriority & portPRIVILEGE_BIT ) != 0x00 )
403
                        {
404
                                xRunPrivileged = pdTRUE;
405
                        }
406
                        else
407
                        {
408
                                xRunPrivileged = pdFALSE;
409
                        }
410
                        uxPriority &= ~portPRIVILEGE_BIT;
411
                #endif /* portUSING_MPU_WRAPPERS == 1 */
412
 
413
                /* Calculate the top of stack address.  This depends on whether the
414
                stack grows from high memory to low (as per the 80x86) or visa versa.
415
                portSTACK_GROWTH is used to make the result positive or negative as
416
                required by the port. */
417
                #if( portSTACK_GROWTH < 0 )
418
                {
419
                        pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
420
                        pxTopOfStack = ( portSTACK_TYPE * ) ( ( ( unsigned long ) pxTopOfStack ) & ( ( unsigned long ) ~portBYTE_ALIGNMENT_MASK  ) );
421
                }
422
                #else
423
                {
424
                        pxTopOfStack = pxNewTCB->pxStack;
425
 
426
                        /* If we want to use stack checking on architectures that use
427
                        a positive stack growth direction then we also need to store the
428
                        other extreme of the stack space. */
429
                        pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
430
                }
431
                #endif
432
 
433
                /* Setup the newly allocated TCB with the initial state of the task. */
434
                prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth );
435
 
436
                /* Initialize the TCB stack to look as if the task was already running,
437
                but had been interrupted by the scheduler.  The return address is set
438
                to the start of the task function. Once the stack has been initialised
439
                the     top of stack variable is updated. */
440
                #if( portUSING_MPU_WRAPPERS == 1 )
441
                {
442
                        pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
443
                }
444
                #else
445
                {
446
                        pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
447
                }
448
                #endif
449
 
450
                if( ( void * ) pxCreatedTask != NULL )
451
                {
452
                        /* Pass the TCB out - in an anonymous way.  The calling function/
453
                        task can use this as a handle to delete the task later if
454
                        required.*/
455
                        *pxCreatedTask = ( xTaskHandle ) pxNewTCB;
456
                }
457
 
458
                /* We are going to manipulate the task queues to add this task to a
459
                ready list, so must make sure no interrupts occur. */
460
                portENTER_CRITICAL();
461
                {
462
                        uxCurrentNumberOfTasks++;
463
                        if( pxCurrentTCB == NULL )
464
                        {
465
                                /* There are no other tasks, or all the other tasks are in
466
                                the suspended state - make this the current task. */
467
                                pxCurrentTCB =  pxNewTCB;
468
 
469
                                if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )
470
                                {
471
                                        /* This is the first task to be created so do the preliminary
472
                                        initialisation required.  We will not recover if this call
473
                                        fails, but we will report the failure. */
474
                                        prvInitialiseTaskLists();
475
                                }
476
                        }
477
                        else
478
                        {
479
                                /* If the scheduler is not already running, make this task the
480
                                current task if it is the highest priority task to be created
481
                                so far. */
482
                                if( xSchedulerRunning == pdFALSE )
483
                                {
484
                                        if( pxCurrentTCB->uxPriority <= uxPriority )
485
                                        {
486
                                                pxCurrentTCB = pxNewTCB;
487
                                        }
488
                                }
489
                        }
490
 
491
                        /* Remember the top priority to make context switching faster.  Use
492
                        the priority in pxNewTCB as this has been capped to a valid value. */
493
                        if( pxNewTCB->uxPriority > uxTopUsedPriority )
494
                        {
495
                                uxTopUsedPriority = pxNewTCB->uxPriority;
496
                        }
497
 
498
                        #if ( configUSE_TRACE_FACILITY == 1 )
499
                        {
500
                                /* Add a counter into the TCB for tracing only. */
501
                                pxNewTCB->uxTCBNumber = uxTaskNumber;
502
                        }
503
                        #endif
504
                        uxTaskNumber++;
505
 
506
                        prvAddTaskToReadyQueue( pxNewTCB );
507
 
508
                        xReturn = pdPASS;
509
                        traceTASK_CREATE( pxNewTCB );
510
                }
511
                portEXIT_CRITICAL();
512
        }
513
        else
514
        {
515
                xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
516
                traceTASK_CREATE_FAILED();
517
        }
518
 
519
        if( xReturn == pdPASS )
520
        {
521
                if( xSchedulerRunning != pdFALSE )
522
                {
523
                        /* If the created task is of a higher priority than the current task
524
                        then it should run now. */
525
                        if( pxCurrentTCB->uxPriority < uxPriority )
526
                        {
527
                                portYIELD_WITHIN_API();
528
                        }
529
                }
530
        }
531
 
532
        return xReturn;
533
}
534
/*-----------------------------------------------------------*/
535
 
536
#if ( INCLUDE_vTaskDelete == 1 )
537
 
538
        void vTaskDelete( xTaskHandle pxTaskToDelete )
539
        {
540
        tskTCB *pxTCB;
541
 
542
                portENTER_CRITICAL();
543
                {
544
                        /* Ensure a yield is performed if the current task is being
545
                        deleted. */
546
                        if( pxTaskToDelete == pxCurrentTCB )
547
                        {
548
                                pxTaskToDelete = NULL;
549
                        }
550
 
551
                        /* If null is passed in here then we are deleting ourselves. */
552
                        pxTCB = prvGetTCBFromHandle( pxTaskToDelete );
553
 
554
                        /* Remove task from the ready list and place in the     termination list.
555
                        This will stop the task from be scheduled.  The idle task will check
556
                        the termination list and free up any memory allocated by the
557
                        scheduler for the TCB and stack. */
558
                        vListRemove( &( pxTCB->xGenericListItem ) );
559
 
560
                        /* Is the task waiting on an event also? */
561
                        if( pxTCB->xEventListItem.pvContainer )
562
                        {
563
                                vListRemove( &( pxTCB->xEventListItem ) );
564
                        }
565
 
566
                        vListInsertEnd( ( xList * ) &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );
567
 
568
                        /* Increment the ucTasksDeleted variable so the idle task knows
569
                        there is a task that has been deleted and that it should therefore
570
                        check the xTasksWaitingTermination list. */
571
                        ++uxTasksDeleted;
572
 
573
                        /* Increment the uxTaskNumberVariable also so kernel aware debuggers
574
                        can detect that the task lists need re-generating. */
575
                        uxTaskNumber++;
576
 
577
                        traceTASK_DELETE( pxTCB );
578
                }
579
                portEXIT_CRITICAL();
580
 
581
                /* Force a reschedule if we have just deleted the current task. */
582
                if( xSchedulerRunning != pdFALSE )
583
                {
584
                        if( ( void * ) pxTaskToDelete == NULL )
585
                        {
586
                                portYIELD_WITHIN_API();
587
                        }
588
                }
589
        }
590
 
591
#endif
592
 
593
 
594
 
595
 
596
 
597
 
598
/*-----------------------------------------------------------
599
 * TASK CONTROL API documented in task.h
600
 *----------------------------------------------------------*/
601
 
602
#if ( INCLUDE_vTaskDelayUntil == 1 )
603
 
604
        void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement )
605
        {
606
        portTickType xTimeToWake;
607
        portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE;
608
 
609
                vTaskSuspendAll();
610
                {
611
                        /* Generate the tick time at which the task wants to wake. */
612
                        xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
613
 
614
                        if( xTickCount < *pxPreviousWakeTime )
615
                        {
616
                                /* The tick count has overflowed since this function was
617
                                lasted called.  In this case the only time we should ever
618
                                actually delay is if the wake time has also     overflowed,
619
                                and the wake time is greater than the tick time.  When this
620
                                is the case it is as if neither time had overflowed. */
621
                                if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xTickCount ) )
622
                                {
623
                                        xShouldDelay = pdTRUE;
624
                                }
625
                        }
626
                        else
627
                        {
628
                                /* The tick time has not overflowed.  In this case we will
629
                                delay if either the wake time has overflowed, and/or the
630
                                tick time is less than the wake time. */
631
                                if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xTickCount ) )
632
                                {
633
                                        xShouldDelay = pdTRUE;
634
                                }
635
                        }
636
 
637
                        /* Update the wake time ready for the next call. */
638
                        *pxPreviousWakeTime = xTimeToWake;
639
 
640
                        if( xShouldDelay )
641
                        {
642
                                traceTASK_DELAY_UNTIL();
643
 
644
                                /* We must remove ourselves from the ready list before adding
645
                                ourselves to the blocked list as the same list item is used for
646
                                both lists. */
647
                                vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
648
 
649
                                /* The list item will be inserted in wake time order. */
650
                                listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
651
 
652
                                if( xTimeToWake < xTickCount )
653
                                {
654
                                        /* Wake time has overflowed.  Place this item in the
655
                                        overflow list. */
656
                                        vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
657
                                }
658
                                else
659
                                {
660
                                        /* The wake time has not overflowed, so we can use the
661
                                        current block list. */
662
                                        vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
663
                                }
664
                        }
665
                }
666
                xAlreadyYielded = xTaskResumeAll();
667
 
668
                /* Force a reschedule if xTaskResumeAll has not already done so, we may
669
                have put ourselves to sleep. */
670
                if( !xAlreadyYielded )
671
                {
672
                        portYIELD_WITHIN_API();
673
                }
674
        }
675
 
676
#endif
677
/*-----------------------------------------------------------*/
678
 
679
#if ( INCLUDE_vTaskDelay == 1 )
680
 
681
        void vTaskDelay( portTickType xTicksToDelay )
682
        {
683
        portTickType xTimeToWake;
684
        signed portBASE_TYPE xAlreadyYielded = pdFALSE;
685
 
686
                /* A delay time of zero just forces a reschedule. */
687
                if( xTicksToDelay > ( portTickType ) 0 )
688
                {
689
                        vTaskSuspendAll();
690
                        {
691
                                traceTASK_DELAY();
692
 
693
                                /* A task that is removed from the event list while the
694
                                scheduler is suspended will not get placed in the ready
695
                                list or removed from the blocked list until the scheduler
696
                                is resumed.
697
 
698
                                This task cannot be in an event list as it is the currently
699
                                executing task. */
700
 
701
                                /* Calculate the time to wake - this may overflow but this is
702
                                not a problem. */
703
                                xTimeToWake = xTickCount + xTicksToDelay;
704
 
705
                                /* We must remove ourselves from the ready list before adding
706
                                ourselves to the blocked list as the same list item is used for
707
                                both lists. */
708
                                vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
709
 
710
                                /* The list item will be inserted in wake time order. */
711
                                listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
712
 
713
                                if( xTimeToWake < xTickCount )
714
                                {
715
                                        /* Wake time has overflowed.  Place this item in the
716
                                        overflow list. */
717
                                        vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
718
                                }
719
                                else
720
                                {
721
                                        /* The wake time has not overflowed, so we can use the
722
                                        current block list. */
723
                                        vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
724
                                }
725
                        }
726
                        xAlreadyYielded = xTaskResumeAll();
727
                }
728
 
729
                /* Force a reschedule if xTaskResumeAll has not already done so, we may
730
                have put ourselves to sleep. */
731
                if( !xAlreadyYielded )
732
                {
733
                        portYIELD_WITHIN_API();
734
                }
735
        }
736
 
737
#endif
738
/*-----------------------------------------------------------*/
739
 
740
#if ( INCLUDE_uxTaskPriorityGet == 1 )
741
 
742
        unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask )
743
        {
744
        tskTCB *pxTCB;
745
        unsigned portBASE_TYPE uxReturn;
746
 
747
                portENTER_CRITICAL();
748
                {
749
                        /* If null is passed in here then we are changing the
750
                        priority of the calling function. */
751
                        pxTCB = prvGetTCBFromHandle( pxTask );
752
                        uxReturn = pxTCB->uxPriority;
753
                }
754
                portEXIT_CRITICAL();
755
 
756
                return uxReturn;
757
        }
758
 
759
#endif
760
/*-----------------------------------------------------------*/
761
 
762
#if ( INCLUDE_vTaskPrioritySet == 1 )
763
 
764
        void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority )
765
        {
766
        tskTCB *pxTCB;
767
        unsigned portBASE_TYPE uxCurrentPriority, xYieldRequired = pdFALSE;
768
 
769
                /* Ensure the new priority is valid. */
770
                if( uxNewPriority >= configMAX_PRIORITIES )
771
                {
772
                        uxNewPriority = configMAX_PRIORITIES - 1;
773
                }
774
 
775
                portENTER_CRITICAL();
776
                {
777
                        if( pxTask == pxCurrentTCB )
778
                        {
779
                                pxTask = NULL;
780
                        }
781
 
782
                        /* If null is passed in here then we are changing the
783
                        priority of the calling function. */
784
                        pxTCB = prvGetTCBFromHandle( pxTask );
785
 
786
                        traceTASK_PRIORITY_SET( pxTask, uxNewPriority );
787
 
788
                        #if ( configUSE_MUTEXES == 1 )
789
                        {
790
                                uxCurrentPriority = pxTCB->uxBasePriority;
791
                        }
792
                        #else
793
                        {
794
                                uxCurrentPriority = pxTCB->uxPriority;
795
                        }
796
                        #endif
797
 
798
                        if( uxCurrentPriority != uxNewPriority )
799
                        {
800
                                /* The priority change may have readied a task of higher
801
                                priority than the calling task. */
802
                                if( uxNewPriority > uxCurrentPriority )
803
                                {
804
                                        if( pxTask != NULL )
805
                                        {
806
                                                /* The priority of another task is being raised.  If we
807
                                                were raising the priority of the currently running task
808
                                                there would be no need to switch as it must have already
809
                                                been the highest priority task. */
810
                                                xYieldRequired = pdTRUE;
811
                                        }
812
                                }
813
                                else if( pxTask == NULL )
814
                                {
815
                                        /* Setting our own priority down means there may now be another
816
                                        task of higher priority that is ready to execute. */
817
                                        xYieldRequired = pdTRUE;
818
                                }
819
 
820
 
821
 
822
                                #if ( configUSE_MUTEXES == 1 )
823
                                {
824
                                        /* Only change the priority being used if the task is not
825
                                        currently using an inherited priority. */
826
                                        if( pxTCB->uxBasePriority == pxTCB->uxPriority )
827
                                        {
828
                                                pxTCB->uxPriority = uxNewPriority;
829
                                        }
830
 
831
                                        /* The base priority gets set whatever. */
832
                                        pxTCB->uxBasePriority = uxNewPriority;
833
                                }
834
                                #else
835
                                {
836
                                        pxTCB->uxPriority = uxNewPriority;
837
                                }
838
                                #endif
839
 
840
                                listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( configMAX_PRIORITIES - ( portTickType ) uxNewPriority ) );
841
 
842
                                /* If the task is in the blocked or suspended list we need do
843
                                nothing more than change it's priority variable. However, if
844
                                the task is in a ready list it needs to be removed and placed
845
                                in the queue appropriate to its new priority. */
846
                                if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxCurrentPriority ] ), &( pxTCB->xGenericListItem ) ) )
847
                                {
848
                                        /* The task is currently in its ready list - remove before adding
849
                                        it to it's new ready list.  As we are in a critical section we
850
                                        can do this even if the scheduler is suspended. */
851
                                        vListRemove( &( pxTCB->xGenericListItem ) );
852
                                        prvAddTaskToReadyQueue( pxTCB );
853
                                }
854
 
855
                                if( xYieldRequired == pdTRUE )
856
                                {
857
                                        portYIELD_WITHIN_API();
858
                                }
859
                        }
860
                }
861
                portEXIT_CRITICAL();
862
        }
863
 
864
#endif
865
/*-----------------------------------------------------------*/
866
 
867
#if ( INCLUDE_vTaskSuspend == 1 )
868
 
869
        void vTaskSuspend( xTaskHandle pxTaskToSuspend )
870
        {
871
        tskTCB *pxTCB;
872
 
873
                portENTER_CRITICAL();
874
                {
875
                        /* Ensure a yield is performed if the current task is being
876
                        suspended. */
877
                        if( pxTaskToSuspend == pxCurrentTCB )
878
                        {
879
                                pxTaskToSuspend = NULL;
880
                        }
881
 
882
                        /* If null is passed in here then we are suspending ourselves. */
883
                        pxTCB = prvGetTCBFromHandle( pxTaskToSuspend );
884
 
885
                        traceTASK_SUSPEND( pxTCB );
886
 
887
                        /* Remove task from the ready/delayed list and place in the     suspended list. */
888
                        vListRemove( &( pxTCB->xGenericListItem ) );
889
 
890
                        /* Is the task waiting on an event also? */
891
                        if( pxTCB->xEventListItem.pvContainer )
892
                        {
893
                                vListRemove( &( pxTCB->xEventListItem ) );
894
                        }
895
 
896
                        vListInsertEnd( ( xList * ) &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );
897
                }
898
                portEXIT_CRITICAL();
899
 
900
                if( ( void * ) pxTaskToSuspend == NULL )
901
                {
902
                        if( xSchedulerRunning != pdFALSE )
903
                        {
904
                                /* We have just suspended the current task. */
905
                                portYIELD_WITHIN_API();
906
                        }
907
                        else
908
                        {
909
                                /* The scheduler is not running, but the task that was pointed
910
                                to by pxCurrentTCB has just been suspended and pxCurrentTCB
911
                                must be adjusted to point to a different task. */
912
                                if( uxCurrentNumberOfTasks == 1 )
913
                                {
914
                                        /* No other tasks are defined, so set pxCurrentTCB back to
915
                                        NULL so when the next task is created pxCurrentTCB will
916
                                        be set to point to it no matter what its relative priority
917
                                        is. */
918
                                        pxCurrentTCB = NULL;
919
                                }
920
                                else
921
                                {
922
                                        vTaskSwitchContext();
923
                                }
924
                        }
925
                }
926
        }
927
 
928
#endif
929
/*-----------------------------------------------------------*/
930
 
931
#if ( INCLUDE_vTaskSuspend == 1 )
932
 
933
        signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask )
934
        {
935
        portBASE_TYPE xReturn = pdFALSE;
936
        const tskTCB * const pxTCB = ( tskTCB * ) xTask;
937
 
938
                /* Is the task we are attempting to resume actually in the
939
                suspended list? */
940
                if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE )
941
                {
942
                        /* Has the task already been resumed from within an ISR? */
943
                        if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) != pdTRUE )
944
                        {
945
                                /* Is it in the suspended list because it is in the
946
                                Suspended state?  It is possible to be in the suspended
947
                                list because it is blocked on a task with no timeout
948
                                specified. */
949
                                if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) == pdTRUE )
950
                                {
951
                                        xReturn = pdTRUE;
952
                                }
953
                        }
954
                }
955
 
956
                return xReturn;
957
        }
958
 
959
#endif
960
/*-----------------------------------------------------------*/
961
 
962
#if ( INCLUDE_vTaskSuspend == 1 )
963
 
964
        void vTaskResume( xTaskHandle pxTaskToResume )
965
        {
966
        tskTCB *pxTCB;
967
 
968
                /* Remove the task from whichever list it is currently in, and place
969
                it in the ready list. */
970
                pxTCB = ( tskTCB * ) pxTaskToResume;
971
 
972
                /* The parameter cannot be NULL as it is impossible to resume the
973
                currently executing task. */
974
                if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
975
                {
976
                        portENTER_CRITICAL();
977
                        {
978
                                if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
979
                                {
980
                                        traceTASK_RESUME( pxTCB );
981
 
982
                                        /* As we are in a critical section we can access the ready
983
                                        lists even if the scheduler is suspended. */
984
                                        vListRemove(  &( pxTCB->xGenericListItem ) );
985
                                        prvAddTaskToReadyQueue( pxTCB );
986
 
987
                                        /* We may have just resumed a higher priority task. */
988
                                        if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
989
                                        {
990
                                                /* This yield may not cause the task just resumed to run, but
991
                                                will leave the lists in the correct state for the next yield. */
992
                                                portYIELD_WITHIN_API();
993
                                        }
994
                                }
995
                        }
996
                        portEXIT_CRITICAL();
997
                }
998
        }
999
 
1000
#endif
1001
 
1002
/*-----------------------------------------------------------*/
1003
 
1004
#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
1005
 
1006
        portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume )
1007
        {
1008
        portBASE_TYPE xYieldRequired = pdFALSE;
1009
        tskTCB *pxTCB;
1010
 
1011
                pxTCB = ( tskTCB * ) pxTaskToResume;
1012
 
1013
                if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
1014
                {
1015
                        traceTASK_RESUME_FROM_ISR( pxTCB );
1016
 
1017
                        if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
1018
                        {
1019
                                xYieldRequired = ( pxTCB->uxPriority >= pxCurrentTCB->uxPriority );
1020
                                vListRemove(  &( pxTCB->xGenericListItem ) );
1021
                                prvAddTaskToReadyQueue( pxTCB );
1022
                        }
1023
                        else
1024
                        {
1025
                                /* We cannot access the delayed or ready lists, so will hold this
1026
                                task pending until the scheduler is resumed, at which point a
1027
                                yield will be performed if necessary. */
1028
                                vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
1029
                        }
1030
                }
1031
 
1032
                return xYieldRequired;
1033
        }
1034
 
1035
#endif
1036
 
1037
 
1038
 
1039
 
1040
/*-----------------------------------------------------------
1041
 * PUBLIC SCHEDULER CONTROL documented in task.h
1042
 *----------------------------------------------------------*/
1043
 
1044
 
1045
void vTaskStartScheduler( void )
1046
{
1047
portBASE_TYPE xReturn;
1048
 
1049
        /* Add the idle task at the lowest priority. */
1050
        xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), ( xTaskHandle * ) NULL );
1051
 
1052
        if( xReturn == pdPASS )
1053
        {
1054
                /* Interrupts are turned off here, to ensure a tick does not occur
1055
                before or during the call to xPortStartScheduler().  The stacks of
1056
                the created tasks contain a status word with interrupts switched on
1057
                so interrupts will automatically get re-enabled when the first task
1058
                starts to run.
1059
 
1060
                STEPPING THROUGH HERE USING A DEBUGGER CAN CAUSE BIG PROBLEMS IF THE
1061
                DEBUGGER ALLOWS INTERRUPTS TO BE PROCESSED. */
1062
                portDISABLE_INTERRUPTS();
1063
 
1064
                xSchedulerRunning = pdTRUE;
1065
                xTickCount = ( portTickType ) 0;
1066
 
1067
                /* If configGENERATE_RUN_TIME_STATS is defined then the following
1068
                macro must be defined to configure the timer/counter used to generate
1069
                the run time counter time base. */
1070
                portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();
1071
 
1072
                /* Setting up the timer tick is hardware specific and thus in the
1073
                portable interface. */
1074
                if( xPortStartScheduler() )
1075
                {
1076
                        /* Should not reach here as if the scheduler is running the
1077
                        function will not return. */
1078
                }
1079
                else
1080
                {
1081
                        /* Should only reach here if a task calls xTaskEndScheduler(). */
1082
                }
1083
        }
1084
}
1085
/*-----------------------------------------------------------*/
1086
 
1087
void vTaskEndScheduler( void )
1088
{
1089
        /* Stop the scheduler interrupts and call the portable scheduler end
1090
        routine so the original ISRs can be restored if necessary.  The port
1091
        layer must ensure interrupts enable     bit is left in the correct state. */
1092
        portDISABLE_INTERRUPTS();
1093
        xSchedulerRunning = pdFALSE;
1094
        vPortEndScheduler();
1095
}
1096
/*----------------------------------------------------------*/
1097
 
1098
void vTaskSuspendAll( void )
1099
{
1100
        /* A critical section is not required as the variable is of type
1101
        portBASE_TYPE. */
1102
        ++uxSchedulerSuspended;
1103
}
1104
/*----------------------------------------------------------*/
1105
 
1106
signed portBASE_TYPE xTaskResumeAll( void )
1107
{
1108
register tskTCB *pxTCB;
1109
signed portBASE_TYPE xAlreadyYielded = pdFALSE;
1110
 
1111
        /* It is possible that an ISR caused a task to be removed from an event
1112
        list while the scheduler was suspended.  If this was the case then the
1113
        removed task will have been added to the xPendingReadyList.  Once the
1114
        scheduler has been resumed it is safe to move all the pending ready
1115
        tasks from this list into their appropriate ready list. */
1116
        portENTER_CRITICAL();
1117
        {
1118
                --uxSchedulerSuspended;
1119
 
1120
                if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
1121
                {
1122
                        if( uxCurrentNumberOfTasks > ( unsigned portBASE_TYPE ) 0 )
1123
                        {
1124
                                portBASE_TYPE xYieldRequired = pdFALSE;
1125
 
1126
                                /* Move any readied tasks from the pending list into the
1127
                                appropriate ready list. */
1128
                                while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY(  ( ( xList * ) &xPendingReadyList ) ) ) != NULL )
1129
                                {
1130
                                        vListRemove( &( pxTCB->xEventListItem ) );
1131
                                        vListRemove( &( pxTCB->xGenericListItem ) );
1132
                                        prvAddTaskToReadyQueue( pxTCB );
1133
 
1134
                                        /* If we have moved a task that has a priority higher than
1135
                                        the current task then we should yield. */
1136
                                        if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
1137
                                        {
1138
                                                xYieldRequired = pdTRUE;
1139
                                        }
1140
                                }
1141
 
1142
                                /* If any ticks occurred while the scheduler was suspended then
1143
                                they should be processed now.  This ensures the tick count does not
1144
                                slip, and that any delayed tasks are resumed at the correct time. */
1145
                                if( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
1146
                                {
1147
                                        while( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
1148
                                        {
1149
                                                vTaskIncrementTick();
1150
                                                --uxMissedTicks;
1151
                                        }
1152
 
1153
                                        /* As we have processed some ticks it is appropriate to yield
1154
                                        to ensure the highest priority task that is ready to run is
1155
                                        the task actually running. */
1156
                                        #if configUSE_PREEMPTION == 1
1157
                                        {
1158
                                                xYieldRequired = pdTRUE;
1159
                                        }
1160
                                        #endif
1161
                                }
1162
 
1163
                                if( ( xYieldRequired == pdTRUE ) || ( xMissedYield == pdTRUE ) )
1164
                                {
1165
                                        xAlreadyYielded = pdTRUE;
1166
                                        xMissedYield = pdFALSE;
1167
                                        portYIELD_WITHIN_API();
1168
                                }
1169
                        }
1170
                }
1171
        }
1172
        portEXIT_CRITICAL();
1173
 
1174
        return xAlreadyYielded;
1175
}
1176
 
1177
 
1178
 
1179
 
1180
 
1181
 
1182
/*-----------------------------------------------------------
1183
 * PUBLIC TASK UTILITIES documented in task.h
1184
 *----------------------------------------------------------*/
1185
 
1186
 
1187
 
1188
portTickType xTaskGetTickCount( void )
1189
{
1190
portTickType xTicks;
1191
 
1192
        /* Critical section required if running on a 16 bit processor. */
1193
        portENTER_CRITICAL();
1194
        {
1195
                xTicks = xTickCount;
1196
        }
1197
        portEXIT_CRITICAL();
1198
 
1199
        return xTicks;
1200
}
1201
/*-----------------------------------------------------------*/
1202
 
1203
portTickType xTaskGetTickCountFromISR( void )
1204
{
1205
        return xTickCount;
1206
}
1207
/*-----------------------------------------------------------*/
1208
 
1209
unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void )
1210
{
1211
        /* A critical section is not required because the variables are of type
1212
        portBASE_TYPE. */
1213
        return uxCurrentNumberOfTasks;
1214
}
1215
/*-----------------------------------------------------------*/
1216
 
1217
#if ( configUSE_TRACE_FACILITY == 1 )
1218
 
1219
        void vTaskList( signed char *pcWriteBuffer )
1220
        {
1221
        unsigned portBASE_TYPE uxQueue;
1222
 
1223
                /* This is a VERY costly function that should be used for debug only.
1224
                It leaves interrupts disabled for a LONG time. */
1225
 
1226
                vTaskSuspendAll();
1227
                {
1228
                        /* Run through all the lists that could potentially contain a TCB and
1229
                        report the task name, state and stack high water mark. */
1230
 
1231
                        pcWriteBuffer[ 0 ] = ( signed char ) 0x00;
1232
                        strcat( ( char * ) pcWriteBuffer, ( const char * ) "\r\n" );
1233
 
1234
                        uxQueue = uxTopUsedPriority + 1;
1235
 
1236
                        do
1237
                        {
1238
                                uxQueue--;
1239
 
1240
                                if( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) )
1241
                                {
1242
                                        prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), tskREADY_CHAR );
1243
                                }
1244
                        }while( uxQueue > ( unsigned short ) tskIDLE_PRIORITY );
1245
 
1246
                        if( !listLIST_IS_EMPTY( pxDelayedTaskList ) )
1247
                        {
1248
                                prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, tskBLOCKED_CHAR );
1249
                        }
1250
 
1251
                        if( !listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) )
1252
                        {
1253
                                prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, tskBLOCKED_CHAR );
1254
                        }
1255
 
1256
                        #if( INCLUDE_vTaskDelete == 1 )
1257
                        {
1258
                                if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) )
1259
                                {
1260
                                        prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, tskDELETED_CHAR );
1261
                                }
1262
                        }
1263
                        #endif
1264
 
1265
                        #if ( INCLUDE_vTaskSuspend == 1 )
1266
                        {
1267
                                if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
1268
                                {
1269
                                        prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, tskSUSPENDED_CHAR );
1270
                                }
1271
                        }
1272
                        #endif
1273
                }
1274
                xTaskResumeAll();
1275
        }
1276
 
1277
#endif
1278
/*----------------------------------------------------------*/
1279
 
1280
#if ( configGENERATE_RUN_TIME_STATS == 1 )
1281
 
1282
        void vTaskGetRunTimeStats( signed char *pcWriteBuffer )
1283
        {
1284
        unsigned portBASE_TYPE uxQueue;
1285
        unsigned long ulTotalRunTime;
1286
 
1287
                /* This is a VERY costly function that should be used for debug only.
1288
                It leaves interrupts disabled for a LONG time. */
1289
 
1290
                vTaskSuspendAll();
1291
                {
1292
                        #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
1293
                                portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime );
1294
                        #else
1295
                                ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
1296
                        #endif
1297
 
1298
                        /* Divide ulTotalRunTime by 100 to make the percentage caluclations
1299
                        simpler in the prvGenerateRunTimeStatsForTasksInList() function. */
1300
                        ulTotalRunTime /= 100UL;
1301
 
1302
                        /* Run through all the lists that could potentially contain a TCB,
1303
                        generating a table of run timer percentages in the provided
1304
                        buffer. */
1305
 
1306
                        pcWriteBuffer[ 0 ] = ( signed char ) 0x00;
1307
                        strcat( ( char * ) pcWriteBuffer, ( const char * ) "\r\n" );
1308
 
1309
                        uxQueue = uxTopUsedPriority + 1;
1310
 
1311
                        do
1312
                        {
1313
                                uxQueue--;
1314
 
1315
                                if( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) )
1316
                                {
1317
                                        prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), ulTotalRunTime );
1318
                                }
1319
                        }while( uxQueue > ( unsigned short ) tskIDLE_PRIORITY );
1320
 
1321
                        if( !listLIST_IS_EMPTY( pxDelayedTaskList ) )
1322
                        {
1323
                                prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, ulTotalRunTime );
1324
                        }
1325
 
1326
                        if( !listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) )
1327
                        {
1328
                                prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, ulTotalRunTime );
1329
                        }
1330
 
1331
                        #if ( INCLUDE_vTaskDelete == 1 )
1332
                        {
1333
                                if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) )
1334
                                {
1335
                                        prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, ulTotalRunTime );
1336
                                }
1337
                        }
1338
                        #endif
1339
 
1340
                        #if ( INCLUDE_vTaskSuspend == 1 )
1341
                        {
1342
                                if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
1343
                                {
1344
                                        prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, ulTotalRunTime );
1345
                                }
1346
                        }
1347
                        #endif
1348
                }
1349
                xTaskResumeAll();
1350
        }
1351
 
1352
#endif
1353
/*----------------------------------------------------------*/
1354
 
1355
#if ( configUSE_TRACE_FACILITY == 1 )
1356
 
1357
        void vTaskStartTrace( signed char * pcBuffer, unsigned long ulBufferSize )
1358
        {
1359
                portENTER_CRITICAL();
1360
                {
1361
                        pcTraceBuffer = ( signed char * )pcBuffer;
1362
                        pcTraceBufferStart = pcBuffer;
1363
                        pcTraceBufferEnd = pcBuffer + ( ulBufferSize - tskSIZE_OF_EACH_TRACE_LINE );
1364
                        xTracing = pdTRUE;
1365
                }
1366
                portEXIT_CRITICAL();
1367
        }
1368
 
1369
#endif
1370
/*----------------------------------------------------------*/
1371
 
1372
#if ( configUSE_TRACE_FACILITY == 1 )
1373
 
1374
        unsigned long ulTaskEndTrace( void )
1375
        {
1376
        unsigned long ulBufferLength;
1377
 
1378
                portENTER_CRITICAL();
1379
                        xTracing = pdFALSE;
1380
                portEXIT_CRITICAL();
1381
 
1382
                ulBufferLength = ( unsigned long ) ( pcTraceBuffer - pcTraceBufferStart );
1383
 
1384
                return ulBufferLength;
1385
        }
1386
 
1387
#endif
1388
 
1389
 
1390
 
1391
/*-----------------------------------------------------------
1392
 * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES
1393
 * documented in task.h
1394
 *----------------------------------------------------------*/
1395
 
1396
 
1397
void vTaskIncrementTick( void )
1398
{
1399
        /* Called by the portable layer each time a tick interrupt occurs.
1400
        Increments the tick then checks to see if the new tick value will cause any
1401
        tasks to be unblocked. */
1402
        if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
1403
        {
1404
                ++xTickCount;
1405
                if( xTickCount == ( portTickType ) 0 )
1406
                {
1407
                        xList *pxTemp;
1408
 
1409
                        /* Tick count has overflowed so we need to swap the delay lists.
1410
                        If there are any items in pxDelayedTaskList here then there is
1411
                        an error! */
1412
                        pxTemp = pxDelayedTaskList;
1413
                        pxDelayedTaskList = pxOverflowDelayedTaskList;
1414
                        pxOverflowDelayedTaskList = pxTemp;
1415
                        xNumOfOverflows++;
1416
                }
1417
 
1418
                /* See if this tick has made a timeout expire. */
1419
                prvCheckDelayedTasks();
1420
        }
1421
        else
1422
        {
1423
                ++uxMissedTicks;
1424
 
1425
                /* The tick hook gets called at regular intervals, even if the
1426
                scheduler is locked. */
1427
                #if ( configUSE_TICK_HOOK == 1 )
1428
                {
1429
                        extern void vApplicationTickHook( void );
1430
 
1431
                        vApplicationTickHook();
1432
                }
1433
                #endif
1434
        }
1435
 
1436
        #if ( configUSE_TICK_HOOK == 1 )
1437
        {
1438
                extern void vApplicationTickHook( void );
1439
 
1440
                /* Guard against the tick hook being called when the missed tick
1441
                count is being unwound (when the scheduler is being unlocked. */
1442
                if( uxMissedTicks == 0 )
1443
                {
1444
                        vApplicationTickHook();
1445
                }
1446
        }
1447
        #endif
1448
 
1449
        traceTASK_INCREMENT_TICK( xTickCount );
1450
}
1451
/*-----------------------------------------------------------*/
1452
 
1453
#if ( ( INCLUDE_vTaskCleanUpResources == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
1454
 
1455
        void vTaskCleanUpResources( void )
1456
        {
1457
        unsigned short usQueue;
1458
        volatile tskTCB *pxTCB;
1459
 
1460
                usQueue = ( unsigned short ) uxTopUsedPriority + ( unsigned short ) 1;
1461
 
1462
                /* Remove any TCB's from the ready queues. */
1463
                do
1464
                {
1465
                        usQueue--;
1466
 
1467
                        while( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ usQueue ] ) ) )
1468
                        {
1469
                                listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &( pxReadyTasksLists[ usQueue ] ) );
1470
                                vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
1471
 
1472
                                prvDeleteTCB( ( tskTCB * ) pxTCB );
1473
                        }
1474
                }while( usQueue > ( unsigned short ) tskIDLE_PRIORITY );
1475
 
1476
                /* Remove any TCB's from the delayed queue. */
1477
                while( !listLIST_IS_EMPTY( &xDelayedTaskList1 ) )
1478
                {
1479
                        listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList1 );
1480
                        vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
1481
 
1482
                        prvDeleteTCB( ( tskTCB * ) pxTCB );
1483
                }
1484
 
1485
                /* Remove any TCB's from the overflow delayed queue. */
1486
                while( !listLIST_IS_EMPTY( &xDelayedTaskList2 ) )
1487
                {
1488
                        listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList2 );
1489
                        vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
1490
 
1491
                        prvDeleteTCB( ( tskTCB * ) pxTCB );
1492
                }
1493
 
1494
                while( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
1495
                {
1496
                        listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xSuspendedTaskList );
1497
                        vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
1498
 
1499
                        prvDeleteTCB( ( tskTCB * ) pxTCB );
1500
                }
1501
        }
1502
 
1503
#endif
1504
/*-----------------------------------------------------------*/
1505
 
1506
#if ( configUSE_APPLICATION_TASK_TAG == 1 )
1507
 
1508
        void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxTagValue )
1509
        {
1510
        tskTCB *xTCB;
1511
 
1512
                /* If xTask is NULL then we are setting our own task hook. */
1513
                if( xTask == NULL )
1514
                {
1515
                        xTCB = ( tskTCB * ) pxCurrentTCB;
1516
                }
1517
                else
1518
                {
1519
                        xTCB = ( tskTCB * ) xTask;
1520
                }
1521
 
1522
                /* Save the hook function in the TCB.  A critical section is required as
1523
                the value can be accessed from an interrupt. */
1524
                portENTER_CRITICAL();
1525
                        xTCB->pxTaskTag = pxTagValue;
1526
                portEXIT_CRITICAL();
1527
        }
1528
 
1529
#endif
1530
/*-----------------------------------------------------------*/
1531
 
1532
#if ( configUSE_APPLICATION_TASK_TAG == 1 )
1533
 
1534
        pdTASK_HOOK_CODE xTaskGetApplicationTaskTag( xTaskHandle xTask )
1535
        {
1536
        tskTCB *xTCB;
1537
        pdTASK_HOOK_CODE xReturn;
1538
 
1539
                /* If xTask is NULL then we are setting our own task hook. */
1540
                if( xTask == NULL )
1541
                {
1542
                        xTCB = ( tskTCB * ) pxCurrentTCB;
1543
                }
1544
                else
1545
                {
1546
                        xTCB = ( tskTCB * ) xTask;
1547
                }
1548
 
1549
                /* Save the hook function in the TCB.  A critical section is required as
1550
                the value can be accessed from an interrupt. */
1551
                portENTER_CRITICAL();
1552
                        xReturn = xTCB->pxTaskTag;
1553
                portEXIT_CRITICAL();
1554
 
1555
                return xReturn;
1556
        }
1557
 
1558
#endif
1559
/*-----------------------------------------------------------*/
1560
 
1561
#if ( configUSE_APPLICATION_TASK_TAG == 1 )
1562
 
1563
        portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParameter )
1564
        {
1565
        tskTCB *xTCB;
1566
        portBASE_TYPE xReturn;
1567
 
1568
                /* If xTask is NULL then we are calling our own task hook. */
1569
                if( xTask == NULL )
1570
                {
1571
                        xTCB = ( tskTCB * ) pxCurrentTCB;
1572
                }
1573
                else
1574
                {
1575
                        xTCB = ( tskTCB * ) xTask;
1576
                }
1577
 
1578
                if( xTCB->pxTaskTag != NULL )
1579
                {
1580
                        xReturn = xTCB->pxTaskTag( pvParameter );
1581
                }
1582
                else
1583
                {
1584
                        xReturn = pdFAIL;
1585
                }
1586
 
1587
                return xReturn;
1588
        }
1589
 
1590
#endif
1591
/*-----------------------------------------------------------*/
1592
 
1593
void vTaskSwitchContext( void )
1594
{
1595
        if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )
1596
        {
1597
                /* The scheduler is currently suspended - do not allow a context
1598
                switch. */
1599
                xMissedYield = pdTRUE;
1600
                return;
1601
        }
1602
 
1603
        traceTASK_SWITCHED_OUT();
1604
 
1605
        #if ( configGENERATE_RUN_TIME_STATS == 1 )
1606
        {
1607
                unsigned long ulTempCounter;
1608
 
1609
                        #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
1610
                                portALT_GET_RUN_TIME_COUNTER_VALUE( ulTempCounter );
1611
                        #else
1612
                                ulTempCounter = portGET_RUN_TIME_COUNTER_VALUE();
1613
                        #endif
1614
 
1615
                        /* Add the amount of time the task has been running to the accumulated
1616
                        time so far.  The time the task started running was stored in
1617
                        ulTaskSwitchedInTime.  Note that there is no overflow protection here
1618
                        so count values are only valid until the timer overflows.  Generally
1619
                        this will be about 1 hour assuming a 1uS timer increment. */
1620
                        pxCurrentTCB->ulRunTimeCounter += ( ulTempCounter - ulTaskSwitchedInTime );
1621
                        ulTaskSwitchedInTime = ulTempCounter;
1622
        }
1623
        #endif
1624
 
1625
        taskFIRST_CHECK_FOR_STACK_OVERFLOW();
1626
        taskSECOND_CHECK_FOR_STACK_OVERFLOW();
1627
 
1628
        /* Find the highest priority queue that contains ready tasks. */
1629
        while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) )
1630
        {
1631
                --uxTopReadyPriority;
1632
        }
1633
 
1634
        /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the tasks of the
1635
        same priority get an equal share of the processor time. */
1636
        listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) );
1637
 
1638
        traceTASK_SWITCHED_IN();
1639
        vWriteTraceToBuffer();
1640
}
1641
/*-----------------------------------------------------------*/
1642
 
1643
void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait )
1644
{
1645
portTickType xTimeToWake;
1646
 
1647
        /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
1648
        SCHEDULER SUSPENDED. */
1649
 
1650
        /* Place the event list item of the TCB in the appropriate event list.
1651
        This is placed in the list in priority order so the highest priority task
1652
        is the first to be woken by the event. */
1653
        vListInsert( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );
1654
 
1655
        /* We must remove ourselves from the ready list before adding ourselves
1656
        to the blocked list as the same list item is used for both lists.  We have
1657
        exclusive access to the ready lists as the scheduler is locked. */
1658
        vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
1659
 
1660
 
1661
        #if ( INCLUDE_vTaskSuspend == 1 )
1662
        {
1663
                if( xTicksToWait == portMAX_DELAY )
1664
                {
1665
                        /* Add ourselves to the suspended task list instead of a delayed task
1666
                        list to ensure we are not woken by a timing event.  We will block
1667
                        indefinitely. */
1668
                        vListInsertEnd( ( xList * ) &xSuspendedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
1669
                }
1670
                else
1671
                {
1672
                        /* Calculate the time at which the task should be woken if the event does
1673
                        not occur.  This may overflow but this doesn't matter. */
1674
                        xTimeToWake = xTickCount + xTicksToWait;
1675
 
1676
                        listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
1677
 
1678
                        if( xTimeToWake < xTickCount )
1679
                        {
1680
                                /* Wake time has overflowed.  Place this item in the overflow list. */
1681
                                vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
1682
                        }
1683
                        else
1684
                        {
1685
                                /* The wake time has not overflowed, so we can use the current block list. */
1686
                                vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
1687
                        }
1688
                }
1689
        }
1690
        #else
1691
        {
1692
                        /* Calculate the time at which the task should be woken if the event does
1693
                        not occur.  This may overflow but this doesn't matter. */
1694
                        xTimeToWake = xTickCount + xTicksToWait;
1695
 
1696
                        listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
1697
 
1698
                        if( xTimeToWake < xTickCount )
1699
                        {
1700
                                /* Wake time has overflowed.  Place this item in the overflow list. */
1701
                                vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
1702
                        }
1703
                        else
1704
                        {
1705
                                /* The wake time has not overflowed, so we can use the current block list. */
1706
                                vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
1707
                        }
1708
        }
1709
        #endif
1710
}
1711
/*-----------------------------------------------------------*/
1712
 
1713
signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList )
1714
{
1715
tskTCB *pxUnblockedTCB;
1716
portBASE_TYPE xReturn;
1717
 
1718
        /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
1719
        SCHEDULER SUSPENDED.  It can also be called from within an ISR. */
1720
 
1721
        /* The event list is sorted in priority order, so we can remove the
1722
        first in the list, remove the TCB from the delayed list, and add
1723
        it to the ready list.
1724
 
1725
        If an event is for a queue that is locked then this function will never
1726
        get called - the lock count on the queue will get modified instead.  This
1727
        means we can always expect exclusive access to the event list here. */
1728
        pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
1729
        vListRemove( &( pxUnblockedTCB->xEventListItem ) );
1730
 
1731
        if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
1732
        {
1733
                vListRemove( &( pxUnblockedTCB->xGenericListItem ) );
1734
                prvAddTaskToReadyQueue( pxUnblockedTCB );
1735
        }
1736
        else
1737
        {
1738
                /* We cannot access the delayed or ready lists, so will hold this
1739
                task pending until the scheduler is resumed. */
1740
                vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );
1741
        }
1742
 
1743
        if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority )
1744
        {
1745
                /* Return true if the task removed from the event list has
1746
                a higher priority than the calling task.  This allows
1747
                the calling task to know if it should force a context
1748
                switch now. */
1749
                xReturn = pdTRUE;
1750
        }
1751
        else
1752
        {
1753
                xReturn = pdFALSE;
1754
        }
1755
 
1756
        return xReturn;
1757
}
1758
/*-----------------------------------------------------------*/
1759
 
1760
void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut )
1761
{
1762
        pxTimeOut->xOverflowCount = xNumOfOverflows;
1763
        pxTimeOut->xTimeOnEntering = xTickCount;
1764
}
1765
/*-----------------------------------------------------------*/
1766
 
1767
portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait )
1768
{
1769
portBASE_TYPE xReturn;
1770
 
1771
        portENTER_CRITICAL();
1772
        {
1773
                #if ( INCLUDE_vTaskSuspend == 1 )
1774
                        /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is
1775
                        the maximum block time then the task should block indefinitely, and
1776
                        therefore never time out. */
1777
                        if( *pxTicksToWait == portMAX_DELAY )
1778
                        {
1779
                                xReturn = pdFALSE;
1780
                        }
1781
                        else /* We are not blocking indefinitely, perform the checks below. */
1782
                #endif
1783
 
1784
                if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( ( portTickType ) xTickCount >= ( portTickType ) pxTimeOut->xTimeOnEntering ) )
1785
                {
1786
                        /* The tick count is greater than the time at which vTaskSetTimeout()
1787
                        was called, but has also overflowed since vTaskSetTimeOut() was called.
1788
                        It must have wrapped all the way around and gone past us again. This
1789
                        passed since vTaskSetTimeout() was called. */
1790
                        xReturn = pdTRUE;
1791
                }
1792
                else if( ( ( portTickType ) ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering ) ) < ( portTickType ) *pxTicksToWait )
1793
                {
1794
                        /* Not a genuine timeout. Adjust parameters for time remaining. */
1795
                        *pxTicksToWait -= ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering );
1796
                        vTaskSetTimeOutState( pxTimeOut );
1797
                        xReturn = pdFALSE;
1798
                }
1799
                else
1800
                {
1801
                        xReturn = pdTRUE;
1802
                }
1803
        }
1804
        portEXIT_CRITICAL();
1805
 
1806
        return xReturn;
1807
}
1808
/*-----------------------------------------------------------*/
1809
 
1810
void vTaskMissedYield( void )
1811
{
1812
        xMissedYield = pdTRUE;
1813
}
1814
 
1815
/*
1816
 * -----------------------------------------------------------
1817
 * The Idle task.
1818
 * ----------------------------------------------------------
1819
 *
1820
 * The portTASK_FUNCTION() macro is used to allow port/compiler specific
1821
 * language extensions.  The equivalent prototype for this function is:
1822
 *
1823
 * void prvIdleTask( void *pvParameters );
1824
 *
1825
 */
1826
static portTASK_FUNCTION( prvIdleTask, pvParameters )
1827
{
1828
        /* Stop warnings. */
1829
        ( void ) pvParameters;
1830
 
1831
        for( ;; )
1832
        {
1833
                /* See if any tasks have been deleted. */
1834
                prvCheckTasksWaitingTermination();
1835
 
1836
                #if ( configUSE_PREEMPTION == 0 )
1837
                {
1838
                        /* If we are not using preemption we keep forcing a task switch to
1839
                        see if any other task has become available.  If we are using
1840
                        preemption we don't need to do this as any task becoming available
1841
                        will automatically get the processor anyway. */
1842
                        taskYIELD();
1843
                }
1844
                #endif
1845
 
1846
                #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
1847
                {
1848
                        /* When using preemption tasks of equal priority will be
1849
                        timesliced.  If a task that is sharing the idle priority is ready
1850
                        to run then the idle task should yield before the end of the
1851
                        timeslice.
1852
 
1853
                        A critical region is not required here as we are just reading from
1854
                        the list, and an occasional incorrect value will not matter.  If
1855
                        the ready list at the idle priority contains more than one task
1856
                        then a task other than the idle task is ready to execute. */
1857
                        if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( unsigned portBASE_TYPE ) 1 )
1858
                        {
1859
                                taskYIELD();
1860
                        }
1861
                }
1862
                #endif
1863
 
1864
                #if ( configUSE_IDLE_HOOK == 1 )
1865
                {
1866
                        extern void vApplicationIdleHook( void );
1867
 
1868
                        /* Call the user defined function from within the idle task.  This
1869
                        allows the application designer to add background functionality
1870
                        without the overhead of a separate task.
1871
                        NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
1872
                        CALL A FUNCTION THAT MIGHT BLOCK. */
1873
                        vApplicationIdleHook();
1874
                }
1875
                #endif
1876
        }
1877
} /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */
1878
 
1879
 
1880
 
1881
 
1882
 
1883
 
1884
 
1885
/*-----------------------------------------------------------
1886
 * File private functions documented at the top of the file.
1887
 *----------------------------------------------------------*/
1888
 
1889
 
1890
 
1891
static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth )
1892
{
1893
        /* Store the function name in the TCB. */
1894
        #if configMAX_TASK_NAME_LEN > 1
1895
        {
1896
                /* Don't bring strncpy into the build unnecessarily. */
1897
                strncpy( ( char * ) pxTCB->pcTaskName, ( const char * ) pcName, ( unsigned short ) configMAX_TASK_NAME_LEN );
1898
        }
1899
        #endif
1900
        pxTCB->pcTaskName[ ( unsigned short ) configMAX_TASK_NAME_LEN - ( unsigned short ) 1 ] = '\0';
1901
 
1902
        /* This is used as an array index so must ensure it's not too large.  First
1903
        remove the privilege bit if one is present. */
1904
        if( uxPriority >= configMAX_PRIORITIES )
1905
        {
1906
                uxPriority = configMAX_PRIORITIES - 1;
1907
        }
1908
 
1909
        pxTCB->uxPriority = uxPriority;
1910
        #if ( configUSE_MUTEXES == 1 )
1911
        {
1912
                pxTCB->uxBasePriority = uxPriority;
1913
        }
1914
        #endif
1915
 
1916
        vListInitialiseItem( &( pxTCB->xGenericListItem ) );
1917
        vListInitialiseItem( &( pxTCB->xEventListItem ) );
1918
 
1919
        /* Set the pxTCB as a link back from the xListItem.  This is so we can get
1920
        back to the containing TCB from a generic item in a list. */
1921
        listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB );
1922
 
1923
        /* Event lists are always in priority order. */
1924
        listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );
1925
        listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB );
1926
 
1927
        #if ( portCRITICAL_NESTING_IN_TCB == 1 )
1928
        {
1929
                pxTCB->uxCriticalNesting = ( unsigned portBASE_TYPE ) 0;
1930
        }
1931
        #endif
1932
 
1933
        #if ( configUSE_APPLICATION_TASK_TAG == 1 )
1934
        {
1935
                pxTCB->pxTaskTag = NULL;
1936
        }
1937
        #endif
1938
 
1939
        #if ( configGENERATE_RUN_TIME_STATS == 1 )
1940
        {
1941
                pxTCB->ulRunTimeCounter = 0UL;
1942
        }
1943
        #endif
1944
 
1945
        #if ( portUSING_MPU_WRAPPERS == 1 )
1946
        {
1947
                vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth );
1948
        }
1949
        #else
1950
        {
1951
                ( void ) xRegions;
1952
                ( void ) usStackDepth;
1953
        }
1954
        #endif
1955
}
1956
/*-----------------------------------------------------------*/
1957
 
1958
#if ( portUSING_MPU_WRAPPERS == 1 )
1959
 
1960
        void vTaskAllocateMPURegions( xTaskHandle xTaskToModify, const xMemoryRegion * const xRegions )
1961
        {
1962
        tskTCB *pxTCB;
1963
 
1964
                if( xTaskToModify == pxCurrentTCB )
1965
                {
1966
                        xTaskToModify = NULL;
1967
                }
1968
 
1969
                /* If null is passed in here then we are deleting ourselves. */
1970
                pxTCB = prvGetTCBFromHandle( xTaskToModify );
1971
 
1972
        vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 );
1973
        }
1974
        /*-----------------------------------------------------------*/
1975
#endif
1976
 
1977
static void prvInitialiseTaskLists( void )
1978
{
1979
unsigned portBASE_TYPE uxPriority;
1980
 
1981
        for( uxPriority = 0; uxPriority < configMAX_PRIORITIES; uxPriority++ )
1982
        {
1983
                vListInitialise( ( xList * ) &( pxReadyTasksLists[ uxPriority ] ) );
1984
        }
1985
 
1986
        vListInitialise( ( xList * ) &xDelayedTaskList1 );
1987
        vListInitialise( ( xList * ) &xDelayedTaskList2 );
1988
        vListInitialise( ( xList * ) &xPendingReadyList );
1989
 
1990
        #if ( INCLUDE_vTaskDelete == 1 )
1991
        {
1992
                vListInitialise( ( xList * ) &xTasksWaitingTermination );
1993
        }
1994
        #endif
1995
 
1996
        #if ( INCLUDE_vTaskSuspend == 1 )
1997
        {
1998
                vListInitialise( ( xList * ) &xSuspendedTaskList );
1999
        }
2000
        #endif
2001
 
2002
        /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
2003
        using list2. */
2004
        pxDelayedTaskList = &xDelayedTaskList1;
2005
        pxOverflowDelayedTaskList = &xDelayedTaskList2;
2006
}
2007
/*-----------------------------------------------------------*/
2008
 
2009
static void prvCheckTasksWaitingTermination( void )
2010
{
2011
        #if ( INCLUDE_vTaskDelete == 1 )
2012
        {
2013
                portBASE_TYPE xListIsEmpty;
2014
 
2015
                /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
2016
                too often in the idle task. */
2017
                if( uxTasksDeleted > ( unsigned portBASE_TYPE ) 0 )
2018
                {
2019
                        vTaskSuspendAll();
2020
                                xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
2021
                        xTaskResumeAll();
2022
 
2023
                        if( !xListIsEmpty )
2024
                        {
2025
                                tskTCB *pxTCB;
2026
 
2027
                                portENTER_CRITICAL();
2028
                                {
2029
                                        pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xTasksWaitingTermination ) );
2030
                                        vListRemove( &( pxTCB->xGenericListItem ) );
2031
                                        --uxCurrentNumberOfTasks;
2032
                                        --uxTasksDeleted;
2033
                                }
2034
                                portEXIT_CRITICAL();
2035
 
2036
                                prvDeleteTCB( pxTCB );
2037
                        }
2038
                }
2039
        }
2040
        #endif
2041
}
2042
/*-----------------------------------------------------------*/
2043
 
2044
static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer )
2045
{
2046
tskTCB *pxNewTCB;
2047
 
2048
        /* Allocate space for the TCB.  Where the memory comes from depends on
2049
        the implementation of the port malloc function. */
2050
        pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) );
2051
 
2052
        if( pxNewTCB != NULL )
2053
        {
2054
                /* Allocate space for the stack used by the task being created.
2055
                The base of the stack memory stored in the TCB so the task can
2056
                be deleted later if required. */
2057
                pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMallocAligned( ( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) ), puxStackBuffer );
2058
 
2059
                if( pxNewTCB->pxStack == NULL )
2060
                {
2061
                        /* Could not allocate the stack.  Delete the allocated TCB. */
2062
                        vPortFree( pxNewTCB );
2063
                        pxNewTCB = NULL;
2064
                }
2065
                else
2066
                {
2067
                        /* Just to help debugging. */
2068
                        memset( pxNewTCB->pxStack, tskSTACK_FILL_BYTE, usStackDepth * sizeof( portSTACK_TYPE ) );
2069
                }
2070
        }
2071
 
2072
        return pxNewTCB;
2073
}
2074
/*-----------------------------------------------------------*/
2075
 
2076
#if ( configUSE_TRACE_FACILITY == 1 )
2077
 
2078
        static void prvListTaskWithinSingleList( const signed char *pcWriteBuffer, xList *pxList, signed char cStatus )
2079
        {
2080
        volatile tskTCB *pxNextTCB, *pxFirstTCB;
2081
        unsigned short usStackRemaining;
2082
 
2083
                /* Write the details of all the TCB's in pxList into the buffer. */
2084
                listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
2085
                do
2086
                {
2087
                        listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
2088
                        #if ( portSTACK_GROWTH > 0 )
2089
                        {
2090
                                usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxEndOfStack );
2091
                        }
2092
                        #else
2093
                        {
2094
                                usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxStack );
2095
                        }
2096
                        #endif                  
2097
 
2098
                        sprintf( pcStatusString, ( char * ) "%s\t\t%c\t%u\t%u\t%u\r\n", pxNextTCB->pcTaskName, cStatus, ( unsigned int ) pxNextTCB->uxPriority, usStackRemaining, ( unsigned int ) pxNextTCB->uxTCBNumber );
2099
                        strcat( ( char * ) pcWriteBuffer, ( char * ) pcStatusString );
2100
 
2101
                } while( pxNextTCB != pxFirstTCB );
2102
        }
2103
 
2104
#endif
2105
/*-----------------------------------------------------------*/
2106
 
2107
#if ( configGENERATE_RUN_TIME_STATS == 1 )
2108
 
2109
        static void prvGenerateRunTimeStatsForTasksInList( const signed char *pcWriteBuffer, xList *pxList, unsigned long ulTotalRunTime )
2110
        {
2111
        volatile tskTCB *pxNextTCB, *pxFirstTCB;
2112
        unsigned long ulStatsAsPercentage;
2113
 
2114
                /* Write the run time stats of all the TCB's in pxList into the buffer. */
2115
                listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
2116
                do
2117
                {
2118
                        /* Get next TCB in from the list. */
2119
                        listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
2120
 
2121
                        /* Divide by zero check. */
2122
                        if( ulTotalRunTime > 0UL )
2123
                        {
2124
                                /* Has the task run at all? */
2125
                                if( pxNextTCB->ulRunTimeCounter == 0 )
2126
                                {
2127
                                        /* The task has used no CPU time at all. */
2128
                                        sprintf( pcStatsString, ( char * ) "%s\t\t0\t\t0%%\r\n", pxNextTCB->pcTaskName );
2129
                                }
2130
                                else
2131
                                {
2132
                                        /* What percentage of the total run time has the task used?
2133
                                        This will always be rounded down to the nearest integer.
2134
                                        ulTotalRunTime has already been divided by 100. */
2135
                                        ulStatsAsPercentage = pxNextTCB->ulRunTimeCounter / ulTotalRunTime;
2136
 
2137
                                        if( ulStatsAsPercentage > 0UL )
2138
                                        {
2139
                                                #ifdef portLU_PRINTF_SPECIFIER_REQUIRED
2140
                                                {
2141
                                                        sprintf( pcStatsString, ( char * ) "%s\t\t%lu\t\t%lu%%\r\n", pxNextTCB->pcTaskName, pxNextTCB->ulRunTimeCounter, ulStatsAsPercentage );
2142
                                                }
2143
                                                #else
2144
                                                {
2145
                                                        /* sizeof( int ) == sizeof( long ) so a smaller
2146
                                                        printf() library can be used. */
2147
                                                        sprintf( pcStatsString, ( char * ) "%s\t\t%u\t\t%u%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage );
2148
                                                }
2149
                                                #endif
2150
                                        }
2151
                                        else
2152
                                        {
2153
                                                /* If the percentage is zero here then the task has
2154
                                                consumed less than 1% of the total run time. */
2155
                                                #ifdef portLU_PRINTF_SPECIFIER_REQUIRED
2156
                                                {
2157
                                                        sprintf( pcStatsString, ( char * ) "%s\t\t%lu\t\t<1%%\r\n", pxNextTCB->pcTaskName, pxNextTCB->ulRunTimeCounter );
2158
                                                }
2159
                                                #else
2160
                                                {
2161
                                                        /* sizeof( int ) == sizeof( long ) so a smaller
2162
                                                        printf() library can be used. */
2163
                                                        sprintf( pcStatsString, ( char * ) "%s\t\t%u\t\t<1%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter );
2164
                                                }
2165
                                                #endif
2166
                                        }
2167
                                }
2168
 
2169
                                strcat( ( char * ) pcWriteBuffer, ( char * ) pcStatsString );
2170
                        }
2171
 
2172
                } while( pxNextTCB != pxFirstTCB );
2173
        }
2174
 
2175
#endif
2176
/*-----------------------------------------------------------*/
2177
 
2178
#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
2179
 
2180
        static unsigned short usTaskCheckFreeStackSpace( const unsigned char * pucStackByte )
2181
        {
2182
        register unsigned short usCount = 0;
2183
 
2184
                while( *pucStackByte == tskSTACK_FILL_BYTE )
2185
                {
2186
                        pucStackByte -= portSTACK_GROWTH;
2187
                        usCount++;
2188
                }
2189
 
2190
                usCount /= sizeof( portSTACK_TYPE );
2191
 
2192
                return usCount;
2193
        }
2194
 
2195
#endif
2196
/*-----------------------------------------------------------*/
2197
 
2198
#if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )
2199
 
2200
        unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask )
2201
        {
2202
        tskTCB *pxTCB;
2203
        unsigned char *pcEndOfStack;
2204
        unsigned portBASE_TYPE uxReturn;
2205
 
2206
                pxTCB = prvGetTCBFromHandle( xTask );
2207
 
2208
                #if portSTACK_GROWTH < 0
2209
                {
2210
                        pcEndOfStack = ( unsigned char * ) pxTCB->pxStack;
2211
                }
2212
                #else
2213
                {
2214
                        pcEndOfStack = ( unsigned char * ) pxTCB->pxEndOfStack;
2215
                }
2216
                #endif
2217
 
2218
                uxReturn = ( unsigned portBASE_TYPE ) usTaskCheckFreeStackSpace( pcEndOfStack );
2219
 
2220
                return uxReturn;
2221
        }
2222
 
2223
#endif
2224
/*-----------------------------------------------------------*/
2225
 
2226
#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
2227
 
2228
        static void prvDeleteTCB( tskTCB *pxTCB )
2229
        {
2230
                /* Free up the memory allocated by the scheduler for the task.  It is up to
2231
                the task to free any memory allocated at the application level. */
2232
                vPortFreeAligned( pxTCB->pxStack );
2233
                vPortFree( pxTCB );
2234
        }
2235
 
2236
#endif
2237
 
2238
 
2239
/*-----------------------------------------------------------*/
2240
 
2241
#if ( INCLUDE_xTaskGetCurrentTaskHandle == 1 )
2242
 
2243
        xTaskHandle xTaskGetCurrentTaskHandle( void )
2244
        {
2245
        xTaskHandle xReturn;
2246
 
2247
                /* A critical section is not required as this is not called from
2248
                an interrupt and the current TCB will always be the same for any
2249
                individual execution thread. */
2250
                xReturn = pxCurrentTCB;
2251
 
2252
                return xReturn;
2253
        }
2254
 
2255
#endif
2256
 
2257
/*-----------------------------------------------------------*/
2258
 
2259
#if ( INCLUDE_xTaskGetSchedulerState == 1 )
2260
 
2261
        portBASE_TYPE xTaskGetSchedulerState( void )
2262
        {
2263
        portBASE_TYPE xReturn;
2264
 
2265
                if( xSchedulerRunning == pdFALSE )
2266
                {
2267
                        xReturn = taskSCHEDULER_NOT_STARTED;
2268
                }
2269
                else
2270
                {
2271
                        if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
2272
                        {
2273
                                xReturn = taskSCHEDULER_RUNNING;
2274
                        }
2275
                        else
2276
                        {
2277
                                xReturn = taskSCHEDULER_SUSPENDED;
2278
                        }
2279
                }
2280
 
2281
                return xReturn;
2282
        }
2283
 
2284
#endif
2285
/*-----------------------------------------------------------*/
2286
 
2287
#if ( configUSE_MUTEXES == 1 )
2288
 
2289
        void vTaskPriorityInherit( xTaskHandle * const pxMutexHolder )
2290
        {
2291
        tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
2292
 
2293
                if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )
2294
                {
2295
                        /* Adjust the mutex holder state to account for its new priority. */
2296
                        listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxCurrentTCB->uxPriority );
2297
 
2298
                        /* If the task being modified is in the ready state it will need to
2299
                        be moved in to a new list. */
2300
                        if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) )
2301
                        {
2302
                                vListRemove( &( pxTCB->xGenericListItem ) );
2303
 
2304
                                /* Inherit the priority before being moved into the new list. */
2305
                                pxTCB->uxPriority = pxCurrentTCB->uxPriority;
2306
                                prvAddTaskToReadyQueue( pxTCB );
2307
                        }
2308
                        else
2309
                        {
2310
                                /* Just inherit the priority. */
2311
                                pxTCB->uxPriority = pxCurrentTCB->uxPriority;
2312
                        }
2313
                }
2314
        }
2315
 
2316
#endif
2317
/*-----------------------------------------------------------*/
2318
 
2319
#if ( configUSE_MUTEXES == 1 )
2320
 
2321
        void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder )
2322
        {
2323
        tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
2324
 
2325
                if( pxMutexHolder != NULL )
2326
                {
2327
                        if( pxTCB->uxPriority != pxTCB->uxBasePriority )
2328
                        {
2329
                                /* We must be the running task to be able to give the mutex back.
2330
                                Remove ourselves from the ready list we currently appear in. */
2331
                                vListRemove( &( pxTCB->xGenericListItem ) );
2332
 
2333
                                /* Disinherit the priority before adding ourselves into the new
2334
                                ready list. */
2335
                                pxTCB->uxPriority = pxTCB->uxBasePriority;
2336
                                listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxTCB->uxPriority );
2337
                                prvAddTaskToReadyQueue( pxTCB );
2338
                        }
2339
                }
2340
        }
2341
 
2342
#endif
2343
/*-----------------------------------------------------------*/
2344
 
2345
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
2346
 
2347
        void vTaskEnterCritical( void )
2348
        {
2349
                portDISABLE_INTERRUPTS();
2350
 
2351
                if( xSchedulerRunning != pdFALSE )
2352
                {
2353
                        ( pxCurrentTCB->uxCriticalNesting )++;
2354
                }
2355
        }
2356
 
2357
#endif
2358
/*-----------------------------------------------------------*/
2359
 
2360
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
2361
 
2362
void vTaskExitCritical( void )
2363
{
2364
        if( xSchedulerRunning != pdFALSE )
2365
        {
2366
                if( pxCurrentTCB->uxCriticalNesting > 0 )
2367
                {
2368
                        ( pxCurrentTCB->uxCriticalNesting )--;
2369
 
2370
                        if( pxCurrentTCB->uxCriticalNesting == 0 )
2371
                        {
2372
                                portENABLE_INTERRUPTS();
2373
                        }
2374
                }
2375
        }
2376
}
2377
 
2378
#endif
2379
/*-----------------------------------------------------------*/
2380
 
2381
 
2382
 
2383
 

powered by: WebSVN 2.1.0

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