forked from FreeRTOS/FreeRTOS-Kernel
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tasks.c
7671 lines (6605 loc) · 305 KB
/
tasks.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/* Standard includes. */
#include <stdlib.h>
#include <string.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
* all the API functions to use the MPU wrappers. That should only be done when
* task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "stack_macros.h"
/* Lint e9021, e961 and e750 are suppressed as a MISRA exception justified
* because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined
* for the header files above, but not in this file, in order to generate the
* correct privileged Vs unprivileged linkage and placement. */
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021. */
/* Set configUSE_STATS_FORMATTING_FUNCTIONS to 2 to include the stats formatting
* functions but without including stdio.h here. */
#if ( configUSE_STATS_FORMATTING_FUNCTIONS == 1 )
/* At the bottom of this file are two optional functions that can be used
* to generate human readable text from the raw data generated by the
* uxTaskGetSystemState() function. Note the formatting functions are provided
* for convenience only, and are NOT considered part of the kernel. */
#include <stdio.h>
#endif /* configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) */
#if ( configNUMBER_OF_CORES == 1 )
#if ( configUSE_PREEMPTION == 0 )
/* If the cooperative scheduler is being used then a yield should not be
* performed just because a higher priority task has been woken. */
#define taskYIELD_IF_USING_PREEMPTION()
#else
#define taskYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API()
#endif
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
/* Values that can be assigned to the ucNotifyState member of the TCB. */
#define taskNOT_WAITING_NOTIFICATION ( ( uint8_t ) 0 ) /* Must be zero as it is the initialised value. */
#define taskWAITING_NOTIFICATION ( ( uint8_t ) 1 )
#define taskNOTIFICATION_RECEIVED ( ( uint8_t ) 2 )
/*
* The value used to fill the stack of a task when the task is created. This
* is used purely for checking the high water mark for tasks.
*/
#define tskSTACK_FILL_BYTE ( 0xa5U )
/* Bits used to record how a task's stack and TCB were allocated. */
#define tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 0 )
#define tskSTATICALLY_ALLOCATED_STACK_ONLY ( ( uint8_t ) 1 )
#define tskSTATICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 2 )
/* If any of the following are set then task stacks are filled with a known
* value so the high water mark can be determined. If none of the following are
* set then don't fill the stack so there is no unnecessary dependency on memset. */
#if ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark2 == 1 ) )
#define tskSET_NEW_STACKS_TO_KNOWN_VALUE 1
#else
#define tskSET_NEW_STACKS_TO_KNOWN_VALUE 0
#endif
/*
* Macros used by vListTask to indicate which state a task is in.
*/
#define tskRUNNING_CHAR ( 'X' )
#define tskBLOCKED_CHAR ( 'B' )
#define tskREADY_CHAR ( 'R' )
#define tskDELETED_CHAR ( 'D' )
#define tskSUSPENDED_CHAR ( 'S' )
/*
* Some kernel aware debuggers require the data the debugger needs access to to
* be global, rather than file scope.
*/
#ifdef portREMOVE_STATIC_QUALIFIER
#define static
#endif
/* The name allocated to the Idle task. This can be overridden by defining
* configIDLE_TASK_NAME in FreeRTOSConfig.h. */
#ifndef configIDLE_TASK_NAME
#define configIDLE_TASK_NAME "IDLE"
#endif
#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
/* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is
* performed in a generic way that is not optimised to any particular
* microcontroller architecture. */
/* uxTopReadyPriority holds the priority of the highest priority ready
* state task. */
#define taskRECORD_READY_PRIORITY( uxPriority ) \
do { \
if( ( uxPriority ) > uxTopReadyPriority ) \
{ \
uxTopReadyPriority = ( uxPriority ); \
} \
} while( 0 ) /* taskRECORD_READY_PRIORITY */
/*-----------------------------------------------------------*/
#if ( configNUMBER_OF_CORES == 1 )
#define taskSELECT_HIGHEST_PRIORITY_TASK() \
do { \
UBaseType_t uxTopPriority = uxTopReadyPriority; \
\
/* Find the highest priority queue that contains ready tasks. */ \
while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopPriority ] ) ) ) \
{ \
configASSERT( uxTopPriority ); \
--uxTopPriority; \
} \
\
/* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of \
* the same priority get an equal share of the processor time. */ \
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \
uxTopReadyPriority = uxTopPriority; \
} while( 0 ) /* taskSELECT_HIGHEST_PRIORITY_TASK */
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
/*-----------------------------------------------------------*/
/* Define away taskRESET_READY_PRIORITY() and portRESET_READY_PRIORITY() as
* they are only required when a port optimised method of task selection is
* being used. */
#define taskRESET_READY_PRIORITY( uxPriority )
#define portRESET_READY_PRIORITY( uxPriority, uxTopReadyPriority )
#else /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
#if ( configNUMBER_OF_CORES > 1 )
#error configUSE_PORT_OPTIMISED_TASK_SELECTION not supported in FreeRTOS SMP.
#endif
/* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 1 then task selection is
* performed in a way that is tailored to the particular microcontroller
* architecture being used. */
/* A port optimised version is provided. Call the port defined macros. */
#define taskRECORD_READY_PRIORITY( uxPriority ) portRECORD_READY_PRIORITY( ( uxPriority ), uxTopReadyPriority )
/*-----------------------------------------------------------*/
#define taskSELECT_HIGHEST_PRIORITY_TASK() \
do { \
UBaseType_t uxTopPriority; \
\
/* Find the highest priority list that contains ready tasks. */ \
portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \
configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \
} while( 0 )
/*-----------------------------------------------------------*/
/* A port optimised version is provided, call it only if the TCB being reset
* is being referenced from a ready list. If it is referenced from a delayed
* or suspended list then it won't be in a ready list. */
#define taskRESET_READY_PRIORITY( uxPriority ) \
do { \
if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == ( UBaseType_t ) 0 ) \
{ \
portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) ); \
} \
} while( 0 )
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
/*-----------------------------------------------------------*/
/* pxDelayedTaskList and pxOverflowDelayedTaskList are switched when the tick
* count overflows. */
#define taskSWITCH_DELAYED_LISTS() \
do { \
List_t * pxTemp; \
\
/* The delayed tasks list should be empty when the lists are switched. */ \
configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) ); \
\
pxTemp = pxDelayedTaskList; \
pxDelayedTaskList = pxOverflowDelayedTaskList; \
pxOverflowDelayedTaskList = pxTemp; \
xNumOfOverflows++; \
prvResetNextTaskUnblockTime(); \
} while( 0 )
/*-----------------------------------------------------------*/
/*
* Place the task represented by pxTCB into the appropriate ready list for
* the task. It is inserted at the end of the list.
*/
#define prvAddTaskToReadyList( pxTCB ) \
do { \
traceMOVED_TASK_TO_READY_STATE( pxTCB ); \
taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \
listINSERT_END( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); \
tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB ); \
} while( 0 )
/*-----------------------------------------------------------*/
/*
* Several functions take a TaskHandle_t parameter that can optionally be NULL,
* where NULL is used to indicate that the handle of the currently executing
* task should be used in place of the parameter. This macro simply checks to
* see if the parameter is NULL and returns a pointer to the appropriate TCB.
*/
#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? pxCurrentTCB : ( pxHandle ) )
/* The item value of the event list item is normally used to hold the priority
* of the task to which it belongs (coded to allow it to be held in reverse
* priority order). However, it is occasionally borrowed for other purposes. It
* is important its value is not updated due to a task priority change while it is
* being used for another purpose. The following bit definition is used to inform
* the scheduler that the value should not be changed - in which case it is the
* responsibility of whichever module is using the value to ensure it gets set back
* to its original value when it is released. */
#if ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_16_BITS )
#define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x8000U
#elif ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_32_BITS )
#define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x80000000UL
#elif ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_64_BITS )
#define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x8000000000000000ULL
#endif
/* Task state. */
typedef BaseType_t TaskRunning_t;
/* Indicates that the task is not actively running on any core. */
#define taskTASK_NOT_RUNNING ( TaskRunning_t ) ( -1 )
/* Indicates that the task is actively running but scheduled to yield. */
#define taskTASK_YIELDING ( TaskRunning_t ) ( -2 )
/* Returns pdTRUE if the task is actively running and not scheduled to yield. */
#if ( configNUMBER_OF_CORES == 1 )
#define taskTASK_IS_RUNNING( pxTCB ) ( ( ( pxTCB ) == pxCurrentTCB ) ? ( pdTRUE ) : ( pdFALSE ) )
#else
#define taskTASK_IS_RUNNING( pxTCB ) ( ( ( ( pxTCB )->xTaskRunState >= ( BaseType_t ) 0 ) && ( ( pxTCB )->xTaskRunState < ( BaseType_t ) configNUMBER_OF_CORES ) ) ? ( pdTRUE ) : ( pdFALSE ) )
#endif
/* Indicates that the task is an Idle task. */
#define taskATTRIBUTE_IS_IDLE ( UBaseType_t ) ( 1UL << 0UL )
#if ( ( configNUMBER_OF_CORES > 1 ) && ( portCRITICAL_NESTING_IN_TCB == 1 ) )
#define portGET_CRITICAL_NESTING_COUNT() ( pxCurrentTCBs[ portGET_CORE_ID() ]->uxCriticalNesting )
#define portSET_CRITICAL_NESTING_COUNT( x ) ( pxCurrentTCBs[ portGET_CORE_ID() ]->uxCriticalNesting = ( x ) )
#define portINCREMENT_CRITICAL_NESTING_COUNT() ( pxCurrentTCBs[ portGET_CORE_ID() ]->uxCriticalNesting++ )
#define portDECREMENT_CRITICAL_NESTING_COUNT() ( pxCurrentTCBs[ portGET_CORE_ID() ]->uxCriticalNesting-- )
#endif /* #if ( ( configNUMBER_OF_CORES > 1 ) && ( portCRITICAL_NESTING_IN_TCB == 1 ) ) */
/* Code below here allows infinite loop controlling, especially for the infinite loop
* in idle task function (for example when performing unit tests). */
#ifndef INFINITE_LOOP
#define INFINITE_LOOP() 1
#endif
/*
* Task control block. A task control block (TCB) is allocated for each task,
* and stores task state information, including a pointer to the task's context
* (the task's run time environment, including register values)
*/
typedef struct tskTaskControlBlock /* The old naming convention is used to prevent breaking kernel aware debuggers. */
{
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. */
#if ( portUSING_MPU_WRAPPERS == 1 )
xMPU_SETTINGS xMPUSettings; /**< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */
#endif
#if ( configUSE_CORE_AFFINITY == 1 ) && ( configNUMBER_OF_CORES > 1 )
UBaseType_t uxCoreAffinityMask; /*< Used to link the task to certain cores. UBaseType_t must have greater than or equal to the number of bits as confNUM_CORES. */
#endif
ListItem_t xStateListItem; /**< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
ListItem_t xEventListItem; /**< Used to reference a task from an event list. */
UBaseType_t uxPriority; /**< The priority of the task. 0 is the lowest priority. */
StackType_t * pxStack; /**< Points to the start of the stack. */
#if ( configNUMBER_OF_CORES > 1 )
volatile TaskRunning_t xTaskRunState; /**< Used to identify the core the task is running on, if the task is running. Otherwise, identifies the task's state - not running or yielding. */
UBaseType_t uxTaskAttributes; /**< Task's attributes - currently used to identify the idle tasks. */
#endif
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. */
#if ( configUSE_TASK_PREEMPTION_DISABLE == 1 )
BaseType_t xPreemptionDisable; /**< Used to prevent the task from being preempted. */
#endif
#if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
StackType_t * pxEndOfStack; /**< Points to the highest valid address for the stack. */
#endif
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
UBaseType_t uxCriticalNesting; /**< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */
#endif
#if ( configUSE_TRACE_FACILITY == 1 )
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. */
UBaseType_t uxTaskNumber; /**< Stores a number specifically for use by third party trace code. */
#endif
#if ( configUSE_MUTEXES == 1 )
UBaseType_t uxBasePriority; /**< The priority last assigned to the task - used by the priority inheritance mechanism. */
UBaseType_t uxMutexesHeld;
#endif
#if ( configUSE_APPLICATION_TASK_TAG == 1 )
TaskHookFunction_t pxTaskTag;
#endif
#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
void * pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
#endif
#if ( configGENERATE_RUN_TIME_STATS == 1 )
configRUN_TIME_COUNTER_TYPE ulRunTimeCounter; /**< Stores the amount of time the task has spent in the Running state. */
#endif
#if ( configUSE_C_RUNTIME_TLS_SUPPORT == 1 )
configTLS_BLOCK_TYPE xTLSBlock; /**< Memory block used as Thread Local Storage (TLS) Block for the task. */
#endif
#if ( configUSE_TASK_NOTIFICATIONS == 1 )
volatile uint32_t ulNotifiedValue[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
volatile uint8_t ucNotifyState[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
#endif
/* See the comments in FreeRTOS.h with the definition of
* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */
#if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */
uint8_t ucStaticallyAllocated; /**< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */
#endif
#if ( INCLUDE_xTaskAbortDelay == 1 )
uint8_t ucDelayAborted;
#endif
#if ( configUSE_POSIX_ERRNO == 1 )
int iTaskErrno;
#endif
} tskTCB;
/* The old tskTCB name is maintained above then typedefed to the new TCB_t name
* below to enable the use of older kernel aware debuggers. */
typedef tskTCB TCB_t;
/*lint -save -e956 A manual analysis and inspection has been used to determine
* which static variables must be declared volatile. */
#if ( configNUMBER_OF_CORES == 1 )
portDONT_DISCARD PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL;
#else
/* MISRA Ref 8.4.1 [Declaration shall be visible] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-84 */
/* coverity[misra_c_2012_rule_8_4_violation] */
portDONT_DISCARD PRIVILEGED_DATA TCB_t * volatile pxCurrentTCBs[ configNUMBER_OF_CORES ];
#define pxCurrentTCB xTaskGetCurrentTaskHandle()
#endif
/* Lists for ready and blocked tasks. --------------------
* xDelayedTaskList1 and xDelayedTaskList2 could be moved to function scope but
* doing so breaks some kernel aware debuggers and debuggers that rely on removing
* the static qualifier. */
PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ]; /**< Prioritised ready tasks. */
PRIVILEGED_DATA static List_t xDelayedTaskList1; /**< Delayed tasks. */
PRIVILEGED_DATA static List_t xDelayedTaskList2; /**< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList; /**< Points to the delayed task list currently being used. */
PRIVILEGED_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. */
PRIVILEGED_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. */
#if ( INCLUDE_vTaskDelete == 1 )
PRIVILEGED_DATA static List_t xTasksWaitingTermination; /**< Tasks that have been deleted - but their memory not yet freed. */
PRIVILEGED_DATA static volatile UBaseType_t uxDeletedTasksWaitingCleanUp = ( UBaseType_t ) 0U;
#endif
#if ( INCLUDE_vTaskSuspend == 1 )
PRIVILEGED_DATA static List_t xSuspendedTaskList; /**< Tasks that are currently suspended. */
#endif
/* Global POSIX errno. Its value is changed upon context switching to match
* the errno of the currently running task. */
#if ( configUSE_POSIX_ERRNO == 1 )
int FreeRTOS_errno = 0;
#endif
/* Other file private variables. --------------------------------*/
PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U;
PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT;
PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY;
PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE;
PRIVILEGED_DATA static volatile TickType_t xPendedTicks = ( TickType_t ) 0U;
PRIVILEGED_DATA static volatile BaseType_t xYieldPendings[ configNUMBER_OF_CORES ] = { pdFALSE };
PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = ( BaseType_t ) 0;
PRIVILEGED_DATA static UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U;
PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = ( TickType_t ) 0U; /* Initialised to portMAX_DELAY before the scheduler starts. */
PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandles[ configNUMBER_OF_CORES ]; /**< Holds the handles of the idle tasks. The idle tasks are created automatically when the scheduler is started. */
/* Improve support for OpenOCD. The kernel tracks Ready tasks via priority lists.
* For tracking the state of remote threads, OpenOCD uses uxTopUsedPriority
* to determine the number of priority lists to read back from the remote target. */
const volatile UBaseType_t uxTopUsedPriority = configMAX_PRIORITIES - 1U;
/* Context switches are held pending while the scheduler is suspended. Also,
* interrupts must not manipulate the xStateListItem of a TCB, or any of the
* lists the xStateListItem can be referenced from, if the scheduler is suspended.
* If an interrupt needs to unblock a task while the scheduler is suspended then it
* moves the task's event list item into the xPendingReadyList, ready for the
* kernel to move the task from the pending ready list into the real ready list
* when the scheduler is unsuspended. The pending ready list itself can only be
* accessed from a critical section.
*
* Updates to uxSchedulerSuspended must be protected by both the task lock and the ISR lock
* and must not be done from an ISR. Reads must be protected by either lock and may be done
* from either an ISR or a task. */
PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t ) 0U;
#if ( configGENERATE_RUN_TIME_STATS == 1 )
/* Do not move these variables to function scope as doing so prevents the
* code working with debuggers that need to remove the static qualifier. */
PRIVILEGED_DATA static configRUN_TIME_COUNTER_TYPE ulTaskSwitchedInTime[ configNUMBER_OF_CORES ] = { 0U }; /**< Holds the value of a timer/counter the last time a task was switched in. */
PRIVILEGED_DATA static volatile configRUN_TIME_COUNTER_TYPE ulTotalRunTime[ configNUMBER_OF_CORES ] = { 0U }; /**< Holds the total amount of execution time as defined by the run time counter clock. */
#endif
#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configNUMBER_OF_CORES > 1 )
/* Do not move these variables to function scope as doing so prevents the
* code working with debuggers that need to remove the static qualifier. */
static StaticTask_t xIdleTCBBuffers[ configNUMBER_OF_CORES - 1 ];
static StackType_t xIdleTaskStackBuffers[ configNUMBER_OF_CORES - 1 ][ configMINIMAL_STACK_SIZE ];
#endif /* #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configNUMBER_OF_CORES > 1 ) */
/*lint -restore */
/*-----------------------------------------------------------*/
/* File private functions. --------------------------------*/
/*
* Creates the idle tasks during scheduler start.
*/
static BaseType_t prvCreateIdleTasks( void );
#if ( configNUMBER_OF_CORES > 1 )
/*
* Checks to see if another task moved the current task out of the ready
* list while it was waiting to enter a critical section and yields, if so.
*/
static void prvCheckForRunStateChange( void );
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
#if ( configNUMBER_OF_CORES > 1 )
/*
* Yields the given core.
*/
static void prvYieldCore( BaseType_t xCoreID );
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
#if ( configNUMBER_OF_CORES > 1 )
/*
* Yields a core, or cores if multiple priorities are not allowed to run
* simultaneously, to allow the task pxTCB to run.
*/
static void prvYieldForTask( const TCB_t * pxTCB );
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
#if ( configNUMBER_OF_CORES > 1 )
/*
* Selects the highest priority available task for the given core.
*/
static void prvSelectHighestPriorityTask( BaseType_t xCoreID );
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
/**
* Utility task that simply returns pdTRUE if the task referenced by xTask is
* currently in the Suspended state, or pdFALSE if the task referenced by xTask
* is in any other state.
*/
#if ( INCLUDE_vTaskSuspend == 1 )
static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
#endif /* INCLUDE_vTaskSuspend */
/*
* Utility to ready all the lists used by the scheduler. This is called
* automatically upon the creation of the first task.
*/
static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION;
/*
* The idle task, which as all tasks is implemented as a never ending loop.
* The idle task is automatically created and added to the ready lists upon
* creation of the first user task.
*
* In the FreeRTOS SMP, configNUMBER_OF_CORES - 1 minimal idle tasks are also
* created to ensure that each core has an idle task to run when no other
* task is available to run.
*
* The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific
* language extensions. The equivalent prototype for these functions are:
*
* void prvIdleTask( void *pvParameters );
* void prvMinimalIdleTask( void *pvParameters );
*
*/
static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters ) PRIVILEGED_FUNCTION;
#if ( configNUMBER_OF_CORES > 1 )
static portTASK_FUNCTION_PROTO( prvMinimalIdleTask, pvParameters ) PRIVILEGED_FUNCTION;
#endif
/*
* Utility to free all memory allocated by the scheduler to hold a TCB,
* including the stack pointed to by the TCB.
*
* This does not free memory allocated by the task itself (i.e. memory
* allocated by calls to pvPortMalloc from within the tasks application code).
*/
#if ( INCLUDE_vTaskDelete == 1 )
static void prvDeleteTCB( TCB_t * pxTCB ) PRIVILEGED_FUNCTION;
#endif
/*
* Used only by the idle task. This checks to see if anything has been placed
* in the list of tasks waiting to be deleted. If so the task is cleaned up
* and its TCB deleted.
*/
static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION;
/*
* The currently executing task is entering the Blocked state. Add the task to
* either the current or the overflow delayed task list.
*/
static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait,
const BaseType_t xCanBlockIndefinitely ) PRIVILEGED_FUNCTION;
/*
* Fills an TaskStatus_t structure with information on each task that is
* referenced from the pxList list (which may be a ready list, a delayed list,
* a suspended list, etc.).
*
* THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM
* NORMAL APPLICATION CODE.
*/
#if ( configUSE_TRACE_FACILITY == 1 )
static UBaseType_t prvListTasksWithinSingleList( TaskStatus_t * pxTaskStatusArray,
List_t * pxList,
eTaskState eState ) PRIVILEGED_FUNCTION;
#endif
/*
* Searches pxList for a task with name pcNameToQuery - returning a handle to
* the task if it is found, or NULL if the task is not found.
*/
#if ( INCLUDE_xTaskGetHandle == 1 )
static TCB_t * prvSearchForNameWithinSingleList( List_t * pxList,
const char pcNameToQuery[] ) PRIVILEGED_FUNCTION;
#endif
/*
* When a task is created, the stack of the task is filled with a known value.
* This function determines the 'high water mark' of the task stack by
* determining how much of the stack remains at the original preset value.
*/
#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark2 == 1 ) )
static configSTACK_DEPTH_TYPE prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte ) PRIVILEGED_FUNCTION;
#endif
/*
* Return the amount of time, in ticks, that will pass before the kernel will
* next move a task from the Blocked state to the Running state.
*
* This conditional compilation should use inequality to 0, not equality to 1.
* This is to ensure portSUPPRESS_TICKS_AND_SLEEP() can be called when user
* defined low power mode implementations require configUSE_TICKLESS_IDLE to be
* set to a value other than 1.
*/
#if ( configUSE_TICKLESS_IDLE != 0 )
static TickType_t prvGetExpectedIdleTime( void ) PRIVILEGED_FUNCTION;
#endif
/*
* Set xNextTaskUnblockTime to the time at which the next Blocked state task
* will exit the Blocked state.
*/
static void prvResetNextTaskUnblockTime( void ) PRIVILEGED_FUNCTION;
#if ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 )
/*
* Helper function used to pad task names with spaces when printing out
* human readable tables of task information.
*/
static char * prvWriteNameToBuffer( char * pcBuffer,
const char * pcTaskName ) PRIVILEGED_FUNCTION;
#endif
/*
* Called after a Task_t structure has been allocated either statically or
* dynamically to fill in the structure's members.
*/
static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
const uint32_t ulStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask,
TCB_t * pxNewTCB,
const MemoryRegion_t * const xRegions ) PRIVILEGED_FUNCTION;
/*
* Called after a new task has been created and initialised to place the task
* under the control of the scheduler.
*/
static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION;
/*
* freertos_tasks_c_additions_init() should only be called if the user definable
* macro FREERTOS_TASKS_C_ADDITIONS_INIT() is defined, as that is the only macro
* called by the function.
*/
#ifdef FREERTOS_TASKS_C_ADDITIONS_INIT
static void freertos_tasks_c_additions_init( void ) PRIVILEGED_FUNCTION;
#endif
#if ( configUSE_MINIMAL_IDLE_HOOK == 1 )
extern void vApplicationMinimalIdleHook( void );
#endif /* #if ( configUSE_MINIMAL_IDLE_HOOK == 1 ) */
/*-----------------------------------------------------------*/
#if ( configNUMBER_OF_CORES > 1 )
static void prvCheckForRunStateChange( void )
{
UBaseType_t uxPrevCriticalNesting;
const TCB_t * pxThisTCB;
/* This should be skipped if called from an ISR. If the task on the current
* core is no longer running, then vTaskSwitchContext() probably should
* be run before returning, but we don't have a way to force that to happen
* from here. */
if( portCHECK_IF_IN_ISR() == pdFALSE )
{
/* This function is always called with interrupts disabled
* so this is safe. */
pxThisTCB = pxCurrentTCBs[ portGET_CORE_ID() ];
while( pxThisTCB->xTaskRunState == taskTASK_YIELDING )
{
/* We are only here if we just entered a critical section
* or if we just suspended the scheduler, and another task
* has requested that we yield.
*
* This is slightly complicated since we need to save and restore
* the suspension and critical nesting counts, as well as release
* and reacquire the correct locks. And then, do it all over again
* if our state changed again during the reacquisition. */
uxPrevCriticalNesting = portGET_CRITICAL_NESTING_COUNT();
if( uxPrevCriticalNesting > 0U )
{
portSET_CRITICAL_NESTING_COUNT( 0U );
portRELEASE_ISR_LOCK();
}
else
{
/* The scheduler is suspended. uxSchedulerSuspended is updated
* only when the task is not requested to yield. */
mtCOVERAGE_TEST_MARKER();
}
portRELEASE_TASK_LOCK();
portMEMORY_BARRIER();
configASSERT( pxThisTCB->xTaskRunState == taskTASK_YIELDING );
portENABLE_INTERRUPTS();
/* Enabling interrupts should cause this core to immediately
* service the pending interrupt and yield. If the run state is still
* yielding here then that is a problem. */
configASSERT( pxThisTCB->xTaskRunState != taskTASK_YIELDING );
portDISABLE_INTERRUPTS();
portGET_TASK_LOCK();
portGET_ISR_LOCK();
portSET_CRITICAL_NESTING_COUNT( uxPrevCriticalNesting );
if( uxPrevCriticalNesting == 0U )
{
portRELEASE_ISR_LOCK();
}
}
}
}
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
/*-----------------------------------------------------------*/
#if ( configNUMBER_OF_CORES > 1 )
static void prvYieldCore( BaseType_t xCoreID )
{
/* This must be called from a critical section and xCoreID must be valid. */
if( ( portCHECK_IF_IN_ISR() == pdTRUE ) && ( xCoreID == ( BaseType_t ) portGET_CORE_ID() ) )
{
xYieldPendings[ xCoreID ] = pdTRUE;
}
else
{
if( pxCurrentTCBs[ xCoreID ]->xTaskRunState != taskTASK_YIELDING )
{
if( xCoreID == ( BaseType_t ) portGET_CORE_ID() )
{
xYieldPendings[ xCoreID ] = pdTRUE;
}
else
{
portYIELD_CORE( xCoreID );
pxCurrentTCBs[ xCoreID ]->xTaskRunState = taskTASK_YIELDING;
}
}
}
}
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
/*-----------------------------------------------------------*/
#if ( configNUMBER_OF_CORES > 1 )
static void prvYieldForTask( const TCB_t * pxTCB )
{
BaseType_t xLowestPriorityToPreempt;
BaseType_t xCurrentCoreTaskPriority;
BaseType_t xLowestPriorityCore = ( BaseType_t ) -1;
BaseType_t xCoreID;
#if ( configRUN_MULTIPLE_PRIORITIES == 0 )
BaseType_t xYieldCount = 0;
#endif /* #if ( configRUN_MULTIPLE_PRIORITIES == 0 ) */
/* This must be called from a critical section. */
configASSERT( portGET_CRITICAL_NESTING_COUNT() > 0U );
#if ( configRUN_MULTIPLE_PRIORITIES == 0 )
/* No task should yield for this one if it is a lower priority
* than priority level of currently ready tasks. */
if( pxTCB->uxPriority >= uxTopReadyPriority )
#else
/* Yield is not required for a task which is already running. */
if( taskTASK_IS_RUNNING( pxTCB ) == pdFALSE )
#endif
{
xLowestPriorityToPreempt = ( BaseType_t ) pxTCB->uxPriority;
/* xLowestPriorityToPreempt will be decremented to -1 if the priority of pxTCB
* is 0. This is ok as we will give system idle tasks a priority of -1 below. */
--xLowestPriorityToPreempt;
for( xCoreID = ( BaseType_t ) 0; xCoreID < ( BaseType_t ) configNUMBER_OF_CORES; xCoreID++ )
{
xCurrentCoreTaskPriority = ( BaseType_t ) pxCurrentTCBs[ xCoreID ]->uxPriority;
/* System idle tasks are being assigned a priority of tskIDLE_PRIORITY - 1 here. */
if( ( pxCurrentTCBs[ xCoreID ]->uxTaskAttributes & taskATTRIBUTE_IS_IDLE ) != 0U )
{
xCurrentCoreTaskPriority = xCurrentCoreTaskPriority - 1;
}
if( ( taskTASK_IS_RUNNING( pxCurrentTCBs[ xCoreID ] ) != pdFALSE ) && ( xYieldPendings[ xCoreID ] == pdFALSE ) )
{
#if ( configRUN_MULTIPLE_PRIORITIES == 0 )
if( taskTASK_IS_RUNNING( pxTCB ) == pdFALSE )
#endif
{
if( xCurrentCoreTaskPriority <= xLowestPriorityToPreempt )
{
#if ( configUSE_CORE_AFFINITY == 1 )
if( ( pxTCB->uxCoreAffinityMask & ( ( UBaseType_t ) 1U << ( UBaseType_t ) xCoreID ) ) != 0U )
#endif
{
#if ( configUSE_TASK_PREEMPTION_DISABLE == 1 )
if( pxCurrentTCBs[ xCoreID ]->xPreemptionDisable == pdFALSE )
#endif
{
xLowestPriorityToPreempt = xCurrentCoreTaskPriority;
xLowestPriorityCore = xCoreID;
}
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#if ( configRUN_MULTIPLE_PRIORITIES == 0 )
{
/* Yield all currently running non-idle tasks with a priority lower than
* the task that needs to run. */
if( ( xCurrentCoreTaskPriority > ( ( BaseType_t ) tskIDLE_PRIORITY - 1 ) ) &&
( xCurrentCoreTaskPriority < ( BaseType_t ) pxTCB->uxPriority ) )
{
prvYieldCore( xCoreID );
xYieldCount++;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* #if ( configRUN_MULTIPLE_PRIORITIES == 0 ) */
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#if ( configRUN_MULTIPLE_PRIORITIES == 0 )
if( ( xYieldCount == 0 ) && ( xLowestPriorityCore >= 0 ) )
#else /* #if ( configRUN_MULTIPLE_PRIORITIES == 0 ) */
if( xLowestPriorityCore >= 0 )
#endif /* #if ( configRUN_MULTIPLE_PRIORITIES == 0 ) */
{
prvYieldCore( xLowestPriorityCore );
}
#if ( configRUN_MULTIPLE_PRIORITIES == 0 )
/* Verify that the calling core always yields to higher priority tasks. */
if( ( ( pxCurrentTCBs[ portGET_CORE_ID() ]->uxTaskAttributes & taskATTRIBUTE_IS_IDLE ) == 0 ) &&
( pxTCB->uxPriority > pxCurrentTCBs[ portGET_CORE_ID() ]->uxPriority ) )
{
configASSERT( ( xYieldPendings[ portGET_CORE_ID() ] == pdTRUE ) ||
( taskTASK_IS_RUNNING( pxCurrentTCBs[ portGET_CORE_ID() ] ) == pdFALSE ) );
}
#endif
}
}
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
/*-----------------------------------------------------------*/
#if ( configNUMBER_OF_CORES > 1 )
static void prvSelectHighestPriorityTask( BaseType_t xCoreID )
{
UBaseType_t uxCurrentPriority = uxTopReadyPriority;
BaseType_t xTaskScheduled = pdFALSE;
BaseType_t xDecrementTopPriority = pdTRUE;
#if ( configUSE_CORE_AFFINITY == 1 )
const TCB_t * pxPreviousTCB = NULL;
#endif
#if ( configRUN_MULTIPLE_PRIORITIES == 0 )
BaseType_t xPriorityDropped = pdFALSE;
#endif
/* This function should be called when scheduler is running. */
configASSERT( xSchedulerRunning == pdTRUE );
/* A new task is created and a running task with the same priority yields
* itself to run the new task. When a running task yields itself, it is still
* in the ready list. This running task will be selected before the new task
* since the new task is always added to the end of the ready list.
* The other problem is that the running task still in the same position of
* the ready list when it yields itself. It is possible that it will be selected
* earlier then other tasks which waits longer than this task.
*
* To fix these problems, the running task should be put to the end of the
* ready list before searching for the ready task in the ready list. */
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxCurrentTCBs[ xCoreID ]->uxPriority ] ),
&pxCurrentTCBs[ xCoreID ]->xStateListItem ) == pdTRUE )
{
( void ) uxListRemove( &pxCurrentTCBs[ xCoreID ]->xStateListItem );
vListInsertEnd( &( pxReadyTasksLists[ pxCurrentTCBs[ xCoreID ]->uxPriority ] ),
&pxCurrentTCBs[ xCoreID ]->xStateListItem );
}
while( xTaskScheduled == pdFALSE )
{
#if ( configRUN_MULTIPLE_PRIORITIES == 0 )
{
if( uxCurrentPriority < uxTopReadyPriority )
{
/* We can't schedule any tasks, other than idle, that have a
* priority lower than the priority of a task currently running
* on another core. */
uxCurrentPriority = tskIDLE_PRIORITY;
}
}
#endif
if( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxCurrentPriority ] ) ) == pdFALSE )
{
const List_t * const pxReadyList = &( pxReadyTasksLists[ uxCurrentPriority ] );
const ListItem_t * pxEndMarker = listGET_END_MARKER( pxReadyList );
ListItem_t * pxIterator;
/* The ready task list for uxCurrentPriority is not empty, so uxTopReadyPriority
* must not be decremented any further. */
xDecrementTopPriority = pdFALSE;
for( pxIterator = listGET_HEAD_ENTRY( pxReadyList ); pxIterator != pxEndMarker; pxIterator = listGET_NEXT( pxIterator ) )
{
TCB_t * pxTCB = ( TCB_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
#if ( configRUN_MULTIPLE_PRIORITIES == 0 )
{
/* When falling back to the idle priority because only one priority
* level is allowed to run at a time, we should ONLY schedule the true
* idle tasks, not user tasks at the idle priority. */
if( uxCurrentPriority < uxTopReadyPriority )
{
if( ( pxTCB->uxTaskAttributes & taskATTRIBUTE_IS_IDLE ) == 0 )
{
continue;
}
}
}
#endif /* #if ( configRUN_MULTIPLE_PRIORITIES == 0 ) */
if( pxTCB->xTaskRunState == taskTASK_NOT_RUNNING )
{
#if ( configUSE_CORE_AFFINITY == 1 )
if( ( pxTCB->uxCoreAffinityMask & ( ( UBaseType_t ) 1U << ( UBaseType_t ) xCoreID ) ) != 0U )
#endif
{
/* If the task is not being executed by any core swap it in. */
pxCurrentTCBs[ xCoreID ]->xTaskRunState = taskTASK_NOT_RUNNING;
#if ( configUSE_CORE_AFFINITY == 1 )
pxPreviousTCB = pxCurrentTCBs[ xCoreID ];
#endif
pxTCB->xTaskRunState = ( TaskRunning_t ) xCoreID;
pxCurrentTCBs[ xCoreID ] = pxTCB;
xTaskScheduled = pdTRUE;
}
}
else if( pxTCB == pxCurrentTCBs[ xCoreID ] )
{
configASSERT( ( pxTCB->xTaskRunState == xCoreID ) || ( pxTCB->xTaskRunState == taskTASK_YIELDING ) );
#if ( configUSE_CORE_AFFINITY == 1 )
if( ( pxTCB->uxCoreAffinityMask & ( ( UBaseType_t ) 1U << ( UBaseType_t ) xCoreID ) ) != 0U )
#endif