· 8 years ago · Dec 28, 2017, 11:28 PM
1
2
3
4
5
6
7
8
9
10
11#include <stdlib.h>
12#include <string.h>
13#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
14#include "Arduino_FreeRTOS.h"
15#include "task.h"
16#include "timers.h"
17#include "StackMacros.h"
18#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */
19
20/* Set configUSE_STATS_FORMATTING_FUNCTIONS to 2 to include the stats formatting
21functions but without including stdio.h here. */
22#if ( configUSE_STATS_FORMATTING_FUNCTIONS == 1 )
23 /* At the bottom of this file are two optional functions that can be used
24 to generate human readable text from the raw data generated by the
25 uxTaskGetSystemState() function. Note the formatting functions are provided
26 for convenience only, and are NOT considered part of the kernel. */
27 #include <stdio.h>
28#endif /* configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) */
29
30/* Sanity check the configuration. */
31#if( configUSE_TICKLESS_IDLE != 0 )
32 #if( INCLUDE_vTaskSuspend != 1 )
33 #error INCLUDE_vTaskSuspend must be set to 1 if configUSE_TICKLESS_IDLE is not set to 0
34 #endif /* INCLUDE_vTaskSuspend */
35#endif /* configUSE_TICKLESS_IDLE */
36
37/*
38 * Defines the size, in words, of the stack allocated to the idle task.
39 */
40#define tskIDLE_STACK_SIZE configIDLE_STACK_SIZE
41
42#if( configUSE_PREEMPTION == 0 )
43 /* If the cooperative scheduler is being used then a yield should not be
44 performed just because a higher priority task has been woken. */
45 #define taskYIELD_IF_USING_PREEMPTION()
46#else
47 #define taskYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API()
48#endif
49
50/* Value that can be assigned to the eNotifyState member of the TCB. */
51typedef enum
52{
53 eNotWaitingNotification = 0,
54 eWaitingNotification,
55 eNotified
56} eNotifyValue;
57
58/*
59 * Task control block. A task control block (TCB) is allocated for each task,
60 * and stores task state information, including a pointer to the task's context
61 * (the task's run time environment, including register values)
62 */
63typedef struct tskTaskControlBlock
64{
65 volatile StackType_t *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */
66
67 #if ( portUSING_MPU_WRAPPERS == 1 )
68 xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */
69 BaseType_t xUsingStaticallyAllocatedStack; /* Set to pdTRUE if the stack is a statically allocated array, and pdFALSE if the stack is dynamically allocated. */
70 #endif
71
72 ListItem_t xGenericListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
73 ListItem_t xEventListItem; /*< Used to reference a task from an event list. */
74 UBaseType_t uxPriority; /*< The priority of the task. 0 is the lowest priority. */
75 StackType_t *pxStack; /*< Points to the start of the stack. */
76 char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
77
78 #if ( portSTACK_GROWTH > 0 )
79 StackType_t *pxEndOfStack; /*< Points to the end of the stack on architectures where the stack grows up from low memory. */
80 #endif
81
82 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
83 UBaseType_t uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */
84 #endif
85
86 #if ( configUSE_TRACE_FACILITY == 1 )
87 UBaseType_t uxTCBNumber; /*< Stores a number that increments each time a TCB is created. It allows debuggers to determine when a task has been deleted and then recreated. */
88 UBaseType_t uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */
89 #endif
90
91 #if ( configUSE_MUTEXES == 1 )
92 UBaseType_t uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
93 UBaseType_t uxMutexesHeld;
94 #endif
95
96 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
97 TaskHookFunction_t pxTaskTag;
98 #endif
99
100 #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
101 void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
102 #endif
103
104 #if ( configGENERATE_RUN_TIME_STATS == 1 )
105 uint32_t ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */
106 #endif
107
108 #if ( configUSE_NEWLIB_REENTRANT == 1 )
109 /* Allocate a Newlib reent structure that is specific to this task.
110 Note Newlib support has been included by popular demand, but is not
111 used by the FreeRTOS maintainers themselves. FreeRTOS is not
112 responsible for resulting newlib operation. User must be familiar with
113 newlib and must provide system-wide implementations of the necessary
114 stubs. Be warned that (at the time of writing) the current newlib design
115 implements a system-wide malloc() that must be provided with locks. */
116 struct _reent xNewLib_reent;
117 #endif
118
119 #if ( configUSE_TASK_NOTIFICATIONS == 1 )
120 volatile uint32_t ulNotifiedValue;
121 volatile eNotifyValue eNotifyState;
122 #endif
123
124} TCB_t;
125
126/*
127 * Some kernel aware debuggers require the data the debugger needs access to to
128 * be global, rather than file scope.
129 */
130#ifdef portREMOVE_STATIC_QUALIFIER
131 #define static
132#endif
133
134/*lint -e956 A manual analysis and inspection has been used to determine which
135static variables must be declared volatile. */
136
137PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL;
138
139/* Lists for ready and blocked tasks. --------------------*/
140PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ];/*< Prioritised ready tasks. */
141PRIVILEGED_DATA static List_t xDelayedTaskList1; /*< Delayed tasks. */
142PRIVILEGED_DATA static List_t xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
143PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList; /*< Points to the delayed task list currently being used. */
144PRIVILEGED_DATA static List_t * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
145PRIVILEGED_DATA static List_t xPendingReadyList; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready list when the scheduler is resumed. */
146
147#if ( INCLUDE_vTaskDelete == 1 )
148
149 PRIVILEGED_DATA static List_t xTasksWaitingTermination; /*< Tasks that have been deleted - but their memory not yet freed. */
150 PRIVILEGED_DATA static volatile UBaseType_t uxTasksDeleted = ( UBaseType_t ) 0U;
151
152#endif
153
154#if ( INCLUDE_vTaskSuspend == 1 )
155
156 PRIVILEGED_DATA static List_t xSuspendedTaskList; /*< Tasks that are currently suspended. */
157
158#endif
159
160#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
161
162 PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle = NULL; /*< Holds the handle of the idle task. The idle task is created automatically when the scheduler is started. */
163
164#endif
165
166/* Other file private variables. --------------------------------*/
167PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U;
168PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) 0U;
169PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY;
170PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE;
171PRIVILEGED_DATA static volatile UBaseType_t uxPendedTicks = ( UBaseType_t ) 0U;
172PRIVILEGED_DATA static volatile BaseType_t xYieldPending = pdFALSE;
173PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = ( BaseType_t ) 0;
174PRIVILEGED_DATA static UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U;
175PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = ( TickType_t ) 0U; /* Initialised to portMAX_DELAY before the scheduler starts. */
176
177/* Context switches are held pending while the scheduler is suspended. Also,
178interrupts must not manipulate the xGenericListItem of a TCB, or any of the
179lists the xGenericListItem can be referenced from, if the scheduler is suspended.
180If an interrupt needs to unblock a task while the scheduler is suspended then it
181moves the task's event list item into the xPendingReadyList, ready for the
182kernel to move the task from the pending ready list into the real ready list
183when the scheduler is unsuspended. The pending ready list itself can only be
184accessed from a critical section. */
185PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t ) pdFALSE;
186
187#if ( configGENERATE_RUN_TIME_STATS == 1 )
188
189 PRIVILEGED_DATA static uint32_t ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */
190 PRIVILEGED_DATA static uint32_t ulTotalRunTime = 0UL; /*< Holds the total amount of execution time as defined by the run time counter clock. */
191
192#endif
193
194/*lint +e956 */
195
196/* Debugging and trace facilities private variables and macros. ------------*/
197
198/*
199 * The value used to fill the stack of a task when the task is created. This
200 * is used purely for checking the high water mark for tasks.
201 */
202#define tskSTACK_FILL_BYTE ( 0xa5U )
203
204/*
205 * Macros used by vListTask to indicate which state a task is in.
206 */
207#define tskBLOCKED_CHAR ( 'B' )
208#define tskREADY_CHAR ( 'R' )
209#define tskDELETED_CHAR ( 'D' )
210#define tskSUSPENDED_CHAR ( 'S' )
211
212/*-----------------------------------------------------------*/
213
214#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
215
216 /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is
217 performed in a generic way that is not optimised to any particular
218 microcontroller architecture. */
219
220 /* uxTopReadyPriority holds the priority of the highest priority ready
221 state task. */
222 #define taskRECORD_READY_PRIORITY( uxPriority ) \
223 { \
224 if( ( uxPriority ) > uxTopReadyPriority ) \
225 { \
226 uxTopReadyPriority = ( uxPriority ); \
227 } \
228 } /* taskRECORD_READY_PRIORITY */
229
230 /*-----------------------------------------------------------*/
231
232 #define taskSELECT_HIGHEST_PRIORITY_TASK() \
233 { \
234 /* Find the highest priority queue that contains ready tasks. */ \
235 while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) ) \
236 { \
237 configASSERT( uxTopReadyPriority ); \
238 --uxTopReadyPriority; \
239 } \
240 \
241 /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of \
242 the same priority get an equal share of the processor time. */ \
243 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) ); \
244 } /* taskSELECT_HIGHEST_PRIORITY_TASK */
245
246 /*-----------------------------------------------------------*/
247
248 /* Define away taskRESET_READY_PRIORITY() and portRESET_READY_PRIORITY() as
249 they are only required when a port optimised method of task selection is
250 being used. */
251 #define taskRESET_READY_PRIORITY( uxPriority )
252 #define portRESET_READY_PRIORITY( uxPriority, uxTopReadyPriority )
253
254#else /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
255
256 /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 1 then task selection is
257 performed in a way that is tailored to the particular microcontroller
258 architecture being used. */
259
260 /* A port optimised version is provided. Call the port defined macros. */
261 #define taskRECORD_READY_PRIORITY( uxPriority ) portRECORD_READY_PRIORITY( uxPriority, uxTopReadyPriority )
262
263 /*-----------------------------------------------------------*/
264
265 #define taskSELECT_HIGHEST_PRIORITY_TASK() \
266 { \
267 UBaseType_t uxTopPriority; \
268 \
269 /* Find the highest priority queue that contains ready tasks. */ \
270 portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \
271 configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \
272 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \
273 } /* taskSELECT_HIGHEST_PRIORITY_TASK() */
274
275 /*-----------------------------------------------------------*/
276
277 /* A port optimised version is provided, call it only if the TCB being reset
278 is being referenced from a ready list. If it is referenced from a delayed
279 or suspended list then it won't be in a ready list. */
280 #define taskRESET_READY_PRIORITY( uxPriority ) \
281 { \
282 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == ( UBaseType_t ) 0 ) \
283 { \
284 portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) ); \
285 } \
286 }
287
288#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
289
290/*-----------------------------------------------------------*/
291
292/* pxDelayedTaskList and pxOverflowDelayedTaskList are switched when the tick
293count overflows. */
294#define taskSWITCH_DELAYED_LISTS() \
295{ \
296 List_t *pxTemp; \
297 \
298 /* The delayed tasks list should be empty when the lists are switched. */ \
299 configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) ); \
300 \
301 pxTemp = pxDelayedTaskList; \
302 pxDelayedTaskList = pxOverflowDelayedTaskList; \
303 pxOverflowDelayedTaskList = pxTemp; \
304 xNumOfOverflows++; \
305 prvResetNextTaskUnblockTime(); \
306}
307
308/*-----------------------------------------------------------*/
309
310/*
311 * Place the task represented by pxTCB into the appropriate ready list for
312 * the task. It is inserted at the end of the list.
313 */
314#define prvAddTaskToReadyList( pxTCB ) \
315 traceMOVED_TASK_TO_READY_STATE( pxTCB ); \
316 taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \
317 vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xGenericListItem ) )
318/*-----------------------------------------------------------*/
319
320/*
321 * Several functions take an TaskHandle_t parameter that can optionally be NULL,
322 * where NULL is used to indicate that the handle of the currently executing
323 * task should be used in place of the parameter. This macro simply checks to
324 * see if the parameter is NULL and returns a pointer to the appropriate TCB.
325 */
326#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( TCB_t * ) pxCurrentTCB : ( TCB_t * ) ( pxHandle ) )
327
328/* The item value of the event list item is normally used to hold the priority
329of the task to which it belongs (coded to allow it to be held in reverse
330priority order). However, it is occasionally borrowed for other purposes. It
331is important its value is not updated due to a task priority change while it is
332being used for another purpose. The following bit definition is used to inform
333the scheduler that the value should not be changed - in which case it is the
334responsibility of whichever module is using the value to ensure it gets set back
335to its original value when it is released. */
336#if configUSE_16_BIT_TICKS == 1
337 #define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x8000U
338#else
339 #define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x80000000UL
340#endif
341
342/* Callback function prototypes. --------------------------*/
343#if configCHECK_FOR_STACK_OVERFLOW > 0
344 extern void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName );
345#endif
346
347#if configUSE_TICK_HOOK > 0
348 extern void vApplicationTickHook( void );
349#endif
350
351/* File private functions. --------------------------------*/
352
353/*
354 * Utility to ready a TCB for a given task. Mainly just copies the parameters
355 * into the TCB structure.
356 */
357static void prvInitialiseTCBVariables( TCB_t * const pxTCB, const char * const pcName, UBaseType_t uxPriority, const MemoryRegion_t * const xRegions, const uint16_t usStackDepth ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
358
359/**
360 * Utility task that simply returns pdTRUE if the task referenced by xTask is
361 * currently in the Suspended state, or pdFALSE if the task referenced by xTask
362 * is in any other state.
363 */
364#if ( INCLUDE_vTaskSuspend == 1 )
365 static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
366#endif /* INCLUDE_vTaskSuspend */
367
368/*
369 * Utility to ready all the lists used by the scheduler. This is called
370 * automatically upon the creation of the first task.
371 */
372static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION;
373
374/*
375 * The idle task, which as all tasks is implemented as a never ending loop.
376 * The idle task is automatically created and added to the ready lists upon
377 * creation of the first user task.
378 *
379 * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific
380 * language extensions. The equivalent prototype for this function is:
381 *
382 * void prvIdleTask( void *pvParameters );
383 *
384 */
385static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters );
386
387/*
388 * Utility to free all memory allocated by the scheduler to hold a TCB,
389 * including the stack pointed to by the TCB.
390 *
391 * This does not free memory allocated by the task itself (i.e. memory
392 * allocated by calls to pvPortMalloc from within the tasks application code).
393 */
394#if ( INCLUDE_vTaskDelete == 1 )
395
396 static void prvDeleteTCB( TCB_t *pxTCB ) PRIVILEGED_FUNCTION;
397
398#endif
399
400/*
401 * Used only by the idle task. This checks to see if anything has been placed
402 * in the list of tasks waiting to be deleted. If so the task is cleaned up
403 * and its TCB deleted.
404 */
405static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION;
406
407/*
408 * The currently executing task is entering the Blocked state. Add the task to
409 * either the current or the overflow delayed task list.
410 */
411static void prvAddCurrentTaskToDelayedList( const TickType_t xTimeToWake ) PRIVILEGED_FUNCTION;
412
413/*
414 * Allocates memory from the heap for a TCB and associated stack. Checks the
415 * allocation was successful.
416 */
417static TCB_t *prvAllocateTCBAndStack( const uint16_t usStackDepth, StackType_t * const puxStackBuffer ) PRIVILEGED_FUNCTION;
418
419/*
420 * Fills an TaskStatus_t structure with information on each task that is
421 * referenced from the pxList list (which may be a ready list, a delayed list,
422 * a suspended list, etc.).
423 *
424 * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM
425 * NORMAL APPLICATION CODE.
426 */
427#if ( configUSE_TRACE_FACILITY == 1 )
428
429 static UBaseType_t prvListTaskWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState ) PRIVILEGED_FUNCTION;
430
431#endif
432
433/*
434 * When a task is created, the stack of the task is filled with a known value.
435 * This function determines the 'high water mark' of the task stack by
436 * determining how much of the stack remains at the original preset value.
437 */
438#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
439
440 static uint16_t prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte ) PRIVILEGED_FUNCTION;
441
442#endif
443
444/*
445 * Return the amount of time, in ticks, that will pass before the kernel will
446 * next move a task from the Blocked state to the Running state.
447 *
448 * This conditional compilation should use inequality to 0, not equality to 1.
449 * This is to ensure portSUPPRESS_TICKS_AND_SLEEP() can be called when user
450 * defined low power mode implementations require configUSE_TICKLESS_IDLE to be
451 * set to a value other than 1.
452 */
453#if ( configUSE_TICKLESS_IDLE != 0 )
454
455 static TickType_t prvGetExpectedIdleTime( void ) PRIVILEGED_FUNCTION;
456
457#endif
458
459/*
460 * Set xNextTaskUnblockTime to the time at which the next Blocked state task
461 * will exit the Blocked state.
462 */
463static void prvResetNextTaskUnblockTime( void );
464
465#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) )
466
467 /*
468 * Helper function used to pad task names with spaces when printing out
469 * human readable tables of task information.
470 */
471 static char *prvWriteNameToBuffer( char *pcBuffer, const char *pcTaskName );
472
473#endif
474/*-----------------------------------------------------------*/
475
476BaseType_t xTaskGenericCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, StackType_t * const puxStackBuffer, const MemoryRegion_t * const xRegions ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
477{
478BaseType_t xReturn;
479TCB_t * pxNewTCB;
480StackType_t *pxTopOfStack;
481
482 configASSERT( pxTaskCode );
483 configASSERT( ( ( uxPriority & ( UBaseType_t ) ( ~portPRIVILEGE_BIT ) ) < ( UBaseType_t ) configMAX_PRIORITIES ) );
484
485 /* Allocate the memory required by the TCB and stack for the new task,
486 checking that the allocation was successful. */
487 pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer );
488
489 if( pxNewTCB != NULL )
490 {
491 #if( portUSING_MPU_WRAPPERS == 1 )
492 /* Should the task be created in privileged mode? */
493 BaseType_t xRunPrivileged;
494 if( ( uxPriority & portPRIVILEGE_BIT ) != 0U )
495 {
496 xRunPrivileged = pdTRUE;
497 }
498 else
499 {
500 xRunPrivileged = pdFALSE;
501 }
502 uxPriority &= ~portPRIVILEGE_BIT;
503
504 if( puxStackBuffer != NULL )
505 {
506 /* The application provided its own stack. Note this so no
507 attempt is made to delete the stack should that task be
508 deleted. */
509 pxNewTCB->xUsingStaticallyAllocatedStack = pdTRUE;
510 }
511 else
512 {
513 /* The stack was allocated dynamically. Note this so it can be
514 deleted again if the task is deleted. */
515 pxNewTCB->xUsingStaticallyAllocatedStack = pdFALSE;
516 }
517 #endif /* portUSING_MPU_WRAPPERS == 1 */
518
519 /* Calculate the top of stack address. This depends on whether the
520 stack grows from high memory to low (as per the 80x86) or vice versa.
521 portSTACK_GROWTH is used to make the result positive or negative as
522 required by the port. */
523 #if( portSTACK_GROWTH < 0 )
524 {
525 pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - ( uint16_t ) 1 );
526 pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); /*lint !e923 MISRA exception. Avoiding casts between pointers and integers is not practical. Size differences accounted for using portPOINTER_SIZE_TYPE type. */
527
528 /* Check the alignment of the calculated top of stack is correct. */
529 configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
530 }
531 #else /* portSTACK_GROWTH */
532 {
533 pxTopOfStack = pxNewTCB->pxStack;
534
535 /* Check the alignment of the stack buffer is correct. */
536 configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxNewTCB->pxStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
537
538 /* If we want to use stack checking on architectures that use
539 a positive stack growth direction then we also need to store the
540 other extreme of the stack space. */
541 pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
542 }
543 #endif /* portSTACK_GROWTH */
544
545 /* Setup the newly allocated TCB with the initial state of the task. */
546 prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth );
547
548 /* Initialize the TCB stack to look as if the task was already running,
549 but had been interrupted by the scheduler. The return address is set
550 to the start of the task function. Once the stack has been initialised
551 the top of stack variable is updated. */
552 #if( portUSING_MPU_WRAPPERS == 1 )
553 {
554 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
555 }
556 #else /* portUSING_MPU_WRAPPERS */
557 {
558 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
559 }
560 #endif /* portUSING_MPU_WRAPPERS */
561
562 if( ( void * ) pxCreatedTask != NULL )
563 {
564 /* Pass the TCB out - in an anonymous way. The calling function/
565 task can use this as a handle to delete the task later if
566 required.*/
567 *pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
568 }
569 else
570 {
571 mtCOVERAGE_TEST_MARKER();
572 }
573
574 /* Ensure interrupts don't access the task lists while they are being
575 updated. */
576 taskENTER_CRITICAL();
577 {
578 uxCurrentNumberOfTasks++;
579 if( pxCurrentTCB == NULL )
580 {
581 /* There are no other tasks, or all the other tasks are in
582 the suspended state - make this the current task. */
583 pxCurrentTCB = pxNewTCB;
584
585 if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )
586 {
587 /* This is the first task to be created so do the preliminary
588 initialisation required. We will not recover if this call
589 fails, but we will report the failure. */
590 prvInitialiseTaskLists();
591 }
592 else
593 {
594 mtCOVERAGE_TEST_MARKER();
595 }
596 }
597 else
598 {
599 /* If the scheduler is not already running, make this task the
600 current task if it is the highest priority task to be created
601 so far. */
602 if( xSchedulerRunning == pdFALSE )
603 {
604 if( pxCurrentTCB->uxPriority <= uxPriority )
605 {
606 pxCurrentTCB = pxNewTCB;
607 }
608 else
609 {
610 mtCOVERAGE_TEST_MARKER();
611 }
612 }
613 else
614 {
615 mtCOVERAGE_TEST_MARKER();
616 }
617 }
618
619 uxTaskNumber++;
620
621 #if ( configUSE_TRACE_FACILITY == 1 )
622 {
623 /* Add a counter into the TCB for tracing only. */
624 pxNewTCB->uxTCBNumber = uxTaskNumber;
625 }
626 #endif /* configUSE_TRACE_FACILITY */
627 traceTASK_CREATE( pxNewTCB );
628
629 prvAddTaskToReadyList( pxNewTCB );
630
631 xReturn = pdPASS;
632 portSETUP_TCB( pxNewTCB );
633 }
634 taskEXIT_CRITICAL();
635 }
636 else
637 {
638 xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
639 traceTASK_CREATE_FAILED();
640 }
641
642 if( xReturn == pdPASS )
643 {
644 if( xSchedulerRunning != pdFALSE )
645 {
646 /* If the created task is of a higher priority than the current task
647 then it should run now. */
648 if( pxCurrentTCB->uxPriority < uxPriority )
649 {
650 taskYIELD_IF_USING_PREEMPTION();
651 }
652 else
653 {
654 mtCOVERAGE_TEST_MARKER();
655 }
656 }
657 else
658 {
659 mtCOVERAGE_TEST_MARKER();
660 }
661 }
662
663 return xReturn;
664}
665/*-----------------------------------------------------------*/
666
667#if ( INCLUDE_vTaskDelete == 1 )
668
669 void vTaskDelete( TaskHandle_t xTaskToDelete )
670 {
671 TCB_t *pxTCB;
672
673 taskENTER_CRITICAL();
674 {
675 /* If null is passed in here then it is the calling task that is
676 being deleted. */
677 pxTCB = prvGetTCBFromHandle( xTaskToDelete );
678
679 /* Remove task from the ready list and place in the termination list.
680 This will stop the task from be scheduled. The idle task will check
681 the termination list and free up any memory allocated by the
682 scheduler for the TCB and stack. */
683 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
684 {
685 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
686 }
687 else
688 {
689 mtCOVERAGE_TEST_MARKER();
690 }
691
692 /* Is the task waiting on an event also? */
693 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
694 {
695 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
696 }
697 else
698 {
699 mtCOVERAGE_TEST_MARKER();
700 }
701
702 vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );
703
704 /* Increment the ucTasksDeleted variable so the idle task knows
705 there is a task that has been deleted and that it should therefore
706 check the xTasksWaitingTermination list. */
707 ++uxTasksDeleted;
708
709 /* Increment the uxTaskNumberVariable also so kernel aware debuggers
710 can detect that the task lists need re-generating. */
711 uxTaskNumber++;
712
713 traceTASK_DELETE( pxTCB );
714 }
715 taskEXIT_CRITICAL();
716
717 /* Force a reschedule if it is the currently running task that has just
718 been deleted. */
719 if( xSchedulerRunning != pdFALSE )
720 {
721 if( pxTCB == pxCurrentTCB )
722 {
723 configASSERT( uxSchedulerSuspended == 0 );
724
725 /* The pre-delete hook is primarily for the Windows simulator,
726 in which Windows specific clean up operations are performed,
727 after which it is not possible to yield away from this task -
728 hence xYieldPending is used to latch that a context switch is
729 required. */
730 portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending );
731 portYIELD_WITHIN_API();
732 }
733 else
734 {
735 /* Reset the next expected unblock time in case it referred to
736 the task that has just been deleted. */
737 taskENTER_CRITICAL();
738 {
739 prvResetNextTaskUnblockTime();
740 }
741 taskEXIT_CRITICAL();
742 }
743 }
744 }
745
746#endif /* INCLUDE_vTaskDelete */
747/*-----------------------------------------------------------*/
748
749#if ( INCLUDE_vTaskDelayUntil == 1 )
750
751 void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement )
752 {
753 TickType_t xTimeToWake;
754 BaseType_t xAlreadyYielded, xShouldDelay = pdFALSE;
755
756 configASSERT( pxPreviousWakeTime );
757 configASSERT( ( xTimeIncrement > 0U ) );
758 configASSERT( uxSchedulerSuspended == 0 );
759
760 vTaskSuspendAll();
761 {
762 /* Minor optimisation. The tick count cannot change in this
763 block. */
764 const TickType_t xConstTickCount = xTickCount;
765
766 /* Generate the tick time at which the task wants to wake. */
767 xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
768
769 if( xConstTickCount < *pxPreviousWakeTime )
770 {
771 /* The tick count has overflowed since this function was
772 lasted called. In this case the only time we should ever
773 actually delay is if the wake time has also overflowed,
774 and the wake time is greater than the tick time. When this
775 is the case it is as if neither time had overflowed. */
776 if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xConstTickCount ) )
777 {
778 xShouldDelay = pdTRUE;
779 }
780 else
781 {
782 mtCOVERAGE_TEST_MARKER();
783 }
784 }
785 else
786 {
787 /* The tick time has not overflowed. In this case we will
788 delay if either the wake time has overflowed, and/or the
789 tick time is less than the wake time. */
790 if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xConstTickCount ) )
791 {
792 xShouldDelay = pdTRUE;
793 }
794 else
795 {
796 mtCOVERAGE_TEST_MARKER();
797 }
798 }
799
800 /* Update the wake time ready for the next call. */
801 *pxPreviousWakeTime = xTimeToWake;
802
803 if( xShouldDelay != pdFALSE )
804 {
805 traceTASK_DELAY_UNTIL();
806
807 /* Remove the task from the ready list before adding it to the
808 blocked list as the same list item is used for both lists. */
809 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
810 {
811 /* The current task must be in a ready list, so there is
812 no need to check, and the port reset macro can be called
813 directly. */
814 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
815 }
816 else
817 {
818 mtCOVERAGE_TEST_MARKER();
819 }
820
821 prvAddCurrentTaskToDelayedList( xTimeToWake );
822 }
823 else
824 {
825 mtCOVERAGE_TEST_MARKER();
826 }
827 }
828 xAlreadyYielded = xTaskResumeAll();
829
830 /* Force a reschedule if xTaskResumeAll has not already done so, we may
831 have put ourselves to sleep. */
832 if( xAlreadyYielded == pdFALSE )
833 {
834 portYIELD_WITHIN_API();
835 }
836 else
837 {
838 mtCOVERAGE_TEST_MARKER();
839 }
840 }
841
842#endif /* INCLUDE_vTaskDelayUntil */
843/*-----------------------------------------------------------*/
844
845#if ( INCLUDE_vTaskDelay == 1 )
846
847 void vTaskDelay( const TickType_t xTicksToDelay )
848 {
849 TickType_t xTimeToWake;
850 BaseType_t xAlreadyYielded = pdFALSE;
851
852
853 /* A delay time of zero just forces a reschedule. */
854 if( xTicksToDelay > ( TickType_t ) 0U )
855 {
856 configASSERT( uxSchedulerSuspended == 0 );
857 vTaskSuspendAll();
858 {
859 traceTASK_DELAY();
860
861 /* A task that is removed from the event list while the
862 scheduler is suspended will not get placed in the ready
863 list or removed from the blocked list until the scheduler
864 is resumed.
865
866 This task cannot be in an event list as it is the currently
867 executing task. */
868
869 /* Calculate the time to wake - this may overflow but this is
870 not a problem. */
871 xTimeToWake = xTickCount + xTicksToDelay;
872
873 /* We must remove ourselves from the ready list before adding
874 ourselves to the blocked list as the same list item is used for
875 both lists. */
876 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
877 {
878 /* The current task must be in a ready list, so there is
879 no need to check, and the port reset macro can be called
880 directly. */
881 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
882 }
883 else
884 {
885 mtCOVERAGE_TEST_MARKER();
886 }
887 prvAddCurrentTaskToDelayedList( xTimeToWake );
888 }
889 xAlreadyYielded = xTaskResumeAll();
890 }
891 else
892 {
893 mtCOVERAGE_TEST_MARKER();
894 }
895
896 /* Force a reschedule if xTaskResumeAll has not already done so, we may
897 have put ourselves to sleep. */
898 if( xAlreadyYielded == pdFALSE )
899 {
900 portYIELD_WITHIN_API();
901 }
902 else
903 {
904 mtCOVERAGE_TEST_MARKER();
905 }
906 }
907
908#endif /* INCLUDE_vTaskDelay */
909/*-----------------------------------------------------------*/
910
911#if ( INCLUDE_eTaskGetState == 1 )
912
913 eTaskState eTaskGetState( TaskHandle_t xTask )
914 {
915 eTaskState eReturn;
916 List_t *pxStateList;
917 const TCB_t * const pxTCB = ( TCB_t * ) xTask;
918
919 configASSERT( pxTCB );
920
921 if( pxTCB == pxCurrentTCB )
922 {
923 /* The task calling this function is querying its own state. */
924 eReturn = eRunning;
925 }
926 else
927 {
928 taskENTER_CRITICAL();
929 {
930 pxStateList = ( List_t * ) listLIST_ITEM_CONTAINER( &( pxTCB->xGenericListItem ) );
931 }
932 taskEXIT_CRITICAL();
933
934 if( ( pxStateList == pxDelayedTaskList ) || ( pxStateList == pxOverflowDelayedTaskList ) )
935 {
936 /* The task being queried is referenced from one of the Blocked
937 lists. */
938 eReturn = eBlocked;
939 }
940
941 #if ( INCLUDE_vTaskSuspend == 1 )
942 else if( pxStateList == &xSuspendedTaskList )
943 {
944 /* The task being queried is referenced from the suspended
945 list. Is it genuinely suspended or is it block
946 indefinitely? */
947 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL )
948 {
949 eReturn = eSuspended;
950 }
951 else
952 {
953 eReturn = eBlocked;
954 }
955 }
956 #endif
957
958 #if ( INCLUDE_vTaskDelete == 1 )
959 else if( pxStateList == &xTasksWaitingTermination )
960 {
961 /* The task being queried is referenced from the deleted
962 tasks list. */
963 eReturn = eDeleted;
964 }
965 #endif
966
967 else
968 {
969 /* If the task is not in any other state, it must be in the
970 Ready (including pending ready) state. */
971 eReturn = eReady;
972 }
973 }
974
975 return eReturn;
976 }
977
978#endif /* INCLUDE_eTaskGetState */
979/*-----------------------------------------------------------*/
980
981#if ( INCLUDE_uxTaskPriorityGet == 1 )
982
983 UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask )
984 {
985 TCB_t *pxTCB;
986 UBaseType_t uxReturn;
987
988 taskENTER_CRITICAL();
989 {
990 /* If null is passed in here then it is the priority of the that
991 called uxTaskPriorityGet() that is being queried. */
992 pxTCB = prvGetTCBFromHandle( xTask );
993 uxReturn = pxTCB->uxPriority;
994 }
995 taskEXIT_CRITICAL();
996
997 return uxReturn;
998 }
999
1000#endif /* INCLUDE_uxTaskPriorityGet */
1001/*-----------------------------------------------------------*/
1002
1003#if ( INCLUDE_uxTaskPriorityGet == 1 )
1004
1005 UBaseType_t uxTaskPriorityGetFromISR( TaskHandle_t xTask )
1006 {
1007 TCB_t *pxTCB;
1008 UBaseType_t uxReturn, uxSavedInterruptState;
1009
1010 /* RTOS ports that support interrupt nesting have the concept of a
1011 maximum system call (or maximum API call) interrupt priority.
1012 Interrupts that are above the maximum system call priority are keep
1013 permanently enabled, even when the RTOS kernel is in a critical section,
1014 but cannot make any calls to FreeRTOS API functions. If configASSERT()
1015 is defined in FreeRTOSConfig.h then
1016 portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
1017 failure if a FreeRTOS API function is called from an interrupt that has
1018 been assigned a priority above the configured maximum system call
1019 priority. Only FreeRTOS functions that end in FromISR can be called
1020 from interrupts that have been assigned a priority at or (logically)
1021 below the maximum system call interrupt priority. FreeRTOS maintains a
1022 separate interrupt safe API to ensure interrupt entry is as fast and as
1023 simple as possible. More information (albeit Cortex-M specific) is
1024 provided on the following link:
1025 http://www.freertos.org/RTOS-Cortex-M3-M4.html */
1026 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
1027
1028 uxSavedInterruptState = portSET_INTERRUPT_MASK_FROM_ISR();
1029 {
1030 /* If null is passed in here then it is the priority of the calling
1031 task that is being queried. */
1032 pxTCB = prvGetTCBFromHandle( xTask );
1033 uxReturn = pxTCB->uxPriority;
1034 }
1035 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptState );
1036
1037 return uxReturn;
1038 }
1039
1040#endif /* INCLUDE_uxTaskPriorityGet */
1041/*-----------------------------------------------------------*/
1042
1043#if ( INCLUDE_vTaskPrioritySet == 1 )
1044
1045 void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority )
1046 {
1047 TCB_t *pxTCB;
1048 UBaseType_t uxCurrentBasePriority, uxPriorityUsedOnEntry;
1049 BaseType_t xYieldRequired = pdFALSE;
1050
1051 configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) );
1052
1053 /* Ensure the new priority is valid. */
1054 if( uxNewPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
1055 {
1056 uxNewPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
1057 }
1058 else
1059 {
1060 mtCOVERAGE_TEST_MARKER();
1061 }
1062
1063 taskENTER_CRITICAL();
1064 {
1065 /* If null is passed in here then it is the priority of the calling
1066 task that is being changed. */
1067 pxTCB = prvGetTCBFromHandle( xTask );
1068
1069 traceTASK_PRIORITY_SET( pxTCB, uxNewPriority );
1070
1071 #if ( configUSE_MUTEXES == 1 )
1072 {
1073 uxCurrentBasePriority = pxTCB->uxBasePriority;
1074 }
1075 #else
1076 {
1077 uxCurrentBasePriority = pxTCB->uxPriority;
1078 }
1079 #endif
1080
1081 if( uxCurrentBasePriority != uxNewPriority )
1082 {
1083 /* The priority change may have readied a task of higher
1084 priority than the calling task. */
1085 if( uxNewPriority > uxCurrentBasePriority )
1086 {
1087 if( pxTCB != pxCurrentTCB )
1088 {
1089 /* The priority of a task other than the currently
1090 running task is being raised. Is the priority being
1091 raised above that of the running task? */
1092 if( uxNewPriority >= pxCurrentTCB->uxPriority )
1093 {
1094 xYieldRequired = pdTRUE;
1095 }
1096 else
1097 {
1098 mtCOVERAGE_TEST_MARKER();
1099 }
1100 }
1101 else
1102 {
1103 /* The priority of the running task is being raised,
1104 but the running task must already be the highest
1105 priority task able to run so no yield is required. */
1106 }
1107 }
1108 else if( pxTCB == pxCurrentTCB )
1109 {
1110 /* Setting the priority of the running task down means
1111 there may now be another task of higher priority that
1112 is ready to execute. */
1113 xYieldRequired = pdTRUE;
1114 }
1115 else
1116 {
1117 /* Setting the priority of any other task down does not
1118 require a yield as the running task must be above the
1119 new priority of the task being modified. */
1120 }
1121
1122 /* Remember the ready list the task might be referenced from
1123 before its uxPriority member is changed so the
1124 taskRESET_READY_PRIORITY() macro can function correctly. */
1125 uxPriorityUsedOnEntry = pxTCB->uxPriority;
1126
1127 #if ( configUSE_MUTEXES == 1 )
1128 {
1129 /* Only change the priority being used if the task is not
1130 currently using an inherited priority. */
1131 if( pxTCB->uxBasePriority == pxTCB->uxPriority )
1132 {
1133 pxTCB->uxPriority = uxNewPriority;
1134 }
1135 else
1136 {
1137 mtCOVERAGE_TEST_MARKER();
1138 }
1139
1140 /* The base priority gets set whatever. */
1141 pxTCB->uxBasePriority = uxNewPriority;
1142 }
1143 #else
1144 {
1145 pxTCB->uxPriority = uxNewPriority;
1146 }
1147 #endif
1148
1149 /* Only reset the event list item value if the value is not
1150 being used for anything else. */
1151 if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
1152 {
1153 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxNewPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
1154 }
1155 else
1156 {
1157 mtCOVERAGE_TEST_MARKER();
1158 }
1159
1160 /* If the task is in the blocked or suspended list we need do
1161 nothing more than change it's priority variable. However, if
1162 the task is in a ready list it needs to be removed and placed
1163 in the list appropriate to its new priority. */
1164 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xGenericListItem ) ) != pdFALSE )
1165 {
1166 /* The task is currently in its ready list - remove before adding
1167 it to it's new ready list. As we are in a critical section we
1168 can do this even if the scheduler is suspended. */
1169 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
1170 {
1171 /* It is known that the task is in its ready list so
1172 there is no need to check again and the port level
1173 reset macro can be called directly. */
1174 portRESET_READY_PRIORITY( uxPriorityUsedOnEntry, uxTopReadyPriority );
1175 }
1176 else
1177 {
1178 mtCOVERAGE_TEST_MARKER();
1179 }
1180 prvAddTaskToReadyList( pxTCB );
1181 }
1182 else
1183 {
1184 mtCOVERAGE_TEST_MARKER();
1185 }
1186
1187 if( xYieldRequired == pdTRUE )
1188 {
1189 taskYIELD_IF_USING_PREEMPTION();
1190 }
1191 else
1192 {
1193 mtCOVERAGE_TEST_MARKER();
1194 }
1195
1196 /* Remove compiler warning about unused variables when the port
1197 optimised task selection is not being used. */
1198 ( void ) uxPriorityUsedOnEntry;
1199 }
1200 }
1201 taskEXIT_CRITICAL();
1202 }
1203
1204#endif /* INCLUDE_vTaskPrioritySet */
1205/*-----------------------------------------------------------*/
1206
1207#if ( INCLUDE_vTaskSuspend == 1 )
1208
1209 void vTaskSuspend( TaskHandle_t xTaskToSuspend )
1210 {
1211 TCB_t *pxTCB;
1212
1213 taskENTER_CRITICAL();
1214 {
1215 /* If null is passed in here then it is the running task that is
1216 being suspended. */
1217 pxTCB = prvGetTCBFromHandle( xTaskToSuspend );
1218
1219 traceTASK_SUSPEND( pxTCB );
1220
1221 /* Remove task from the ready/delayed list and place in the
1222 suspended list. */
1223 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
1224 {
1225 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
1226 }
1227 else
1228 {
1229 mtCOVERAGE_TEST_MARKER();
1230 }
1231
1232 /* Is the task waiting on an event also? */
1233 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
1234 {
1235 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
1236 }
1237 else
1238 {
1239 mtCOVERAGE_TEST_MARKER();
1240 }
1241
1242 vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );
1243 }
1244 taskEXIT_CRITICAL();
1245
1246 if( pxTCB == pxCurrentTCB )
1247 {
1248 if( xSchedulerRunning != pdFALSE )
1249 {
1250 /* The current task has just been suspended. */
1251 configASSERT( uxSchedulerSuspended == 0 );
1252 portYIELD_WITHIN_API();
1253 }
1254 else
1255 {
1256 /* The scheduler is not running, but the task that was pointed
1257 to by pxCurrentTCB has just been suspended and pxCurrentTCB
1258 must be adjusted to point to a different task. */
1259 if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks )
1260 {
1261 /* No other tasks are ready, so set pxCurrentTCB back to
1262 NULL so when the next task is created pxCurrentTCB will
1263 be set to point to it no matter what its relative priority
1264 is. */
1265 pxCurrentTCB = NULL;
1266 }
1267 else
1268 {
1269 vTaskSwitchContext();
1270 }
1271 }
1272 }
1273 else
1274 {
1275 if( xSchedulerRunning != pdFALSE )
1276 {
1277 /* A task other than the currently running task was suspended,
1278 reset the next expected unblock time in case it referred to the
1279 task that is now in the Suspended state. */
1280 taskENTER_CRITICAL();
1281 {
1282 prvResetNextTaskUnblockTime();
1283 }
1284 taskEXIT_CRITICAL();
1285 }
1286 else
1287 {
1288 mtCOVERAGE_TEST_MARKER();
1289 }
1290 }
1291 }
1292
1293#endif /* INCLUDE_vTaskSuspend */
1294/*-----------------------------------------------------------*/
1295
1296#if ( INCLUDE_vTaskSuspend == 1 )
1297
1298 static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask )
1299 {
1300 BaseType_t xReturn = pdFALSE;
1301 const TCB_t * const pxTCB = ( TCB_t * ) xTask;
1302
1303 /* Accesses xPendingReadyList so must be called from a critical
1304 section. */
1305
1306 /* It does not make sense to check if the calling task is suspended. */
1307 configASSERT( xTask );
1308
1309 /* Is the task being resumed actually in the suspended list? */
1310 if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE )
1311 {
1312 /* Has the task already been resumed from within an ISR? */
1313 if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) == pdFALSE )
1314 {
1315 /* Is it in the suspended list because it is in the Suspended
1316 state, or because is is blocked with no timeout? */
1317 if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) != pdFALSE )
1318 {
1319 xReturn = pdTRUE;
1320 }
1321 else
1322 {
1323 mtCOVERAGE_TEST_MARKER();
1324 }
1325 }
1326 else
1327 {
1328 mtCOVERAGE_TEST_MARKER();
1329 }
1330 }
1331 else
1332 {
1333 mtCOVERAGE_TEST_MARKER();
1334 }
1335
1336 return xReturn;
1337 } /*lint !e818 xTask cannot be a pointer to const because it is a typedef. */
1338
1339#endif /* INCLUDE_vTaskSuspend */
1340/*-----------------------------------------------------------*/
1341
1342#if ( INCLUDE_vTaskSuspend == 1 )
1343
1344 void vTaskResume( TaskHandle_t xTaskToResume )
1345 {
1346 TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume;
1347
1348 /* It does not make sense to resume the calling task. */
1349 configASSERT( xTaskToResume );
1350
1351 /* The parameter cannot be NULL as it is impossible to resume the
1352 currently executing task. */
1353 if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
1354 {
1355 taskENTER_CRITICAL();
1356 {
1357 if( prvTaskIsTaskSuspended( pxTCB ) == pdTRUE )
1358 {
1359 traceTASK_RESUME( pxTCB );
1360
1361 /* As we are in a critical section we can access the ready
1362 lists even if the scheduler is suspended. */
1363 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
1364 prvAddTaskToReadyList( pxTCB );
1365
1366 /* We may have just resumed a higher priority task. */
1367 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
1368 {
1369 /* This yield may not cause the task just resumed to run,
1370 but will leave the lists in the correct state for the
1371 next yield. */
1372 taskYIELD_IF_USING_PREEMPTION();
1373 }
1374 else
1375 {
1376 mtCOVERAGE_TEST_MARKER();
1377 }
1378 }
1379 else
1380 {
1381 mtCOVERAGE_TEST_MARKER();
1382 }
1383 }
1384 taskEXIT_CRITICAL();
1385 }
1386 else
1387 {
1388 mtCOVERAGE_TEST_MARKER();
1389 }
1390 }
1391
1392#endif /* INCLUDE_vTaskSuspend */
1393
1394/*-----------------------------------------------------------*/
1395
1396#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
1397
1398 BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume )
1399 {
1400 BaseType_t xYieldRequired = pdFALSE;
1401 TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume;
1402 UBaseType_t uxSavedInterruptStatus;
1403
1404 configASSERT( xTaskToResume );
1405
1406 /* RTOS ports that support interrupt nesting have the concept of a
1407 maximum system call (or maximum API call) interrupt priority.
1408 Interrupts that are above the maximum system call priority are keep
1409 permanently enabled, even when the RTOS kernel is in a critical section,
1410 but cannot make any calls to FreeRTOS API functions. If configASSERT()
1411 is defined in FreeRTOSConfig.h then
1412 portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
1413 failure if a FreeRTOS API function is called from an interrupt that has
1414 been assigned a priority above the configured maximum system call
1415 priority. Only FreeRTOS functions that end in FromISR can be called
1416 from interrupts that have been assigned a priority at or (logically)
1417 below the maximum system call interrupt priority. FreeRTOS maintains a
1418 separate interrupt safe API to ensure interrupt entry is as fast and as
1419 simple as possible. More information (albeit Cortex-M specific) is
1420 provided on the following link:
1421 http://www.freertos.org/RTOS-Cortex-M3-M4.html */
1422 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
1423
1424 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
1425 {
1426 if( prvTaskIsTaskSuspended( pxTCB ) == pdTRUE )
1427 {
1428 traceTASK_RESUME_FROM_ISR( pxTCB );
1429
1430 /* Check the ready lists can be accessed. */
1431 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
1432 {
1433 /* Ready lists can be accessed so move the task from the
1434 suspended list to the ready list directly. */
1435 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
1436 {
1437 xYieldRequired = pdTRUE;
1438 }
1439 else
1440 {
1441 mtCOVERAGE_TEST_MARKER();
1442 }
1443
1444 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
1445 prvAddTaskToReadyList( pxTCB );
1446 }
1447 else
1448 {
1449 /* The delayed or ready lists cannot be accessed so the task
1450 is held in the pending ready list until the scheduler is
1451 unsuspended. */
1452 vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
1453 }
1454 }
1455 else
1456 {
1457 mtCOVERAGE_TEST_MARKER();
1458 }
1459 }
1460 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
1461
1462 return xYieldRequired;
1463 }
1464
1465#endif /* ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) */
1466/*-----------------------------------------------------------*/
1467
1468void vTaskStartScheduler( void )
1469{
1470BaseType_t xReturn;
1471
1472 /* Add the idle task at the lowest priority. */
1473 #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
1474 {
1475 /* Create the idle task, storing its handle in xIdleTaskHandle so it can
1476 be returned by the xTaskGetIdleTaskHandle() function. */
1477 xReturn = xTaskCreate( prvIdleTask, "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
1478 }
1479 #else
1480 {
1481 /* Create the idle task without storing its handle. */
1482 xReturn = xTaskCreate( prvIdleTask, "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), NULL ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
1483 }
1484 #endif /* INCLUDE_xTaskGetIdleTaskHandle */
1485
1486 #if ( configUSE_TIMERS == 1 )
1487 {
1488 if( xReturn == pdPASS )
1489 {
1490 xReturn = xTimerCreateTimerTask();
1491 }
1492 else
1493 {
1494 mtCOVERAGE_TEST_MARKER();
1495 }
1496 }
1497 #endif /* configUSE_TIMERS */
1498
1499 if( xReturn == pdPASS )
1500 {
1501 /* Interrupts are turned off here, to ensure a tick does not occur
1502 before or during the call to xPortStartScheduler(). The stacks of
1503 the created tasks contain a status word with interrupts switched on
1504 so interrupts will automatically get re-enabled when the first task
1505 starts to run. */
1506 portDISABLE_INTERRUPTS();
1507
1508 #if ( configUSE_NEWLIB_REENTRANT == 1 )
1509 {
1510 /* Switch Newlib's _impure_ptr variable to point to the _reent
1511 structure specific to the task that will run first. */
1512 _impure_ptr = &( pxCurrentTCB->xNewLib_reent );
1513 }
1514 #endif /* configUSE_NEWLIB_REENTRANT */
1515
1516 xNextTaskUnblockTime = portMAX_DELAY;
1517 xSchedulerRunning = pdTRUE;
1518 xTickCount = ( TickType_t ) 0U;
1519
1520 /* If configGENERATE_RUN_TIME_STATS is defined then the following
1521 macro must be defined to configure the timer/counter used to generate
1522 the run time counter time base. */
1523 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();
1524
1525 /* Setting up the timer tick is hardware specific and thus in the
1526 portable interface. */
1527 if( xPortStartScheduler() != pdFALSE )
1528 {
1529 /* Should not reach here as if the scheduler is running the
1530 function will not return. */
1531 }
1532 else
1533 {
1534 /* Should only reach here if a task calls xTaskEndScheduler(). */
1535 }
1536 }
1537 else
1538 {
1539 /* This line will only be reached if the kernel could not be started,
1540 because there was not enough FreeRTOS heap to create the idle task
1541 or the timer task. */
1542 configASSERT( xReturn );
1543 }
1544}
1545/*-----------------------------------------------------------*/
1546
1547void vTaskEndScheduler( void )
1548{
1549 /* Stop the scheduler interrupts and call the portable scheduler end
1550 routine so the original ISRs can be restored if necessary. The port
1551 layer must ensure interrupts enable bit is left in the correct state. */
1552 portDISABLE_INTERRUPTS();
1553 xSchedulerRunning = pdFALSE;
1554 vPortEndScheduler();
1555 portENABLE_INTERRUPTS(); /* As per comment, enable interrupts. */
1556}
1557/*----------------------------------------------------------*/
1558
1559void vTaskSuspendAll( void )
1560{
1561 /* A critical section is not required as the variable is of type
1562 BaseType_t. Please read Richard Barry's reply in the following link to a
1563 post in the FreeRTOS support forum before reporting this as a bug! -
1564 http://goo.gl/wu4acr */
1565 ++uxSchedulerSuspended;
1566}
1567/*----------------------------------------------------------*/
1568
1569#if ( configUSE_TICKLESS_IDLE != 0 )
1570
1571 static TickType_t prvGetExpectedIdleTime( void )
1572 {
1573 TickType_t xReturn;
1574
1575 if( pxCurrentTCB->uxPriority > tskIDLE_PRIORITY )
1576 {
1577 xReturn = 0;
1578 }
1579 else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > 1 )
1580 {
1581 /* There are other idle priority tasks in the ready state. If
1582 time slicing is used then the very next tick interrupt must be
1583 processed. */
1584 xReturn = 0;
1585 }
1586 else
1587 {
1588 xReturn = xNextTaskUnblockTime - xTickCount;
1589 }
1590
1591 return xReturn;
1592 }
1593
1594#endif /* configUSE_TICKLESS_IDLE */
1595/*----------------------------------------------------------*/
1596
1597BaseType_t xTaskResumeAll( void )
1598{
1599TCB_t *pxTCB;
1600BaseType_t xAlreadyYielded = pdFALSE;
1601
1602 /* If uxSchedulerSuspended is zero then this function does not match a
1603 previous call to vTaskSuspendAll(). */
1604 configASSERT( uxSchedulerSuspended );
1605
1606 /* It is possible that an ISR caused a task to be removed from an event
1607 list while the scheduler was suspended. If this was the case then the
1608 removed task will have been added to the xPendingReadyList. Once the
1609 scheduler has been resumed it is safe to move all the pending ready
1610 tasks from this list into their appropriate ready list. */
1611 taskENTER_CRITICAL();
1612 {
1613 --uxSchedulerSuspended;
1614
1615 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
1616 {
1617 if( uxCurrentNumberOfTasks > ( UBaseType_t ) 0U )
1618 {
1619 /* Move any readied tasks from the pending list into the
1620 appropriate ready list. */
1621 while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE )
1622 {
1623 pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) );
1624 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
1625 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
1626 prvAddTaskToReadyList( pxTCB );
1627
1628 /* If the moved task has a priority higher than the current
1629 task then a yield must be performed. */
1630 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
1631 {
1632 xYieldPending = pdTRUE;
1633 }
1634 else
1635 {
1636 mtCOVERAGE_TEST_MARKER();
1637 }
1638 }
1639
1640 /* If any ticks occurred while the scheduler was suspended then
1641 they should be processed now. This ensures the tick count does
1642 not slip, and that any delayed tasks are resumed at the correct
1643 time. */
1644 if( uxPendedTicks > ( UBaseType_t ) 0U )
1645 {
1646 while( uxPendedTicks > ( UBaseType_t ) 0U )
1647 {
1648 if( xTaskIncrementTick() != pdFALSE )
1649 {
1650 xYieldPending = pdTRUE;
1651 }
1652 else
1653 {
1654 mtCOVERAGE_TEST_MARKER();
1655 }
1656 --uxPendedTicks;
1657 }
1658 }
1659 else
1660 {
1661 mtCOVERAGE_TEST_MARKER();
1662 }
1663
1664 if( xYieldPending == pdTRUE )
1665 {
1666 #if( configUSE_PREEMPTION != 0 )
1667 {
1668 xAlreadyYielded = pdTRUE;
1669 }
1670 #endif
1671 taskYIELD_IF_USING_PREEMPTION();
1672 }
1673 else
1674 {
1675 mtCOVERAGE_TEST_MARKER();
1676 }
1677 }
1678 }
1679 else
1680 {
1681 mtCOVERAGE_TEST_MARKER();
1682 }
1683 }
1684 taskEXIT_CRITICAL();
1685
1686 return xAlreadyYielded;
1687}
1688/*-----------------------------------------------------------*/
1689
1690TickType_t xTaskGetTickCount( void )
1691{
1692TickType_t xTicks;
1693
1694 /* Critical section required if running on a 16 bit processor. */
1695 portTICK_TYPE_ENTER_CRITICAL();
1696 {
1697 xTicks = xTickCount;
1698 }
1699 portTICK_TYPE_EXIT_CRITICAL();
1700
1701 return xTicks;
1702}
1703/*-----------------------------------------------------------*/
1704
1705TickType_t xTaskGetTickCountFromISR( void )
1706{
1707TickType_t xReturn;
1708UBaseType_t uxSavedInterruptStatus;
1709
1710 /* RTOS ports that support interrupt nesting have the concept of a maximum
1711 system call (or maximum API call) interrupt priority. Interrupts that are
1712 above the maximum system call priority are kept permanently enabled, even
1713 when the RTOS kernel is in a critical section, but cannot make any calls to
1714 FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h
1715 then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
1716 failure if a FreeRTOS API function is called from an interrupt that has been
1717 assigned a priority above the configured maximum system call priority.
1718 Only FreeRTOS functions that end in FromISR can be called from interrupts
1719 that have been assigned a priority at or (logically) below the maximum
1720 system call interrupt priority. FreeRTOS maintains a separate interrupt
1721 safe API to ensure interrupt entry is as fast and as simple as possible.
1722 More information (albeit Cortex-M specific) is provided on the following
1723 link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */
1724 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
1725
1726 uxSavedInterruptStatus = portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR();
1727 {
1728 xReturn = xTickCount;
1729 }
1730 portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
1731
1732 return xReturn;
1733}
1734/*-----------------------------------------------------------*/
1735
1736UBaseType_t uxTaskGetNumberOfTasks( void )
1737{
1738 /* A critical section is not required because the variables are of type
1739 BaseType_t. */
1740 return uxCurrentNumberOfTasks;
1741}
1742/*-----------------------------------------------------------*/
1743
1744#if ( INCLUDE_pcTaskGetTaskName == 1 )
1745
1746 char *pcTaskGetTaskName( TaskHandle_t xTaskToQuery )
1747 {
1748 TCB_t *pxTCB;
1749
1750 /* If null is passed in here then the name of the calling task is being queried. */
1751 pxTCB = prvGetTCBFromHandle( xTaskToQuery );
1752 configASSERT( pxTCB );
1753 return &( pxTCB->pcTaskName[ 0 ] );
1754 }
1755
1756#endif /* INCLUDE_pcTaskGetTaskName */
1757/*-----------------------------------------------------------*/
1758
1759#if ( configUSE_TRACE_FACILITY == 1 )
1760
1761 UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime )
1762 {
1763 UBaseType_t uxTask = 0, uxQueue = configMAX_PRIORITIES;
1764
1765 vTaskSuspendAll();
1766 {
1767 /* Is there a space in the array for each task in the system? */
1768 if( uxArraySize >= uxCurrentNumberOfTasks )
1769 {
1770 /* Fill in an TaskStatus_t structure with information on each
1771 task in the Ready state. */
1772 do
1773 {
1774 uxQueue--;
1775 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &( pxReadyTasksLists[ uxQueue ] ), eReady );
1776
1777 } while( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
1778
1779 /* Fill in an TaskStatus_t structure with information on each
1780 task in the Blocked state. */
1781 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxDelayedTaskList, eBlocked );
1782 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxOverflowDelayedTaskList, eBlocked );
1783
1784 #if( INCLUDE_vTaskDelete == 1 )
1785 {
1786 /* Fill in an TaskStatus_t structure with information on
1787 each task that has been deleted but not yet cleaned up. */
1788 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xTasksWaitingTermination, eDeleted );
1789 }
1790 #endif
1791
1792 #if ( INCLUDE_vTaskSuspend == 1 )
1793 {
1794 /* Fill in an TaskStatus_t structure with information on
1795 each task in the Suspended state. */
1796 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xSuspendedTaskList, eSuspended );
1797 }
1798 #endif
1799
1800 #if ( configGENERATE_RUN_TIME_STATS == 1)
1801 {
1802 if( pulTotalRunTime != NULL )
1803 {
1804 #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
1805 portALT_GET_RUN_TIME_COUNTER_VALUE( ( *pulTotalRunTime ) );
1806 #else
1807 *pulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
1808 #endif
1809 }
1810 }
1811 #else
1812 {
1813 if( pulTotalRunTime != NULL )
1814 {
1815 *pulTotalRunTime = 0;
1816 }
1817 }
1818 #endif
1819 }
1820 else
1821 {
1822 mtCOVERAGE_TEST_MARKER();
1823 }
1824 }
1825 ( void ) xTaskResumeAll();
1826
1827 return uxTask;
1828 }
1829
1830#endif /* configUSE_TRACE_FACILITY */
1831/*----------------------------------------------------------*/
1832
1833#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
1834
1835 TaskHandle_t xTaskGetIdleTaskHandle( void )
1836 {
1837 /* If xTaskGetIdleTaskHandle() is called before the scheduler has been
1838 started, then xIdleTaskHandle will be NULL. */
1839 configASSERT( ( xIdleTaskHandle != NULL ) );
1840 return xIdleTaskHandle;
1841 }
1842
1843#endif /* INCLUDE_xTaskGetIdleTaskHandle */
1844/*----------------------------------------------------------*/
1845
1846/* This conditional compilation should use inequality to 0, not equality to 1.
1847This is to ensure vTaskStepTick() is available when user defined low power mode
1848implementations require configUSE_TICKLESS_IDLE to be set to a value other than
18491. */
1850#if ( configUSE_TICKLESS_IDLE != 0 )
1851
1852 void vTaskStepTick( const TickType_t xTicksToJump )
1853 {
1854 /* Correct the tick count value after a period during which the tick
1855 was suppressed. Note this does *not* call the tick hook function for
1856 each stepped tick. */
1857 configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime );
1858 xTickCount += xTicksToJump;
1859 traceINCREASE_TICK_COUNT( xTicksToJump );
1860 }
1861
1862#endif /* configUSE_TICKLESS_IDLE */
1863/*----------------------------------------------------------*/
1864
1865BaseType_t xTaskIncrementTick( void )
1866{
1867TCB_t * pxTCB;
1868TickType_t xItemValue;
1869BaseType_t xSwitchRequired = pdFALSE;
1870
1871 /* Called by the portable layer each time a tick interrupt occurs.
1872 Increments the tick then checks to see if the new tick value will cause any
1873 tasks to be unblocked. */
1874 traceTASK_INCREMENT_TICK( xTickCount );
1875 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
1876 {
1877 /* Increment the RTOS tick, switching the delayed and overflowed
1878 delayed lists if it wraps to 0. */
1879 ++xTickCount;
1880
1881 {
1882 /* Minor optimisation. The tick count cannot change in this
1883 block. */
1884 const TickType_t xConstTickCount = xTickCount;
1885
1886 if( xConstTickCount == ( TickType_t ) 0U )
1887 {
1888 taskSWITCH_DELAYED_LISTS();
1889 }
1890 else
1891 {
1892 mtCOVERAGE_TEST_MARKER();
1893 }
1894
1895 /* See if this tick has made a timeout expire. Tasks are stored in
1896 the queue in the order of their wake time - meaning once one task
1897 has been found whose block time has not expired there is no need to
1898 look any further down the list. */
1899 if( xConstTickCount >= xNextTaskUnblockTime )
1900 {
1901 for( ;; )
1902 {
1903 if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
1904 {
1905 /* The delayed list is empty. Set xNextTaskUnblockTime
1906 to the maximum possible value so it is extremely
1907 unlikely that the
1908 if( xTickCount >= xNextTaskUnblockTime ) test will pass
1909 next time through. */
1910 xNextTaskUnblockTime = portMAX_DELAY;
1911 break;
1912 }
1913 else
1914 {
1915 /* The delayed list is not empty, get the value of the
1916 item at the head of the delayed list. This is the time
1917 at which the task at the head of the delayed list must
1918 be removed from the Blocked state. */
1919 pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
1920 xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) );
1921
1922 if( xConstTickCount < xItemValue )
1923 {
1924 /* It is not time to unblock this item yet, but the
1925 item value is the time at which the task at the head
1926 of the blocked list must be removed from the Blocked
1927 state - so record the item value in
1928 xNextTaskUnblockTime. */
1929 xNextTaskUnblockTime = xItemValue;
1930 break;
1931 }
1932 else
1933 {
1934 mtCOVERAGE_TEST_MARKER();
1935 }
1936
1937 /* It is time to remove the item from the Blocked state. */
1938 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
1939
1940 /* Is the task waiting on an event also? If so remove
1941 it from the event list. */
1942 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
1943 {
1944 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
1945 }
1946 else
1947 {
1948 mtCOVERAGE_TEST_MARKER();
1949 }
1950
1951 /* Place the unblocked task into the appropriate ready
1952 list. */
1953 prvAddTaskToReadyList( pxTCB );
1954
1955 /* A task being unblocked cannot cause an immediate
1956 context switch if preemption is turned off. */
1957 #if ( configUSE_PREEMPTION == 1 )
1958 {
1959 /* Preemption is on, but a context switch should
1960 only be performed if the unblocked task has a
1961 priority that is equal to or higher than the
1962 currently executing task. */
1963 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
1964 {
1965 xSwitchRequired = pdTRUE;
1966 }
1967 else
1968 {
1969 mtCOVERAGE_TEST_MARKER();
1970 }
1971 }
1972 #endif /* configUSE_PREEMPTION */
1973 }
1974 }
1975 }
1976 }
1977
1978 /* Tasks of equal priority to the currently running task will share
1979 processing time (time slice) if preemption is on, and the application
1980 writer has not explicitly turned time slicing off. */
1981 #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )
1982 {
1983 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( UBaseType_t ) 1 )
1984 {
1985 xSwitchRequired = pdTRUE;
1986 }
1987 else
1988 {
1989 mtCOVERAGE_TEST_MARKER();
1990 }
1991 }
1992 #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */
1993
1994 #if ( configUSE_TICK_HOOK == 1 )
1995 {
1996 /* Guard against the tick hook being called when the pended tick
1997 count is being unwound (when the scheduler is being unlocked). */
1998 if( uxPendedTicks == ( UBaseType_t ) 0U )
1999 {
2000 vApplicationTickHook();
2001 }
2002 else
2003 {
2004 mtCOVERAGE_TEST_MARKER();
2005 }
2006 }
2007 #endif /* configUSE_TICK_HOOK */
2008 }
2009 else
2010 {
2011 ++uxPendedTicks;
2012
2013 /* The tick hook gets called at regular intervals, even if the
2014 scheduler is locked. */
2015 #if ( configUSE_TICK_HOOK == 1 )
2016 {
2017 vApplicationTickHook();
2018 }
2019 #endif
2020 }
2021
2022 #if ( configUSE_PREEMPTION == 1 )
2023 {
2024 if( xYieldPending != pdFALSE )
2025 {
2026 xSwitchRequired = pdTRUE;
2027 }
2028 else
2029 {
2030 mtCOVERAGE_TEST_MARKER();
2031 }
2032 }
2033 #endif /* configUSE_PREEMPTION */
2034
2035 return xSwitchRequired;
2036}
2037/*-----------------------------------------------------------*/
2038
2039#if ( configUSE_APPLICATION_TASK_TAG == 1 )
2040
2041 void vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction )
2042 {
2043 TCB_t *xTCB;
2044
2045 /* If xTask is NULL then it is the task hook of the calling task that is
2046 getting set. */
2047 if( xTask == NULL )
2048 {
2049 xTCB = ( TCB_t * ) pxCurrentTCB;
2050 }
2051 else
2052 {
2053 xTCB = ( TCB_t * ) xTask;
2054 }
2055
2056 /* Save the hook function in the TCB. A critical section is required as
2057 the value can be accessed from an interrupt. */
2058 taskENTER_CRITICAL();
2059 xTCB->pxTaskTag = pxHookFunction;
2060 taskEXIT_CRITICAL();
2061 }
2062
2063#endif /* configUSE_APPLICATION_TASK_TAG */
2064/*-----------------------------------------------------------*/
2065
2066#if ( configUSE_APPLICATION_TASK_TAG == 1 )
2067
2068 TaskHookFunction_t xTaskGetApplicationTaskTag( TaskHandle_t xTask )
2069 {
2070 TCB_t *xTCB;
2071 TaskHookFunction_t xReturn;
2072
2073 /* If xTask is NULL then we are setting our own task hook. */
2074 if( xTask == NULL )
2075 {
2076 xTCB = ( TCB_t * ) pxCurrentTCB;
2077 }
2078 else
2079 {
2080 xTCB = ( TCB_t * ) xTask;
2081 }
2082
2083 /* Save the hook function in the TCB. A critical section is required as
2084 the value can be accessed from an interrupt. */
2085 taskENTER_CRITICAL();
2086 {
2087 xReturn = xTCB->pxTaskTag;
2088 }
2089 taskEXIT_CRITICAL();
2090
2091 return xReturn;
2092 }
2093
2094#endif /* configUSE_APPLICATION_TASK_TAG */
2095/*-----------------------------------------------------------*/
2096
2097#if ( configUSE_APPLICATION_TASK_TAG == 1 )
2098
2099 BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter )
2100 {
2101 TCB_t *xTCB;
2102 BaseType_t xReturn;
2103
2104 /* If xTask is NULL then we are calling our own task hook. */
2105 if( xTask == NULL )
2106 {
2107 xTCB = ( TCB_t * ) pxCurrentTCB;
2108 }
2109 else
2110 {
2111 xTCB = ( TCB_t * ) xTask;
2112 }
2113
2114 if( xTCB->pxTaskTag != NULL )
2115 {
2116 xReturn = xTCB->pxTaskTag( pvParameter );
2117 }
2118 else
2119 {
2120 xReturn = pdFAIL;
2121 }
2122
2123 return xReturn;
2124 }
2125
2126#endif /* configUSE_APPLICATION_TASK_TAG */
2127/*-----------------------------------------------------------*/
2128
2129void vTaskSwitchContext( void )
2130{
2131 if( uxSchedulerSuspended != ( UBaseType_t ) pdFALSE )
2132 {
2133 /* The scheduler is currently suspended - do not allow a context
2134 switch. */
2135 xYieldPending = pdTRUE;
2136 }
2137 else
2138 {
2139 xYieldPending = pdFALSE;
2140 traceTASK_SWITCHED_OUT();
2141
2142 #if ( configGENERATE_RUN_TIME_STATS == 1 )
2143 {
2144 #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
2145 portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime );
2146 #else
2147 ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
2148 #endif
2149
2150 /* Add the amount of time the task has been running to the
2151 accumulated time so far. The time the task started running was
2152 stored in ulTaskSwitchedInTime. Note that there is no overflow
2153 protection here so count values are only valid until the timer
2154 overflows. The guard against negative values is to protect
2155 against suspect run time stat counter implementations - which
2156 are provided by the application, not the kernel. */
2157 if( ulTotalRunTime > ulTaskSwitchedInTime )
2158 {
2159 pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime );
2160 }
2161 else
2162 {
2163 mtCOVERAGE_TEST_MARKER();
2164 }
2165 ulTaskSwitchedInTime = ulTotalRunTime;
2166 }
2167 #endif /* configGENERATE_RUN_TIME_STATS */
2168
2169 /* Check for stack overflow, if configured. */
2170 taskCHECK_FOR_STACK_OVERFLOW();
2171
2172 /* Select a new task to run using either the generic C or port
2173 optimised asm code. */
2174 taskSELECT_HIGHEST_PRIORITY_TASK();
2175 traceTASK_SWITCHED_IN();
2176
2177 #if ( configUSE_NEWLIB_REENTRANT == 1 )
2178 {
2179 /* Switch Newlib's _impure_ptr variable to point to the _reent
2180 structure specific to this task. */
2181 _impure_ptr = &( pxCurrentTCB->xNewLib_reent );
2182 }
2183 #endif /* configUSE_NEWLIB_REENTRANT */
2184 }
2185}
2186/*-----------------------------------------------------------*/
2187
2188void vTaskPlaceOnEventList( List_t * const pxEventList, const TickType_t xTicksToWait )
2189{
2190TickType_t xTimeToWake;
2191
2192 configASSERT( pxEventList );
2193
2194 /* THIS FUNCTION MUST BE CALLED WITH EITHER INTERRUPTS DISABLED OR THE
2195 SCHEDULER SUSPENDED AND THE QUEUE BEING ACCESSED LOCKED. */
2196
2197 /* Place the event list item of the TCB in the appropriate event list.
2198 This is placed in the list in priority order so the highest priority task
2199 is the first to be woken by the event. The queue that contains the event
2200 list is locked, preventing simultaneous access from interrupts. */
2201 vListInsert( pxEventList, &( pxCurrentTCB->xEventListItem ) );
2202
2203 /* The task must be removed from from the ready list before it is added to
2204 the blocked list as the same list item is used for both lists. Exclusive
2205 access to the ready lists guaranteed because the scheduler is locked. */
2206 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
2207 {
2208 /* The current task must be in a ready list, so there is no need to
2209 check, and the port reset macro can be called directly. */
2210 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
2211 }
2212 else
2213 {
2214 mtCOVERAGE_TEST_MARKER();
2215 }
2216
2217 #if ( INCLUDE_vTaskSuspend == 1 )
2218 {
2219 if( xTicksToWait == portMAX_DELAY )
2220 {
2221 /* Add the task to the suspended task list instead of a delayed task
2222 list to ensure the task is not woken by a timing event. It will
2223 block indefinitely. */
2224 vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) );
2225 }
2226 else
2227 {
2228 /* Calculate the time at which the task should be woken if the event
2229 does not occur. This may overflow but this doesn't matter, the
2230 scheduler will handle it. */
2231 xTimeToWake = xTickCount + xTicksToWait;
2232 prvAddCurrentTaskToDelayedList( xTimeToWake );
2233 }
2234 }
2235 #else /* INCLUDE_vTaskSuspend */
2236 {
2237 /* Calculate the time at which the task should be woken if the event does
2238 not occur. This may overflow but this doesn't matter, the scheduler
2239 will handle it. */
2240 xTimeToWake = xTickCount + xTicksToWait;
2241 prvAddCurrentTaskToDelayedList( xTimeToWake );
2242 }
2243 #endif /* INCLUDE_vTaskSuspend */
2244}
2245/*-----------------------------------------------------------*/
2246
2247void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, const TickType_t xItemValue, const TickType_t xTicksToWait )
2248{
2249TickType_t xTimeToWake;
2250
2251 configASSERT( pxEventList );
2252
2253 /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by
2254 the event groups implementation. */
2255 configASSERT( uxSchedulerSuspended != 0 );
2256
2257 /* Store the item value in the event list item. It is safe to access the
2258 event list item here as interrupts won't access the event list item of a
2259 task that is not in the Blocked state. */
2260 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE );
2261
2262 /* Place the event list item of the TCB at the end of the appropriate event
2263 list. It is safe to access the event list here because it is part of an
2264 event group implementation - and interrupts don't access event groups
2265 directly (instead they access them indirectly by pending function calls to
2266 the task level). */
2267 vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) );
2268
2269 /* The task must be removed from the ready list before it is added to the
2270 blocked list. Exclusive access can be assured to the ready list as the
2271 scheduler is locked. */
2272 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
2273 {
2274 /* The current task must be in a ready list, so there is no need to
2275 check, and the port reset macro can be called directly. */
2276 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
2277 }
2278 else
2279 {
2280 mtCOVERAGE_TEST_MARKER();
2281 }
2282
2283 #if ( INCLUDE_vTaskSuspend == 1 )
2284 {
2285 if( xTicksToWait == portMAX_DELAY )
2286 {
2287 /* Add the task to the suspended task list instead of a delayed task
2288 list to ensure it is not woken by a timing event. It will block
2289 indefinitely. */
2290 vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) );
2291 }
2292 else
2293 {
2294 /* Calculate the time at which the task should be woken if the event
2295 does not occur. This may overflow but this doesn't matter, the
2296 kernel will manage it correctly. */
2297 xTimeToWake = xTickCount + xTicksToWait;
2298 prvAddCurrentTaskToDelayedList( xTimeToWake );
2299 }
2300 }
2301 #else /* INCLUDE_vTaskSuspend */
2302 {
2303 /* Calculate the time at which the task should be woken if the event does
2304 not occur. This may overflow but this doesn't matter, the kernel
2305 will manage it correctly. */
2306 xTimeToWake = xTickCount + xTicksToWait;
2307 prvAddCurrentTaskToDelayedList( xTimeToWake );
2308 }
2309 #endif /* INCLUDE_vTaskSuspend */
2310}
2311/*-----------------------------------------------------------*/
2312
2313#if configUSE_TIMERS == 1
2314
2315 void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, const TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely )
2316 {
2317 TickType_t xTimeToWake;
2318
2319 configASSERT( pxEventList );
2320
2321 /* This function should not be called by application code hence the
2322 'Restricted' in its name. It is not part of the public API. It is
2323 designed for use by kernel code, and has special calling requirements -
2324 it should be called with the scheduler suspended. */
2325
2326
2327 /* Place the event list item of the TCB in the appropriate event list.
2328 In this case it is assume that this is the only task that is going to
2329 be waiting on this event list, so the faster vListInsertEnd() function
2330 can be used in place of vListInsert. */
2331 vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) );
2332
2333 /* We must remove this task from the ready list before adding it to the
2334 blocked list as the same list item is used for both lists. This
2335 function is called with the scheduler locked so interrupts will not
2336 access the lists at the same time. */
2337 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
2338 {
2339 /* The current task must be in a ready list, so there is no need to
2340 check, and the port reset macro can be called directly. */
2341 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
2342 }
2343 else
2344 {
2345 mtCOVERAGE_TEST_MARKER();
2346 }
2347
2348 /* If vTaskSuspend() is available then the suspended task list is also
2349 available and a task that is blocking indefinitely can enter the
2350 suspended state (it is not really suspended as it will re-enter the
2351 Ready state when the event it is waiting indefinitely for occurs).
2352 Blocking indefinitely is useful when using tickless idle mode as when
2353 all tasks are blocked indefinitely all timers can be turned off. */
2354 #if( INCLUDE_vTaskSuspend == 1 )
2355 {
2356 if( xWaitIndefinitely == pdTRUE )
2357 {
2358 /* Add the task to the suspended task list instead of a delayed
2359 task list to ensure the task is not woken by a timing event. It
2360 will block indefinitely. */
2361 vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) );
2362 }
2363 else
2364 {
2365 /* Calculate the time at which the task should be woken if the
2366 event does not occur. This may overflow but this doesn't
2367 matter. */
2368 xTimeToWake = xTickCount + xTicksToWait;
2369 traceTASK_DELAY_UNTIL();
2370 prvAddCurrentTaskToDelayedList( xTimeToWake );
2371 }
2372 }
2373 #else
2374 {
2375 /* Calculate the time at which the task should be woken if the event
2376 does not occur. This may overflow but this doesn't matter. */
2377 xTimeToWake = xTickCount + xTicksToWait;
2378 traceTASK_DELAY_UNTIL();
2379 prvAddCurrentTaskToDelayedList( xTimeToWake );
2380
2381 /* Remove compiler warnings when INCLUDE_vTaskSuspend() is not
2382 defined. */
2383 ( void ) xWaitIndefinitely;
2384 }
2385 #endif
2386 }
2387
2388#endif /* configUSE_TIMERS */
2389/*-----------------------------------------------------------*/
2390
2391BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList )
2392{
2393TCB_t *pxUnblockedTCB;
2394BaseType_t xReturn;
2395
2396 /* THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION. It can also be
2397 called from a critical section within an ISR. */
2398
2399 /* The event list is sorted in priority order, so the first in the list can
2400 be removed as it is known to be the highest priority. Remove the TCB from
2401 the delayed list, and add it to the ready list.
2402
2403 If an event is for a queue that is locked then this function will never
2404 get called - the lock count on the queue will get modified instead. This
2405 means exclusive access to the event list is guaranteed here.
2406
2407 This function assumes that a check has already been made to ensure that
2408 pxEventList is not empty. */
2409 pxUnblockedTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
2410 configASSERT( pxUnblockedTCB );
2411 ( void ) uxListRemove( &( pxUnblockedTCB->xEventListItem ) );
2412
2413 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
2414 {
2415 ( void ) uxListRemove( &( pxUnblockedTCB->xGenericListItem ) );
2416 prvAddTaskToReadyList( pxUnblockedTCB );
2417 }
2418 else
2419 {
2420 /* The delayed and ready lists cannot be accessed, so hold this task
2421 pending until the scheduler is resumed. */
2422 vListInsertEnd( &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );
2423 }
2424
2425 if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority )
2426 {
2427 /* Return true if the task removed from the event list has a higher
2428 priority than the calling task. This allows the calling task to know if
2429 it should force a context switch now. */
2430 xReturn = pdTRUE;
2431
2432 /* Mark that a yield is pending in case the user is not using the
2433 "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */
2434 xYieldPending = pdTRUE;
2435 }
2436 else
2437 {
2438 xReturn = pdFALSE;
2439 }
2440
2441 #if( configUSE_TICKLESS_IDLE != 0 )
2442 {
2443 /* If a task is blocked on a kernel object then xNextTaskUnblockTime
2444 might be set to the blocked task's time out time. If the task is
2445 unblocked for a reason other than a timeout xNextTaskUnblockTime is
2446 normally left unchanged, because it is automatically reset to a new
2447 value when the tick count equals xNextTaskUnblockTime. However if
2448 tickless idling is used it might be more important to enter sleep mode
2449 at the earliest possible time - so reset xNextTaskUnblockTime here to
2450 ensure it is updated at the earliest possible time. */
2451 prvResetNextTaskUnblockTime();
2452 }
2453 #endif
2454
2455 return xReturn;
2456}
2457/*-----------------------------------------------------------*/
2458
2459BaseType_t xTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue )
2460{
2461TCB_t *pxUnblockedTCB;
2462BaseType_t xReturn;
2463
2464 /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by
2465 the event flags implementation. */
2466 configASSERT( uxSchedulerSuspended != pdFALSE );
2467
2468 /* Store the new item value in the event list. */
2469 listSET_LIST_ITEM_VALUE( pxEventListItem, xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE );
2470
2471 /* Remove the event list form the event flag. Interrupts do not access
2472 event flags. */
2473 pxUnblockedTCB = ( TCB_t * ) listGET_LIST_ITEM_OWNER( pxEventListItem );
2474 configASSERT( pxUnblockedTCB );
2475 ( void ) uxListRemove( pxEventListItem );
2476
2477 /* Remove the task from the delayed list and add it to the ready list. The
2478 scheduler is suspended so interrupts will not be accessing the ready
2479 lists. */
2480 ( void ) uxListRemove( &( pxUnblockedTCB->xGenericListItem ) );
2481 prvAddTaskToReadyList( pxUnblockedTCB );
2482
2483 if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority )
2484 {
2485 /* Return true if the task removed from the event list has
2486 a higher priority than the calling task. This allows
2487 the calling task to know if it should force a context
2488 switch now. */
2489 xReturn = pdTRUE;
2490
2491 /* Mark that a yield is pending in case the user is not using the
2492 "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */
2493 xYieldPending = pdTRUE;
2494 }
2495 else
2496 {
2497 xReturn = pdFALSE;
2498 }
2499
2500 return xReturn;
2501}
2502/*-----------------------------------------------------------*/
2503
2504void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut )
2505{
2506 configASSERT( pxTimeOut );
2507 pxTimeOut->xOverflowCount = xNumOfOverflows;
2508 pxTimeOut->xTimeOnEntering = xTickCount;
2509}
2510/*-----------------------------------------------------------*/
2511
2512BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait )
2513{
2514BaseType_t xReturn;
2515
2516 configASSERT( pxTimeOut );
2517 configASSERT( pxTicksToWait );
2518
2519 taskENTER_CRITICAL();
2520 {
2521 /* Minor optimisation. The tick count cannot change in this block. */
2522 const TickType_t xConstTickCount = xTickCount;
2523
2524 #if ( INCLUDE_vTaskSuspend == 1 )
2525 /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is
2526 the maximum block time then the task should block indefinitely, and
2527 therefore never time out. */
2528 if( *pxTicksToWait == portMAX_DELAY )
2529 {
2530 xReturn = pdFALSE;
2531 }
2532 else /* We are not blocking indefinitely, perform the checks below. */
2533 #endif
2534
2535 if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( xConstTickCount >= pxTimeOut->xTimeOnEntering ) ) /*lint !e525 Indentation preferred as is to make code within pre-processor directives clearer. */
2536 {
2537 /* The tick count is greater than the time at which vTaskSetTimeout()
2538 was called, but has also overflowed since vTaskSetTimeOut() was called.
2539 It must have wrapped all the way around and gone past us again. This
2540 passed since vTaskSetTimeout() was called. */
2541 xReturn = pdTRUE;
2542 }
2543 else if( ( xConstTickCount - pxTimeOut->xTimeOnEntering ) < *pxTicksToWait )
2544 {
2545 /* Not a genuine timeout. Adjust parameters for time remaining. */
2546 *pxTicksToWait -= ( xConstTickCount - pxTimeOut->xTimeOnEntering );
2547 vTaskSetTimeOutState( pxTimeOut );
2548 xReturn = pdFALSE;
2549 }
2550 else
2551 {
2552 xReturn = pdTRUE;
2553 }
2554 }
2555 taskEXIT_CRITICAL();
2556
2557 return xReturn;
2558}
2559/*-----------------------------------------------------------*/
2560
2561void vTaskMissedYield( void )
2562{
2563 xYieldPending = pdTRUE;
2564}
2565/*-----------------------------------------------------------*/
2566
2567#if ( configUSE_TRACE_FACILITY == 1 )
2568
2569 UBaseType_t uxTaskGetTaskNumber( TaskHandle_t xTask )
2570 {
2571 UBaseType_t uxReturn;
2572 TCB_t *pxTCB;
2573
2574 if( xTask != NULL )
2575 {
2576 pxTCB = ( TCB_t * ) xTask;
2577 uxReturn = pxTCB->uxTaskNumber;
2578 }
2579 else
2580 {
2581 uxReturn = 0U;
2582 }
2583
2584 return uxReturn;
2585 }
2586
2587#endif /* configUSE_TRACE_FACILITY */
2588/*-----------------------------------------------------------*/
2589
2590#if ( configUSE_TRACE_FACILITY == 1 )
2591
2592 void vTaskSetTaskNumber( TaskHandle_t xTask, const UBaseType_t uxHandle )
2593 {
2594 TCB_t *pxTCB;
2595
2596 if( xTask != NULL )
2597 {
2598 pxTCB = ( TCB_t * ) xTask;
2599 pxTCB->uxTaskNumber = uxHandle;
2600 }
2601 }
2602
2603#endif /* configUSE_TRACE_FACILITY */
2604
2605/*
2606 * -----------------------------------------------------------
2607 * The Idle task.
2608 * ----------------------------------------------------------
2609 *
2610 * The portTASK_FUNCTION() macro is used to allow port/compiler specific
2611 * language extensions. The equivalent prototype for this function is:
2612 *
2613 * void prvIdleTask( void *pvParameters );
2614 *
2615 */
2616static portTASK_FUNCTION( prvIdleTask, pvParameters )
2617{
2618 /* Stop warnings. */
2619 ( void ) pvParameters;
2620
2621 for( ;; )
2622 {
2623 /* See if any tasks have been deleted. */
2624 prvCheckTasksWaitingTermination();
2625
2626 #if ( configUSE_PREEMPTION == 0 )
2627 {
2628 /* If we are not using preemption we keep forcing a task switch to
2629 see if any other task has become available. If we are using
2630 preemption we don't need to do this as any task becoming available
2631 will automatically get the processor anyway. */
2632 taskYIELD();
2633 }
2634 #endif /* configUSE_PREEMPTION */
2635
2636 #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
2637 {
2638 /* When using preemption tasks of equal priority will be
2639 timesliced. If a task that is sharing the idle priority is ready
2640 to run then the idle task should yield before the end of the
2641 timeslice.
2642
2643 A critical region is not required here as we are just reading from
2644 the list, and an occasional incorrect value will not matter. If
2645 the ready list at the idle priority contains more than one task
2646 then a task other than the idle task is ready to execute. */
2647 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( UBaseType_t ) 1 )
2648 {
2649 taskYIELD();
2650 }
2651 else
2652 {
2653 mtCOVERAGE_TEST_MARKER();
2654 }
2655 }
2656 #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */
2657
2658 #if ( configUSE_IDLE_HOOK == 1 )
2659 {
2660 extern void vApplicationIdleHook( void );
2661
2662 /* Call the user defined function from within the idle task. This
2663 allows the application designer to add background functionality
2664 without the overhead of a separate task.
2665 NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
2666 CALL A FUNCTION THAT MIGHT BLOCK. */
2667 vApplicationIdleHook();
2668 }
2669 #endif /* configUSE_IDLE_HOOK */
2670
2671 /* This conditional compilation should use inequality to 0, not equality
2672 to 1. This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when
2673 user defined low power mode implementations require
2674 configUSE_TICKLESS_IDLE to be set to a value other than 1. */
2675 #if ( configUSE_TICKLESS_IDLE != 0 )
2676 {
2677 TickType_t xExpectedIdleTime;
2678
2679 /* It is not desirable to suspend then resume the scheduler on
2680 each iteration of the idle task. Therefore, a preliminary
2681 test of the expected idle time is performed without the
2682 scheduler suspended. The result here is not necessarily
2683 valid. */
2684 xExpectedIdleTime = prvGetExpectedIdleTime();
2685
2686 if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
2687 {
2688 vTaskSuspendAll();
2689 {
2690 /* Now the scheduler is suspended, the expected idle
2691 time can be sampled again, and this time its value can
2692 be used. */
2693 configASSERT( xNextTaskUnblockTime >= xTickCount );
2694 xExpectedIdleTime = prvGetExpectedIdleTime();
2695
2696 if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
2697 {
2698 traceLOW_POWER_IDLE_BEGIN();
2699 portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime );
2700 traceLOW_POWER_IDLE_END();
2701 }
2702 else
2703 {
2704 mtCOVERAGE_TEST_MARKER();
2705 }
2706 }
2707 ( void ) xTaskResumeAll();
2708 }
2709 else
2710 {
2711 mtCOVERAGE_TEST_MARKER();
2712 }
2713 }
2714 #endif /* configUSE_TICKLESS_IDLE */
2715 }
2716}
2717/*-----------------------------------------------------------*/
2718
2719#if( configUSE_TICKLESS_IDLE != 0 )
2720
2721 eSleepModeStatus eTaskConfirmSleepModeStatus( void )
2722 {
2723 /* The idle task exists in addition to the application tasks. */
2724 const UBaseType_t uxNonApplicationTasks = 1;
2725 eSleepModeStatus eReturn = eStandardSleep;
2726
2727 if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0 )
2728 {
2729 /* A task was made ready while the scheduler was suspended. */
2730 eReturn = eAbortSleep;
2731 }
2732 else if( xYieldPending != pdFALSE )
2733 {
2734 /* A yield was pended while the scheduler was suspended. */
2735 eReturn = eAbortSleep;
2736 }
2737 else
2738 {
2739 /* If all the tasks are in the suspended list (which might mean they
2740 have an infinite block time rather than actually being suspended)
2741 then it is safe to turn all clocks off and just wait for external
2742 interrupts. */
2743 if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) )
2744 {
2745 eReturn = eNoTasksWaitingTimeout;
2746 }
2747 else
2748 {
2749 mtCOVERAGE_TEST_MARKER();
2750 }
2751 }
2752
2753 return eReturn;
2754 }
2755
2756#endif /* configUSE_TICKLESS_IDLE */
2757/*-----------------------------------------------------------*/
2758
2759static void prvInitialiseTCBVariables( TCB_t * const pxTCB, const char * const pcName, UBaseType_t uxPriority, const MemoryRegion_t * const xRegions, const uint16_t usStackDepth ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
2760{
2761UBaseType_t x;
2762
2763 /* Store the task name in the TCB. */
2764 for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
2765 {
2766 pxTCB->pcTaskName[ x ] = pcName[ x ];
2767
2768 /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than
2769 configMAX_TASK_NAME_LEN characters just in case the memory after the
2770 string is not accessible (extremely unlikely). */
2771 if( pcName[ x ] == 0x00 )
2772 {
2773 break;
2774 }
2775 else
2776 {
2777 mtCOVERAGE_TEST_MARKER();
2778 }
2779 }
2780
2781 /* Ensure the name string is terminated in the case that the string length
2782 was greater or equal to configMAX_TASK_NAME_LEN. */
2783 pxTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0';
2784
2785 /* This is used as an array index so must ensure it's not too large. First
2786 remove the privilege bit if one is present. */
2787 if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
2788 {
2789 uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
2790 }
2791 else
2792 {
2793 mtCOVERAGE_TEST_MARKER();
2794 }
2795
2796 pxTCB->uxPriority = uxPriority;
2797 #if ( configUSE_MUTEXES == 1 )
2798 {
2799 pxTCB->uxBasePriority = uxPriority;
2800 pxTCB->uxMutexesHeld = 0;
2801 }
2802 #endif /* configUSE_MUTEXES */
2803
2804 vListInitialiseItem( &( pxTCB->xGenericListItem ) );
2805 vListInitialiseItem( &( pxTCB->xEventListItem ) );
2806
2807 /* Set the pxTCB as a link back from the ListItem_t. This is so we can get
2808 back to the containing TCB from a generic item in a list. */
2809 listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB );
2810
2811 /* Event lists are always in priority order. */
2812 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
2813 listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB );
2814
2815 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
2816 {
2817 pxTCB->uxCriticalNesting = ( UBaseType_t ) 0U;
2818 }
2819 #endif /* portCRITICAL_NESTING_IN_TCB */
2820
2821 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
2822 {
2823 pxTCB->pxTaskTag = NULL;
2824 }
2825 #endif /* configUSE_APPLICATION_TASK_TAG */
2826
2827 #if ( configGENERATE_RUN_TIME_STATS == 1 )
2828 {
2829 pxTCB->ulRunTimeCounter = 0UL;
2830 }
2831 #endif /* configGENERATE_RUN_TIME_STATS */
2832
2833 #if ( portUSING_MPU_WRAPPERS == 1 )
2834 {
2835 vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth );
2836 }
2837 #else /* portUSING_MPU_WRAPPERS */
2838 {
2839 ( void ) xRegions;
2840 ( void ) usStackDepth;
2841 }
2842 #endif /* portUSING_MPU_WRAPPERS */
2843
2844 #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 )
2845 {
2846 for( x = 0; x < ( UBaseType_t ) configNUM_THREAD_LOCAL_STORAGE_POINTERS; x++ )
2847 {
2848 pxTCB->pvThreadLocalStoragePointers[ x ] = NULL;
2849 }
2850 }
2851 #endif
2852
2853 #if ( configUSE_TASK_NOTIFICATIONS == 1 )
2854 {
2855 pxTCB->ulNotifiedValue = 0;
2856 pxTCB->eNotifyState = eNotWaitingNotification;
2857 }
2858 #endif
2859
2860 #if ( configUSE_NEWLIB_REENTRANT == 1 )
2861 {
2862 /* Initialise this task's Newlib reent structure. */
2863 _REENT_INIT_PTR( ( &( pxTCB->xNewLib_reent ) ) );
2864 }
2865 #endif /* configUSE_NEWLIB_REENTRANT */
2866}
2867/*-----------------------------------------------------------*/
2868
2869#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 )
2870
2871 void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue )
2872 {
2873 TCB_t *pxTCB;
2874
2875 if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS )
2876 {
2877 pxTCB = prvGetTCBFromHandle( xTaskToSet );
2878 pxTCB->pvThreadLocalStoragePointers[ xIndex ] = pvValue;
2879 }
2880 }
2881
2882#endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS */
2883/*-----------------------------------------------------------*/
2884
2885#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 )
2886
2887 void *pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery, BaseType_t xIndex )
2888 {
2889 void *pvReturn = NULL;
2890 TCB_t *pxTCB;
2891
2892 if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS )
2893 {
2894 pxTCB = prvGetTCBFromHandle( xTaskToQuery );
2895 pvReturn = pxTCB->pvThreadLocalStoragePointers[ xIndex ];
2896 }
2897 else
2898 {
2899 pvReturn = NULL;
2900 }
2901
2902 return pvReturn;
2903 }
2904
2905#endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS */
2906/*-----------------------------------------------------------*/
2907
2908#if ( portUSING_MPU_WRAPPERS == 1 )
2909
2910 void vTaskAllocateMPURegions( TaskHandle_t xTaskToModify, const MemoryRegion_t * const xRegions )
2911 {
2912 TCB_t *pxTCB;
2913
2914 /* If null is passed in here then we are modifying the MPU settings of
2915 the calling task. */
2916 pxTCB = prvGetTCBFromHandle( xTaskToModify );
2917
2918 vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 );
2919 }
2920
2921#endif /* portUSING_MPU_WRAPPERS */
2922/*-----------------------------------------------------------*/
2923
2924static void prvInitialiseTaskLists( void )
2925{
2926UBaseType_t uxPriority;
2927
2928 for( uxPriority = ( UBaseType_t ) 0U; uxPriority < ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ )
2929 {
2930 vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) );
2931 }
2932
2933 vListInitialise( &xDelayedTaskList1 );
2934 vListInitialise( &xDelayedTaskList2 );
2935 vListInitialise( &xPendingReadyList );
2936
2937 #if ( INCLUDE_vTaskDelete == 1 )
2938 {
2939 vListInitialise( &xTasksWaitingTermination );
2940 }
2941 #endif /* INCLUDE_vTaskDelete */
2942
2943 #if ( INCLUDE_vTaskSuspend == 1 )
2944 {
2945 vListInitialise( &xSuspendedTaskList );
2946 }
2947 #endif /* INCLUDE_vTaskSuspend */
2948
2949 /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
2950 using list2. */
2951 pxDelayedTaskList = &xDelayedTaskList1;
2952 pxOverflowDelayedTaskList = &xDelayedTaskList2;
2953}
2954/*-----------------------------------------------------------*/
2955
2956static void prvCheckTasksWaitingTermination( void )
2957{
2958 #if ( INCLUDE_vTaskDelete == 1 )
2959 {
2960 BaseType_t xListIsEmpty;
2961
2962 /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
2963 too often in the idle task. */
2964 while( uxTasksDeleted > ( UBaseType_t ) 0U )
2965 {
2966 vTaskSuspendAll();
2967 {
2968 xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
2969 }
2970 ( void ) xTaskResumeAll();
2971
2972 if( xListIsEmpty == pdFALSE )
2973 {
2974 TCB_t *pxTCB;
2975
2976 taskENTER_CRITICAL();
2977 {
2978 pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) );
2979 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
2980 --uxCurrentNumberOfTasks;
2981 --uxTasksDeleted;
2982 }
2983 taskEXIT_CRITICAL();
2984
2985 prvDeleteTCB( pxTCB );
2986 }
2987 else
2988 {
2989 mtCOVERAGE_TEST_MARKER();
2990 }
2991 }
2992 }
2993 #endif /* vTaskDelete */
2994}
2995/*-----------------------------------------------------------*/
2996
2997static void prvAddCurrentTaskToDelayedList( const TickType_t xTimeToWake )
2998{
2999 /* The list item will be inserted in wake time order. */
3000 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
3001
3002 if( xTimeToWake < xTickCount )
3003 {
3004 /* Wake time has overflowed. Place this item in the overflow list. */
3005 vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xGenericListItem ) );
3006 }
3007 else
3008 {
3009 /* The wake time has not overflowed, so the current block list is used. */
3010 vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xGenericListItem ) );
3011
3012 /* If the task entering the blocked state was placed at the head of the
3013 list of blocked tasks then xNextTaskUnblockTime needs to be updated
3014 too. */
3015 if( xTimeToWake < xNextTaskUnblockTime )
3016 {
3017 xNextTaskUnblockTime = xTimeToWake;
3018 }
3019 else
3020 {
3021 mtCOVERAGE_TEST_MARKER();
3022 }
3023 }
3024}
3025/*-----------------------------------------------------------*/
3026
3027static TCB_t *prvAllocateTCBAndStack( const uint16_t usStackDepth, StackType_t * const puxStackBuffer )
3028{
3029TCB_t *pxNewTCB;
3030
3031 /* If the stack grows down then allocate the stack then the TCB so the stack
3032 does not grow into the TCB. Likewise if the stack grows up then allocate
3033 the TCB then the stack. */
3034 #if( portSTACK_GROWTH > 0 )
3035 {
3036 /* Allocate space for the TCB. Where the memory comes from depends on
3037 the implementation of the port malloc function. */
3038 pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
3039
3040 if( pxNewTCB != NULL )
3041 {
3042 /* Allocate space for the stack used by the task being created.
3043 The base of the stack memory stored in the TCB so the task can
3044 be deleted later if required. */
3045 pxNewTCB->pxStack = ( StackType_t * ) pvPortMallocAligned( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ), puxStackBuffer ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
3046
3047 if( pxNewTCB->pxStack == NULL )
3048 {
3049 /* Could not allocate the stack. Delete the allocated TCB. */
3050 vPortFree( pxNewTCB );
3051 pxNewTCB = NULL;
3052 }
3053 }
3054 }
3055 #else /* portSTACK_GROWTH */
3056 {
3057 StackType_t *pxStack;
3058
3059 /* Allocate space for the stack used by the task being created. */
3060 pxStack = ( StackType_t * ) pvPortMallocAligned( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ), puxStackBuffer ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
3061
3062 if( pxStack != NULL )
3063 {
3064 /* Allocate space for the TCB. Where the memory comes from depends
3065 on the implementation of the port malloc function. */
3066 pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
3067
3068 if( pxNewTCB != NULL )
3069 {
3070 /* Store the stack location in the TCB. */
3071 pxNewTCB->pxStack = pxStack;
3072 }
3073 else
3074 {
3075 /* The stack cannot be used as the TCB was not created. Free it
3076 again. */
3077 vPortFree( pxStack );
3078 }
3079 }
3080 else
3081 {
3082 pxNewTCB = NULL;
3083 }
3084 }
3085 #endif /* portSTACK_GROWTH */
3086
3087 if( pxNewTCB != NULL )
3088 {
3089 /* Avoid dependency on memset() if it is not required. */
3090 #if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
3091 {
3092 /* Just to help debugging. */
3093 ( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) usStackDepth * sizeof( StackType_t ) );
3094 }
3095 #endif /* ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) ) */
3096 }
3097
3098 return pxNewTCB;
3099}
3100/*-----------------------------------------------------------*/
3101
3102#if ( configUSE_TRACE_FACILITY == 1 )
3103
3104 static UBaseType_t prvListTaskWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState )
3105 {
3106 volatile TCB_t *pxNextTCB, *pxFirstTCB;
3107 UBaseType_t uxTask = 0;
3108
3109 if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 )
3110 {
3111 listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
3112
3113 /* Populate an TaskStatus_t structure within the
3114 pxTaskStatusArray array for each task that is referenced from
3115 pxList. See the definition of TaskStatus_t in task.h for the
3116 meaning of each TaskStatus_t structure member. */
3117 do
3118 {
3119 listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
3120
3121 pxTaskStatusArray[ uxTask ].xHandle = ( TaskHandle_t ) pxNextTCB;
3122 pxTaskStatusArray[ uxTask ].pcTaskName = ( const char * ) &( pxNextTCB->pcTaskName [ 0 ] );
3123 pxTaskStatusArray[ uxTask ].xTaskNumber = pxNextTCB->uxTCBNumber;
3124 pxTaskStatusArray[ uxTask ].eCurrentState = eState;
3125 pxTaskStatusArray[ uxTask ].uxCurrentPriority = pxNextTCB->uxPriority;
3126
3127 #if ( INCLUDE_vTaskSuspend == 1 )
3128 {
3129 /* If the task is in the suspended list then there is a chance
3130 it is actually just blocked indefinitely - so really it should
3131 be reported as being in the Blocked state. */
3132 if( eState == eSuspended )
3133 {
3134 if( listLIST_ITEM_CONTAINER( &( pxNextTCB->xEventListItem ) ) != NULL )
3135 {
3136 pxTaskStatusArray[ uxTask ].eCurrentState = eBlocked;
3137 }
3138 }
3139 }
3140 #endif /* INCLUDE_vTaskSuspend */
3141
3142 #if ( configUSE_MUTEXES == 1 )
3143 {
3144 pxTaskStatusArray[ uxTask ].uxBasePriority = pxNextTCB->uxBasePriority;
3145 }
3146 #else
3147 {
3148 pxTaskStatusArray[ uxTask ].uxBasePriority = 0;
3149 }
3150 #endif
3151
3152 #if ( configGENERATE_RUN_TIME_STATS == 1 )
3153 {
3154 pxTaskStatusArray[ uxTask ].ulRunTimeCounter = pxNextTCB->ulRunTimeCounter;
3155 }
3156 #else
3157 {
3158 pxTaskStatusArray[ uxTask ].ulRunTimeCounter = 0;
3159 }
3160 #endif
3161
3162 #if ( portSTACK_GROWTH > 0 )
3163 {
3164 pxTaskStatusArray[ uxTask ].usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxNextTCB->pxEndOfStack );
3165 }
3166 #else
3167 {
3168 pxTaskStatusArray[ uxTask ].usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxNextTCB->pxStack );
3169 }
3170 #endif
3171
3172 uxTask++;
3173
3174 } while( pxNextTCB != pxFirstTCB );
3175 }
3176 else
3177 {
3178 mtCOVERAGE_TEST_MARKER();
3179 }
3180
3181 return uxTask;
3182 }
3183
3184#endif /* configUSE_TRACE_FACILITY */
3185/*-----------------------------------------------------------*/
3186
3187#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
3188
3189 static uint16_t prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte )
3190 {
3191 uint32_t ulCount = 0U;
3192
3193 while( *pucStackByte == ( uint8_t ) tskSTACK_FILL_BYTE )
3194 {
3195 pucStackByte -= portSTACK_GROWTH;
3196 ulCount++;
3197 }
3198
3199 ulCount /= ( uint32_t ) sizeof( StackType_t );
3200
3201 return ( uint16_t ) ulCount;
3202 }
3203
3204#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) */
3205/*-----------------------------------------------------------*/
3206
3207#if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )
3208
3209 UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask )
3210 {
3211 TCB_t *pxTCB;
3212 uint8_t *pucEndOfStack;
3213 UBaseType_t uxReturn;
3214
3215 pxTCB = prvGetTCBFromHandle( xTask );
3216
3217 #if portSTACK_GROWTH < 0
3218 {
3219 pucEndOfStack = ( uint8_t * ) pxTCB->pxStack;
3220 }
3221 #else
3222 {
3223 pucEndOfStack = ( uint8_t * ) pxTCB->pxEndOfStack;
3224 }
3225 #endif
3226
3227 uxReturn = ( UBaseType_t ) prvTaskCheckFreeStackSpace( pucEndOfStack );
3228
3229 return uxReturn;
3230 }
3231
3232#endif /* INCLUDE_uxTaskGetStackHighWaterMark */
3233/*-----------------------------------------------------------*/
3234
3235#if ( INCLUDE_vTaskDelete == 1 )
3236
3237 static void prvDeleteTCB( TCB_t *pxTCB )
3238 {
3239 /* This call is required specifically for the TriCore port. It must be
3240 above the vPortFree() calls. The call is also used by ports/demos that
3241 want to allocate and clean RAM statically. */
3242 portCLEAN_UP_TCB( pxTCB );
3243
3244 /* Free up the memory allocated by the scheduler for the task. It is up
3245 to the task to free any memory allocated at the application level. */
3246 #if ( configUSE_NEWLIB_REENTRANT == 1 )
3247 {
3248 _reclaim_reent( &( pxTCB->xNewLib_reent ) );
3249 }
3250 #endif /* configUSE_NEWLIB_REENTRANT */
3251
3252 #if( portUSING_MPU_WRAPPERS == 1 )
3253 {
3254 /* Only free the stack if it was allocated dynamically in the first
3255 place. */
3256 if( pxTCB->xUsingStaticallyAllocatedStack == pdFALSE )
3257 {
3258 vPortFreeAligned( pxTCB->pxStack );
3259 }
3260 }
3261 #else
3262 {
3263 vPortFreeAligned( pxTCB->pxStack );
3264 }
3265 #endif
3266
3267 vPortFree( pxTCB );
3268 }
3269
3270#endif /* INCLUDE_vTaskDelete */
3271/*-----------------------------------------------------------*/
3272
3273static void prvResetNextTaskUnblockTime( void )
3274{
3275TCB_t *pxTCB;
3276
3277 if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
3278 {
3279 /* The new current delayed list is empty. Set xNextTaskUnblockTime to
3280 the maximum possible value so it is extremely unlikely that the
3281 if( xTickCount >= xNextTaskUnblockTime ) test will pass until
3282 there is an item in the delayed list. */
3283 xNextTaskUnblockTime = portMAX_DELAY;
3284 }
3285 else
3286 {
3287 /* The new current delayed list is not empty, get the value of
3288 the item at the head of the delayed list. This is the time at
3289 which the task at the head of the delayed list should be removed
3290 from the Blocked state. */
3291 ( pxTCB ) = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
3292 xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( ( pxTCB )->xGenericListItem ) );
3293 }
3294}
3295/*-----------------------------------------------------------*/
3296
3297#if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) )
3298
3299 TaskHandle_t xTaskGetCurrentTaskHandle( void )
3300 {
3301 TaskHandle_t xReturn;
3302
3303 /* A critical section is not required as this is not called from
3304 an interrupt and the current TCB will always be the same for any
3305 individual execution thread. */
3306 xReturn = pxCurrentTCB;
3307
3308 return xReturn;
3309 }
3310
3311#endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */
3312/*-----------------------------------------------------------*/
3313
3314#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
3315
3316 BaseType_t xTaskGetSchedulerState( void )
3317 {
3318 BaseType_t xReturn;
3319
3320 if( xSchedulerRunning == pdFALSE )
3321 {
3322 xReturn = taskSCHEDULER_NOT_STARTED;
3323 }
3324 else
3325 {
3326 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
3327 {
3328 xReturn = taskSCHEDULER_RUNNING;
3329 }
3330 else
3331 {
3332 xReturn = taskSCHEDULER_SUSPENDED;
3333 }
3334 }
3335
3336 return xReturn;
3337 }
3338
3339#endif /* ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) */
3340/*-----------------------------------------------------------*/
3341
3342#if ( configUSE_MUTEXES == 1 )
3343
3344 void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder )
3345 {
3346 TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder;
3347
3348 /* If the mutex was given back by an interrupt while the queue was
3349 locked then the mutex holder might now be NULL. */
3350 if( pxMutexHolder != NULL )
3351 {
3352 /* If the holder of the mutex has a priority below the priority of
3353 the task attempting to obtain the mutex then it will temporarily
3354 inherit the priority of the task attempting to obtain the mutex. */
3355 if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )
3356 {
3357 /* Adjust the mutex holder state to account for its new
3358 priority. Only reset the event list item value if the value is
3359 not being used for anything else. */
3360 if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
3361 {
3362 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
3363 }
3364 else
3365 {
3366 mtCOVERAGE_TEST_MARKER();
3367 }
3368
3369 /* If the task being modified is in the ready state it will need
3370 to be moved into a new list. */
3371 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) != pdFALSE )
3372 {
3373 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
3374 {
3375 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
3376 }
3377 else
3378 {
3379 mtCOVERAGE_TEST_MARKER();
3380 }
3381
3382 /* Inherit the priority before being moved into the new list. */
3383 pxTCB->uxPriority = pxCurrentTCB->uxPriority;
3384 prvAddTaskToReadyList( pxTCB );
3385 }
3386 else
3387 {
3388 /* Just inherit the priority. */
3389 pxTCB->uxPriority = pxCurrentTCB->uxPriority;
3390 }
3391
3392 traceTASK_PRIORITY_INHERIT( pxTCB, pxCurrentTCB->uxPriority );
3393 }
3394 else
3395 {
3396 mtCOVERAGE_TEST_MARKER();
3397 }
3398 }
3399 else
3400 {
3401 mtCOVERAGE_TEST_MARKER();
3402 }
3403 }
3404
3405#endif /* configUSE_MUTEXES */
3406/*-----------------------------------------------------------*/
3407
3408#if ( configUSE_MUTEXES == 1 )
3409
3410 BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder )
3411 {
3412 TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder;
3413 BaseType_t xReturn = pdFALSE;
3414
3415 if( pxMutexHolder != NULL )
3416 {
3417 /* A task can only have an inherited priority if it holds the mutex.
3418 If the mutex is held by a task then it cannot be given from an
3419 interrupt, and if a mutex is given by the holding task then it must
3420 be the running state task. */
3421 configASSERT( pxTCB == pxCurrentTCB );
3422
3423 configASSERT( pxTCB->uxMutexesHeld );
3424 ( pxTCB->uxMutexesHeld )--;
3425
3426 /* Has the holder of the mutex inherited the priority of another
3427 task? */
3428 if( pxTCB->uxPriority != pxTCB->uxBasePriority )
3429 {
3430 /* Only disinherit if no other mutexes are held. */
3431 if( pxTCB->uxMutexesHeld == ( UBaseType_t ) 0 )
3432 {
3433 /* A task can only have an inherited priority if it holds
3434 the mutex. If the mutex is held by a task then it cannot be
3435 given from an interrupt, and if a mutex is given by the
3436 holding task then it must be the running state task. Remove
3437 the holding task from the ready list. */
3438 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
3439 {
3440 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
3441 }
3442 else
3443 {
3444 mtCOVERAGE_TEST_MARKER();
3445 }
3446
3447 /* Disinherit the priority before adding the task into the
3448 new ready list. */
3449 traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority );
3450 pxTCB->uxPriority = pxTCB->uxBasePriority;
3451
3452 /* Reset the event list item value. It cannot be in use for
3453 any other purpose if this task is running, and it must be
3454 running to give back the mutex. */
3455 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxTCB->uxPriority );
3456 prvAddTaskToReadyList( pxTCB );
3457
3458 /* Return true to indicate that a context switch is required.
3459 This is only actually required in the corner case whereby
3460 multiple mutexes were held and the mutexes were given back
3461 in an order different to that in which they were taken.
3462 If a context switch did not occur when the first mutex was
3463 returned, even if a task was waiting on it, then a context
3464 switch should occur when the last mutex is returned whether
3465 a task is waiting on it or not. */
3466 xReturn = pdTRUE;
3467 }
3468 else
3469 {
3470 mtCOVERAGE_TEST_MARKER();
3471 }
3472 }
3473 else
3474 {
3475 mtCOVERAGE_TEST_MARKER();
3476 }
3477 }
3478 else
3479 {
3480 mtCOVERAGE_TEST_MARKER();
3481 }
3482
3483 return xReturn;
3484 }
3485
3486#endif /* configUSE_MUTEXES */
3487/*-----------------------------------------------------------*/
3488
3489#if ( portCRITICAL_NESTING_IN_TCB == 1 )
3490
3491 void vTaskEnterCritical( void )
3492 {
3493 portDISABLE_INTERRUPTS();
3494
3495 if( xSchedulerRunning != pdFALSE )
3496 {
3497 ( pxCurrentTCB->uxCriticalNesting )++;
3498
3499 /* This is not the interrupt safe version of the enter critical
3500 function so assert() if it is being called from an interrupt
3501 context. Only API functions that end in "FromISR" can be used in an
3502 interrupt. Only assert if the critical nesting count is 1 to
3503 protect against recursive calls if the assert function also uses a
3504 critical section. */
3505 if( pxCurrentTCB->uxCriticalNesting == 1 )
3506 {
3507 portASSERT_IF_IN_ISR();
3508 }
3509 }
3510 else
3511 {
3512 mtCOVERAGE_TEST_MARKER();
3513 }
3514 }
3515
3516#endif /* portCRITICAL_NESTING_IN_TCB */
3517/*-----------------------------------------------------------*/
3518
3519#if ( portCRITICAL_NESTING_IN_TCB == 1 )
3520
3521 void vTaskExitCritical( void )
3522 {
3523 if( xSchedulerRunning != pdFALSE )
3524 {
3525 if( pxCurrentTCB->uxCriticalNesting > 0U )
3526 {
3527 ( pxCurrentTCB->uxCriticalNesting )--;
3528
3529 if( pxCurrentTCB->uxCriticalNesting == 0U )
3530 {
3531 portENABLE_INTERRUPTS();
3532 }
3533 else
3534 {
3535 mtCOVERAGE_TEST_MARKER();
3536 }
3537 }
3538 else
3539 {
3540 mtCOVERAGE_TEST_MARKER();
3541 }
3542 }
3543 else
3544 {
3545 mtCOVERAGE_TEST_MARKER();
3546 }
3547 }
3548
3549#endif /* portCRITICAL_NESTING_IN_TCB */
3550/*-----------------------------------------------------------*/
3551
3552#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) )
3553
3554 static char *prvWriteNameToBuffer( char *pcBuffer, const char *pcTaskName )
3555 {
3556 size_t x;
3557
3558 /* Start by copying the entire string. */
3559 strcpy( pcBuffer, pcTaskName );
3560
3561 /* Pad the end of the string with spaces to ensure columns line up when
3562 printed out. */
3563 for( x = strlen( pcBuffer ); x < ( size_t ) ( configMAX_TASK_NAME_LEN - 1 ); x++ )
3564 {
3565 pcBuffer[ x ] = ' ';
3566 }
3567
3568 /* Terminate. */
3569 pcBuffer[ x ] = 0x00;
3570
3571 /* Return the new end of string. */
3572 return &( pcBuffer[ x ] );
3573 }
3574
3575#endif /* ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) */
3576/*-----------------------------------------------------------*/
3577
3578#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) )
3579
3580 void vTaskList( char * pcWriteBuffer )
3581 {
3582 TaskStatus_t *pxTaskStatusArray;
3583 volatile UBaseType_t uxArraySize, x;
3584 char cStatus;
3585
3586 /*
3587 * PLEASE NOTE:
3588 *
3589 * This function is provided for convenience only, and is used by many
3590 * of the demo applications. Do not consider it to be part of the
3591 * scheduler.
3592 *
3593 * vTaskList() calls uxTaskGetSystemState(), then formats part of the
3594 * uxTaskGetSystemState() output into a human readable table that
3595 * displays task names, states and stack usage.
3596 *
3597 * vTaskList() has a dependency on the sprintf() C library function that
3598 * might bloat the code size, use a lot of stack, and provide different
3599 * results on different platforms. An alternative, tiny, third party,
3600 * and limited functionality implementation of sprintf() is provided in
3601 * many of the FreeRTOS/Demo sub-directories in a file called
3602 * printf-stdarg.c (note printf-stdarg.c does not provide a full
3603 * snprintf() implementation!).
3604 *
3605 * It is recommended that production systems call uxTaskGetSystemState()
3606 * directly to get access to raw stats data, rather than indirectly
3607 * through a call to vTaskList().
3608 */
3609
3610
3611 /* Make sure the write buffer does not contain a string. */
3612 *pcWriteBuffer = 0x00;
3613
3614 /* Take a snapshot of the number of tasks in case it changes while this
3615 function is executing. */
3616 uxArraySize = uxCurrentNumberOfTasks;
3617
3618 /* Allocate an array index for each task. */
3619 pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) );
3620
3621 if( pxTaskStatusArray != NULL )
3622 {
3623 /* Generate the (binary) data. */
3624 uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, NULL );
3625
3626 /* Create a human readable table from the binary data. */
3627 for( x = 0; x < uxArraySize; x++ )
3628 {
3629 switch( pxTaskStatusArray[ x ].eCurrentState )
3630 {
3631 case eReady: cStatus = tskREADY_CHAR;
3632 break;
3633
3634 case eBlocked: cStatus = tskBLOCKED_CHAR;
3635 break;
3636
3637 case eSuspended: cStatus = tskSUSPENDED_CHAR;
3638 break;
3639
3640 case eDeleted: cStatus = tskDELETED_CHAR;
3641 break;
3642
3643 default: /* Should not get here, but it is included
3644 to prevent static checking errors. */
3645 cStatus = 0x00;
3646 break;
3647 }
3648
3649 /* Write the task name to the string, padding with spaces so it
3650 can be printed in tabular form more easily. */
3651 pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName );
3652
3653 /* Write the rest of the string. */
3654 sprintf( pcWriteBuffer, "\t%c\t%u\t%u\t%u\r\n", cStatus, ( unsigned int ) pxTaskStatusArray[ x ].uxCurrentPriority, ( unsigned int ) pxTaskStatusArray[ x ].usStackHighWaterMark, ( unsigned int ) pxTaskStatusArray[ x ].xTaskNumber );
3655 pcWriteBuffer += strlen( pcWriteBuffer );
3656 }
3657
3658 /* Free the array again. */
3659 vPortFree( pxTaskStatusArray );
3660 }
3661 else
3662 {
3663 mtCOVERAGE_TEST_MARKER();
3664 }
3665 }
3666
3667#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */
3668/*----------------------------------------------------------*/
3669
3670#if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) )
3671
3672 void vTaskGetRunTimeStats( char *pcWriteBuffer )
3673 {
3674 TaskStatus_t *pxTaskStatusArray;
3675 volatile UBaseType_t uxArraySize, x;
3676 uint32_t ulTotalTime, ulStatsAsPercentage;
3677
3678 #if( configUSE_TRACE_FACILITY != 1 )
3679 {
3680 #error configUSE_TRACE_FACILITY must also be set to 1 in FreeRTOSConfig.h to use vTaskGetRunTimeStats().
3681 }
3682 #endif
3683
3684 /*
3685 * PLEASE NOTE:
3686 *
3687 * This function is provided for convenience only, and is used by many
3688 * of the demo applications. Do not consider it to be part of the
3689 * scheduler.
3690 *
3691 * vTaskGetRunTimeStats() calls uxTaskGetSystemState(), then formats part
3692 * of the uxTaskGetSystemState() output into a human readable table that
3693 * displays the amount of time each task has spent in the Running state
3694 * in both absolute and percentage terms.
3695 *
3696 * vTaskGetRunTimeStats() has a dependency on the sprintf() C library
3697 * function that might bloat the code size, use a lot of stack, and
3698 * provide different results on different platforms. An alternative,
3699 * tiny, third party, and limited functionality implementation of
3700 * sprintf() is provided in many of the FreeRTOS/Demo sub-directories in
3701 * a file called printf-stdarg.c (note printf-stdarg.c does not provide
3702 * a full snprintf() implementation!).
3703 *
3704 * It is recommended that production systems call uxTaskGetSystemState()
3705 * directly to get access to raw stats data, rather than indirectly
3706 * through a call to vTaskGetRunTimeStats().
3707 */
3708
3709 /* Make sure the write buffer does not contain a string. */
3710 *pcWriteBuffer = 0x00;
3711
3712 /* Take a snapshot of the number of tasks in case it changes while this
3713 function is executing. */
3714 uxArraySize = uxCurrentNumberOfTasks;
3715
3716 /* Allocate an array index for each task. */
3717 pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) );
3718
3719 if( pxTaskStatusArray != NULL )
3720 {
3721 /* Generate the (binary) data. */
3722 uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, &ulTotalTime );
3723
3724 /* For percentage calculations. */
3725 ulTotalTime /= 100UL;
3726
3727 /* Avoid divide by zero errors. */
3728 if( ulTotalTime > 0 )
3729 {
3730 /* Create a human readable table from the binary data. */
3731 for( x = 0; x < uxArraySize; x++ )
3732 {
3733 /* What percentage of the total run time has the task used?
3734 This will always be rounded down to the nearest integer.
3735 ulTotalRunTimeDiv100 has already been divided by 100. */
3736 ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter / ulTotalTime;
3737
3738 /* Write the task name to the string, padding with
3739 spaces so it can be printed in tabular form more
3740 easily. */
3741 pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName );
3742
3743 if( ulStatsAsPercentage > 0UL )
3744 {
3745 #ifdef portLU_PRINTF_SPECIFIER_REQUIRED
3746 {
3747 sprintf( pcWriteBuffer, "\t%lu\t\t%lu%%\r\n", pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage );
3748 }
3749 #else
3750 {
3751 /* sizeof( int ) == sizeof( long ) so a smaller
3752 printf() library can be used. */
3753 sprintf( pcWriteBuffer, "\t%u\t\t%u%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage );
3754 }
3755 #endif
3756 }
3757 else
3758 {
3759 /* If the percentage is zero here then the task has
3760 consumed less than 1% of the total run time. */
3761 #ifdef portLU_PRINTF_SPECIFIER_REQUIRED
3762 {
3763 sprintf( pcWriteBuffer, "\t%lu\t\t<1%%\r\n", pxTaskStatusArray[ x ].ulRunTimeCounter );
3764 }
3765 #else
3766 {
3767 /* sizeof( int ) == sizeof( long ) so a smaller
3768 printf() library can be used. */
3769 sprintf( pcWriteBuffer, "\t%u\t\t<1%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter );
3770 }
3771 #endif
3772 }
3773
3774 pcWriteBuffer += strlen( pcWriteBuffer );
3775 }
3776 }
3777 else
3778 {
3779 mtCOVERAGE_TEST_MARKER();
3780 }
3781
3782 /* Free the array again. */
3783 vPortFree( pxTaskStatusArray );
3784 }
3785 else
3786 {
3787 mtCOVERAGE_TEST_MARKER();
3788 }
3789 }
3790
3791#endif /* ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */
3792/*-----------------------------------------------------------*/
3793
3794TickType_t uxTaskResetEventItemValue( void )
3795{
3796TickType_t uxReturn;
3797
3798 uxReturn = listGET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ) );
3799
3800 /* Reset the event list item to its normal value - so it can be used with
3801 queues and semaphores. */
3802 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
3803
3804 return uxReturn;
3805}
3806/*-----------------------------------------------------------*/
3807
3808#if ( configUSE_MUTEXES == 1 )
3809
3810 void *pvTaskIncrementMutexHeldCount( void )
3811 {
3812 /* If xSemaphoreCreateMutex() is called before any tasks have been created
3813 then pxCurrentTCB will be NULL. */
3814 if( pxCurrentTCB != NULL )
3815 {
3816 ( pxCurrentTCB->uxMutexesHeld )++;
3817 }
3818
3819 return pxCurrentTCB;
3820 }
3821
3822#endif /* configUSE_MUTEXES */
3823/*-----------------------------------------------------------*/
3824
3825#if( configUSE_TASK_NOTIFICATIONS == 1 )
3826
3827 uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait )
3828 {
3829 TickType_t xTimeToWake;
3830 uint32_t ulReturn;
3831
3832 taskENTER_CRITICAL();
3833 {
3834 /* Only block if the notification count is not already non-zero. */
3835 if( pxCurrentTCB->ulNotifiedValue == 0UL )
3836 {
3837 /* Mark this task as waiting for a notification. */
3838 pxCurrentTCB->eNotifyState = eWaitingNotification;
3839
3840 if( xTicksToWait > ( TickType_t ) 0 )
3841 {
3842 /* The task is going to block. First it must be removed
3843 from the ready list. */
3844 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
3845 {
3846 /* The current task must be in a ready list, so there is
3847 no need to check, and the port reset macro can be called
3848 directly. */
3849 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
3850 }
3851 else
3852 {
3853 mtCOVERAGE_TEST_MARKER();
3854 }
3855
3856 #if ( INCLUDE_vTaskSuspend == 1 )
3857 {
3858 if( xTicksToWait == portMAX_DELAY )
3859 {
3860 /* Add the task to the suspended task list instead
3861 of a delayed task list to ensure the task is not
3862 woken by a timing event. It will block
3863 indefinitely. */
3864 vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) );
3865 }
3866 else
3867 {
3868 /* Calculate the time at which the task should be
3869 woken if no notification events occur. This may
3870 overflow but this doesn't matter, the scheduler will
3871 handle it. */
3872 xTimeToWake = xTickCount + xTicksToWait;
3873 prvAddCurrentTaskToDelayedList( xTimeToWake );
3874 }
3875 }
3876 #else /* INCLUDE_vTaskSuspend */
3877 {
3878 /* Calculate the time at which the task should be
3879 woken if the event does not occur. This may
3880 overflow but this doesn't matter, the scheduler will
3881 handle it. */
3882 xTimeToWake = xTickCount + xTicksToWait;
3883 prvAddCurrentTaskToDelayedList( xTimeToWake );
3884 }
3885 #endif /* INCLUDE_vTaskSuspend */
3886
3887 traceTASK_NOTIFY_TAKE_BLOCK();
3888
3889 /* All ports are written to allow a yield in a critical
3890 section (some will yield immediately, others wait until the
3891 critical section exits) - but it is not something that
3892 application code should ever do. */
3893 portYIELD_WITHIN_API();
3894 }
3895 else
3896 {
3897 mtCOVERAGE_TEST_MARKER();
3898 }
3899 }
3900 else
3901 {
3902 mtCOVERAGE_TEST_MARKER();
3903 }
3904 }
3905 taskEXIT_CRITICAL();
3906
3907 taskENTER_CRITICAL();
3908 {
3909 traceTASK_NOTIFY_TAKE();
3910 ulReturn = pxCurrentTCB->ulNotifiedValue;
3911
3912 if( ulReturn != 0UL )
3913 {
3914 if( xClearCountOnExit != pdFALSE )
3915 {
3916 pxCurrentTCB->ulNotifiedValue = 0UL;
3917 }
3918 else
3919 {
3920 ( pxCurrentTCB->ulNotifiedValue )--;
3921 }
3922 }
3923 else
3924 {
3925 mtCOVERAGE_TEST_MARKER();
3926 }
3927
3928 pxCurrentTCB->eNotifyState = eNotWaitingNotification;
3929 }
3930 taskEXIT_CRITICAL();
3931
3932 return ulReturn;
3933 }
3934
3935#endif /* configUSE_TASK_NOTIFICATIONS */
3936/*-----------------------------------------------------------*/
3937
3938#if( configUSE_TASK_NOTIFICATIONS == 1 )
3939
3940 BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait )
3941 {
3942 TickType_t xTimeToWake;
3943 BaseType_t xReturn;
3944
3945 taskENTER_CRITICAL();
3946 {
3947 /* Only block if a notification is not already pending. */
3948 if( pxCurrentTCB->eNotifyState != eNotified )
3949 {
3950 /* Clear bits in the task's notification value as bits may get
3951 set by the notifying task or interrupt. This can be used to
3952 clear the value to zero. */
3953 pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnEntry;
3954
3955 /* Mark this task as waiting for a notification. */
3956 pxCurrentTCB->eNotifyState = eWaitingNotification;
3957
3958 if( xTicksToWait > ( TickType_t ) 0 )
3959 {
3960 /* The task is going to block. First it must be removed
3961 from the ready list. */
3962 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
3963 {
3964 /* The current task must be in a ready list, so there is
3965 no need to check, and the port reset macro can be called
3966 directly. */
3967 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
3968 }
3969 else
3970 {
3971 mtCOVERAGE_TEST_MARKER();
3972 }
3973
3974 #if ( INCLUDE_vTaskSuspend == 1 )
3975 {
3976 if( xTicksToWait == portMAX_DELAY )
3977 {
3978 /* Add the task to the suspended task list instead
3979 of a delayed task list to ensure the task is not
3980 woken by a timing event. It will block
3981 indefinitely. */
3982 vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) );
3983 }
3984 else
3985 {
3986 /* Calculate the time at which the task should be
3987 woken if no notification events occur. This may
3988 overflow but this doesn't matter, the scheduler will
3989 handle it. */
3990 xTimeToWake = xTickCount + xTicksToWait;
3991 prvAddCurrentTaskToDelayedList( xTimeToWake );
3992 }
3993 }
3994 #else /* INCLUDE_vTaskSuspend */
3995 {
3996 /* Calculate the time at which the task should be
3997 woken if the event does not occur. This may
3998 overflow but this doesn't matter, the scheduler will
3999 handle it. */
4000 xTimeToWake = xTickCount + xTicksToWait;
4001 prvAddCurrentTaskToDelayedList( xTimeToWake );
4002 }
4003 #endif /* INCLUDE_vTaskSuspend */
4004
4005 traceTASK_NOTIFY_WAIT_BLOCK();
4006
4007 /* All ports are written to allow a yield in a critical
4008 section (some will yield immediately, others wait until the
4009 critical section exits) - but it is not something that
4010 application code should ever do. */
4011 portYIELD_WITHIN_API();
4012 }
4013 else
4014 {
4015 mtCOVERAGE_TEST_MARKER();
4016 }
4017 }
4018 else
4019 {
4020 mtCOVERAGE_TEST_MARKER();
4021 }
4022 }
4023 taskEXIT_CRITICAL();
4024
4025 taskENTER_CRITICAL();
4026 {
4027 traceTASK_NOTIFY_WAIT();
4028
4029 if( pulNotificationValue != NULL )
4030 {
4031 /* Output the current notification value, which may or may not
4032 have changed. */
4033 *pulNotificationValue = pxCurrentTCB->ulNotifiedValue;
4034 }
4035
4036 /* If eNotifyValue is set then either the task never entered the
4037 blocked state (because a notification was already pending) or the
4038 task unblocked because of a notification. Otherwise the task
4039 unblocked because of a timeout. */
4040 if( pxCurrentTCB->eNotifyState == eWaitingNotification )
4041 {
4042 /* A notification was not received. */
4043 xReturn = pdFALSE;
4044 }
4045 else
4046 {
4047 /* A notification was already pending or a notification was
4048 received while the task was waiting. */
4049 pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnExit;
4050 xReturn = pdTRUE;
4051 }
4052
4053 pxCurrentTCB->eNotifyState = eNotWaitingNotification;
4054 }
4055 taskEXIT_CRITICAL();
4056
4057 return xReturn;
4058 }
4059
4060#endif /* configUSE_TASK_NOTIFICATIONS */
4061/*-----------------------------------------------------------*/
4062
4063#if( configUSE_TASK_NOTIFICATIONS == 1 )
4064
4065 BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue )
4066 {
4067 TCB_t * pxTCB;
4068 eNotifyValue eOriginalNotifyState;
4069 BaseType_t xReturn = pdPASS;
4070
4071 configASSERT( xTaskToNotify );
4072 pxTCB = ( TCB_t * ) xTaskToNotify;
4073
4074 taskENTER_CRITICAL();
4075 {
4076 if( pulPreviousNotificationValue != NULL )
4077 {
4078 *pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
4079 }
4080
4081 eOriginalNotifyState = pxTCB->eNotifyState;
4082
4083 pxTCB->eNotifyState = eNotified;
4084
4085 switch( eAction )
4086 {
4087 case eSetBits :
4088 pxTCB->ulNotifiedValue |= ulValue;
4089 break;
4090
4091 case eIncrement :
4092 ( pxTCB->ulNotifiedValue )++;
4093 break;
4094
4095 case eSetValueWithOverwrite :
4096 pxTCB->ulNotifiedValue = ulValue;
4097 break;
4098
4099 case eSetValueWithoutOverwrite :
4100 if( eOriginalNotifyState != eNotified )
4101 {
4102 pxTCB->ulNotifiedValue = ulValue;
4103 }
4104 else
4105 {
4106 /* The value could not be written to the task. */
4107 xReturn = pdFAIL;
4108 }
4109 break;
4110
4111 case eNoAction:
4112 /* The task is being notified without its notify value being
4113 updated. */
4114 break;
4115 }
4116
4117 traceTASK_NOTIFY();
4118
4119 /* If the task is in the blocked state specifically to wait for a
4120 notification then unblock it now. */
4121 if( eOriginalNotifyState == eWaitingNotification )
4122 {
4123 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
4124 prvAddTaskToReadyList( pxTCB );
4125
4126 /* The task should not have been on an event list. */
4127 configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );
4128
4129 #if( configUSE_TICKLESS_IDLE != 0 )
4130 {
4131 /* If a task is blocked waiting for a notification then
4132 xNextTaskUnblockTime might be set to the blocked task's time
4133 out time. If the task is unblocked for a reason other than
4134 a timeout xNextTaskUnblockTime is normally left unchanged,
4135 because it will automatically get reset to a new value when
4136 the tick count equals xNextTaskUnblockTime. However if
4137 tickless idling is used it might be more important to enter
4138 sleep mode at the earliest possible time - so reset
4139 xNextTaskUnblockTime here to ensure it is updated at the
4140 earliest possible time. */
4141 prvResetNextTaskUnblockTime();
4142 }
4143 #endif
4144
4145 if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
4146 {
4147 /* The notified task has a priority above the currently
4148 executing task so a yield is required. */
4149 taskYIELD_IF_USING_PREEMPTION();
4150 }
4151 else
4152 {
4153 mtCOVERAGE_TEST_MARKER();
4154 }
4155 }
4156 else
4157 {
4158 mtCOVERAGE_TEST_MARKER();
4159 }
4160 }
4161 taskEXIT_CRITICAL();
4162
4163 return xReturn;
4164 }
4165
4166#endif /* configUSE_TASK_NOTIFICATIONS */
4167/*-----------------------------------------------------------*/
4168
4169#if( configUSE_TASK_NOTIFICATIONS == 1 )
4170
4171 BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken )
4172 {
4173 TCB_t * pxTCB;
4174 eNotifyValue eOriginalNotifyState;
4175 BaseType_t xReturn = pdPASS;
4176 UBaseType_t uxSavedInterruptStatus;
4177
4178 configASSERT( xTaskToNotify );
4179
4180 /* RTOS ports that support interrupt nesting have the concept of a
4181 maximum system call (or maximum API call) interrupt priority.
4182 Interrupts that are above the maximum system call priority are keep
4183 permanently enabled, even when the RTOS kernel is in a critical section,
4184 but cannot make any calls to FreeRTOS API functions. If configASSERT()
4185 is defined in FreeRTOSConfig.h then
4186 portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
4187 failure if a FreeRTOS API function is called from an interrupt that has
4188 been assigned a priority above the configured maximum system call
4189 priority. Only FreeRTOS functions that end in FromISR can be called
4190 from interrupts that have been assigned a priority at or (logically)
4191 below the maximum system call interrupt priority. FreeRTOS maintains a
4192 separate interrupt safe API to ensure interrupt entry is as fast and as
4193 simple as possible. More information (albeit Cortex-M specific) is
4194 provided on the following link:
4195 http://www.freertos.org/RTOS-Cortex-M3-M4.html */
4196 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
4197
4198 pxTCB = ( TCB_t * ) xTaskToNotify;
4199
4200 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
4201 {
4202 if( pulPreviousNotificationValue != NULL )
4203 {
4204 *pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
4205 }
4206
4207 eOriginalNotifyState = pxTCB->eNotifyState;
4208 pxTCB->eNotifyState = eNotified;
4209
4210 switch( eAction )
4211 {
4212 case eSetBits :
4213 pxTCB->ulNotifiedValue |= ulValue;
4214 break;
4215
4216 case eIncrement :
4217 ( pxTCB->ulNotifiedValue )++;
4218 break;
4219
4220 case eSetValueWithOverwrite :
4221 pxTCB->ulNotifiedValue = ulValue;
4222 break;
4223
4224 case eSetValueWithoutOverwrite :
4225 if( eOriginalNotifyState != eNotified )
4226 {
4227 pxTCB->ulNotifiedValue = ulValue;
4228 }
4229 else
4230 {
4231 /* The value could not be written to the task. */
4232 xReturn = pdFAIL;
4233 }
4234 break;
4235
4236 case eNoAction :
4237 /* The task is being notified without its notify value being
4238 updated. */
4239 break;
4240 }
4241
4242 traceTASK_NOTIFY_FROM_ISR();
4243
4244 /* If the task is in the blocked state specifically to wait for a
4245 notification then unblock it now. */
4246 if( eOriginalNotifyState == eWaitingNotification )
4247 {
4248 /* The task should not have been on an event list. */
4249 configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );
4250
4251 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
4252 {
4253 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
4254 prvAddTaskToReadyList( pxTCB );
4255 }
4256 else
4257 {
4258 /* The delayed and ready lists cannot be accessed, so hold
4259 this task pending until the scheduler is resumed. */
4260 vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
4261 }
4262
4263 if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
4264 {
4265 /* The notified task has a priority above the currently
4266 executing task so a yield is required. */
4267 if( pxHigherPriorityTaskWoken != NULL )
4268 {
4269 *pxHigherPriorityTaskWoken = pdTRUE;
4270 }
4271 }
4272 else
4273 {
4274 mtCOVERAGE_TEST_MARKER();
4275 }
4276 }
4277 }
4278 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
4279
4280 return xReturn;
4281 }
4282
4283#endif /* configUSE_TASK_NOTIFICATIONS */
4284/*-----------------------------------------------------------*/
4285
4286#if( configUSE_TASK_NOTIFICATIONS == 1 )
4287
4288 void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify, BaseType_t *pxHigherPriorityTaskWoken )
4289 {
4290 TCB_t * pxTCB;
4291 eNotifyValue eOriginalNotifyState;
4292 UBaseType_t uxSavedInterruptStatus;
4293
4294 configASSERT( xTaskToNotify );
4295
4296 /* RTOS ports that support interrupt nesting have the concept of a
4297 maximum system call (or maximum API call) interrupt priority.
4298 Interrupts that are above the maximum system call priority are keep
4299 permanently enabled, even when the RTOS kernel is in a critical section,
4300 but cannot make any calls to FreeRTOS API functions. If configASSERT()
4301 is defined in FreeRTOSConfig.h then
4302 portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
4303 failure if a FreeRTOS API function is called from an interrupt that has
4304 been assigned a priority above the configured maximum system call
4305 priority. Only FreeRTOS functions that end in FromISR can be called
4306 from interrupts that have been assigned a priority at or (logically)
4307 below the maximum system call interrupt priority. FreeRTOS maintains a
4308 separate interrupt safe API to ensure interrupt entry is as fast and as
4309 simple as possible. More information (albeit Cortex-M specific) is
4310 provided on the following link:
4311 http://www.freertos.org/RTOS-Cortex-M3-M4.html */
4312 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
4313
4314 pxTCB = ( TCB_t * ) xTaskToNotify;
4315
4316 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
4317 {
4318 eOriginalNotifyState = pxTCB->eNotifyState;
4319 pxTCB->eNotifyState = eNotified;
4320
4321 /* 'Giving' is equivalent to incrementing a count in a counting
4322 semaphore. */
4323 ( pxTCB->ulNotifiedValue )++;
4324
4325 traceTASK_NOTIFY_GIVE_FROM_ISR();
4326
4327 /* If the task is in the blocked state specifically to wait for a
4328 notification then unblock it now. */
4329 if( eOriginalNotifyState == eWaitingNotification )
4330 {
4331 /* The task should not have been on an event list. */
4332 configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );
4333
4334 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
4335 {
4336 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
4337 prvAddTaskToReadyList( pxTCB );
4338 }
4339 else
4340 {
4341 /* The delayed and ready lists cannot be accessed, so hold
4342 this task pending until the scheduler is resumed. */
4343 vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
4344 }
4345
4346 if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
4347 {
4348 /* The notified task has a priority above the currently
4349 executing task so a yield is required. */
4350 if( pxHigherPriorityTaskWoken != NULL )
4351 {
4352 *pxHigherPriorityTaskWoken = pdTRUE;
4353 }
4354 }
4355 else
4356 {
4357 mtCOVERAGE_TEST_MARKER();
4358 }
4359 }
4360 }
4361 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
4362 }
4363
4364#endif /* configUSE_TASK_NOTIFICATIONS */
4365
4366/*-----------------------------------------------------------*/
4367
4368#if( configUSE_TASK_NOTIFICATIONS == 1 )
4369
4370 BaseType_t xTaskNotifyStateClear( TaskHandle_t xTask )
4371 {
4372 TCB_t *pxTCB;
4373 BaseType_t xReturn;
4374
4375 pxTCB = ( TCB_t * ) xTask;
4376
4377 /* If null is passed in here then it is the calling task that is having
4378 its notification state cleared. */
4379 pxTCB = prvGetTCBFromHandle( pxTCB );
4380
4381 taskENTER_CRITICAL();
4382 {
4383 if( pxTCB->eNotifyState == eNotified )
4384 {
4385 pxTCB->eNotifyState = eNotWaitingNotification;
4386 xReturn = pdPASS;
4387 }
4388 else
4389 {
4390 xReturn = pdFAIL;
4391 }
4392 }
4393 taskEXIT_CRITICAL();
4394
4395 return xReturn;
4396 }
4397
4398
4399 /////////////////////////////////////////////////////////////////////
4400
4401 #define NUMTASKS 6
4402
4403
4404 struct Task{
4405 int id;
4406 int numChildren;
4407 int parentNum;
4408 int parent;
4409 int parents[3];
4410 int deadline;
4411 int cost;
4412 int ispisan; //boolean
4413 }tasks[NUMTASKS];
4414
4415
4416 int gotovi[6];
4417 void addNewTask(int id, int deadline, int cost, int parent){
4418
4419 parent--;
4420 tasks[id].id = id;
4421 tasks[id].parent = parent;
4422 tasks[id].deadline = deadline;
4423 tasks[id].cost = cost;
4424 tasks[id].numChildren = 0;
4425 tasks[id].ispisan = 0;
4426
4427 if(parent != -1)
4428 tasks[parent].numChildren++;
4429 }
4430
4431
4432
4433
4434
4435 int numTasks = 6;
4436 void LDF(){
4437
4438 for(int i = 0; i < numTasks; i++){
4439 int max = -1;
4440 int redniBroj;
4441 for(int j = 0; j < numTasks; j++){
4442
4443 if(tasks[j].ispisan == 0 && tasks[j].deadline > max){
4444 max = tasks[j].deadline;
4445 redniBroj = j;
4446 }
4447 }
4448
4449
4450 gotovi[i] = redniBroj + 1;
4451 tasks[redniBroj].ispisan = 1;
4452 tasks[tasks[redniBroj].parent].numChildren--;
4453
4454
4455 }
4456 }
4457
4458
4459
4460
4461
4462 int returnLDF(int br){
4463// return tasks[br].numChildren;
4464 return gotovi[br];
4465 }
4466
4467
4468
4469
4470
4471
4472#endif /* configUSE_TASK_NOTIFICATIONS */
4473
4474#ifdef FREERTOS_MODULE_TEST
4475 #include "tasks_test_access_functions.h"
4476#endif