烯八 发表于 2025-6-8 13:00:28

freeRTOS源码解析4--tasks.c 2

4、tasks.c解析

时隔两年,还是决定继续把这个系统解析完成,有始有终。不过这次源码又从官网上下载了最新的,可能和我以前看的略有区别,但应该基本不影响理解。
接下来正式开始。

[*]4.1.3 新增或是遗漏的两个宏
1   /* Returns pdTRUE if the task is actively running and not scheduled to yield. */
2   /* 如果任务正在运行并且没有被调度,则返回 TRUE。 */
3   #define taskTASK_IS_RUNNING( pxTCB )                        ( ( ( pxTCB ) == pxCurrentTCB ) ? ( pdTRUE ) : ( pdFALSE ) )
4   #define taskTASK_IS_RUNNING_OR_SCHEDULED_TO_YIELD( pxTCB )    ( ( ( pxTCB ) == pxCurrentTCB ) ? ( pdTRUE ) : ( pdFALSE ) )4.2 接口解析

 4.2.1 静态创建任务--xTaskCreateStatic

 这个接口创建的任务,根据“FreeRTOS.h”文件的描述,当任务删除时,任务的栈和TCB都不能被释放。
1 /* 根据FreeRTOSConfig.h配置的不同结构体会有差异, 这是我的结果 */
2 struct xSTATIC_LIST_ITEM
3 {
4   TickType_t xDummy2;
5   void * pvDummy3[ 4 ];
6 };
7 typedef struct xSTATIC_LIST_ITEM StaticListItem_t;
8
9 /* 根据FreeRTOSConfig.h配置的不同结构体会有差异, 这是我的结果。
10* configMAX_TASK_NAME_LEN = 16
11* configTASK_NOTIFICATION_ARRAY_ENTRIES = 1 */
12 typedef struct xSTATIC_TCB {
13   void * pxDummy1;
14   StaticListItem_t xDummy3[ 2 ];
15   UBaseType_t uxDummy5;
16   void * pxDummy6;
17   uint8_t ucDummy7[ configMAX_TASK_NAME_LEN ];
18   UBaseType_t uxDummy12[ 2 ];
19   uint32_t ulDummy18[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
20   uint8_t ucDummy19[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
21   uint8_t uxDummy20;
22 } StaticTask_t;
23
24
25 static TCB_t * prvCreateStaticTask( TaskFunction_t pxTaskCode,
26                                       const char * const pcName,
27                                       const configSTACK_DEPTH_TYPE uxStackDepth,
28                                       void * const pvParameters,
29                                       UBaseType_t uxPriority,
30                                       StackType_t * const puxStackBuffer,
31                                       StaticTask_t * const pxTaskBuffer,
32                                       TaskHandle_t * const pxCreatedTask )
33   {
34         TCB_t * pxNewTCB;
35
36         configASSERT( puxStackBuffer != NULL );
37         configASSERT( pxTaskBuffer != NULL );
38
39         #if ( configASSERT_DEFINED == 1 )
40         {
41             /* Sanity check that the size of the structure used to declare a
42            * variable of type StaticTask_t equals the size of the real task
43            * structure. */
44            /* 确保静态的TCB和TCB_t大小是一致的,一般是一致的 */
45             volatile size_t xSize = sizeof( StaticTask_t );
46             configASSERT( xSize == sizeof( TCB_t ) );
47             ( void ) xSize; /* Prevent unused variable warning when configASSERT() is not used. */
48         }
49         #endif /* configASSERT_DEFINED */
50
51         if( ( pxTaskBuffer != NULL ) && ( puxStackBuffer != NULL ) )
52         {
53             /* The memory used for the task's TCB and stack are passed into this
54            * function - use them. */
55             /* MISRA Ref 11.3.1 */
56             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-113 */
57             /* coverity */
58             pxNewTCB = ( TCB_t * ) pxTaskBuffer;
59             ( void ) memset( ( void * ) pxNewTCB, 0x00, sizeof( TCB_t ) );
60             pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer;
61
62             #if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
63             {
64               /* Tasks can be created statically or dynamically, so note this
65                  * task was created statically in case the task is later deleted. */
66                  /* 标记任务是静态创建的 */
67               pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_AND_TCB;
68             }
69             #endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */
70
71             /* 初始化任务参数,后面会讲到 */
72             prvInitialiseNewTask( pxTaskCode, pcName, uxStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL );
73         }
74         else
75         {
76             pxNewTCB = NULL;
77         }
78
79         return pxNewTCB;
80   }
81 /*-----------------------------------------------------------*/
82
83   /* pxTaskCode:任务入口;
84      * pcName:任务名称;
85      * uxStackDepth:任务栈深;
86      * pvParameters:任务形参;
87      * uxPriority:任务优先级;
88      * puxStackBuffer:任务栈,用户提供内存;
89      * pxTaskBuffer:任务TCB数据存放,用户提供内存。 */
90   TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,
91                                     const char * const pcName,
92                                     const configSTACK_DEPTH_TYPE uxStackDepth,
93                                     void * const pvParameters,
94                                     UBaseType_t uxPriority,
95                                     StackType_t * const puxStackBuffer,
96                                     StaticTask_t * const pxTaskBuffer )
97   {
98         TaskHandle_t xReturn = NULL;
99         TCB_t * pxNewTCB;
100
101         /* 设置任务,初始化参数 */
102         pxNewTCB = prvCreateStaticTask( pxTaskCode, pcName, uxStackDepth, pvParameters, uxPriority, puxStackBuffer, pxTaskBuffer, &xReturn );
103
104         if( pxNewTCB != NULL )
105         {
106             prvAddNewTaskToReadyList( pxNewTCB );   /* 加入到就绪列表中,后面会讲到 */
107         }
108         else
109         {
110             mtCOVERAGE_TEST_MARKER();
111         }
112
113         return xReturn;
114   }xTaskCreateStatic 4.2.2 动态创建任务--xTaskCreate

1 static TCB_t * prvCreateTask( TaskFunction_t pxTaskCode,
2                                    const char * const pcName,
3                                    const configSTACK_DEPTH_TYPE uxStackDepth,
4                                    void * const pvParameters,
5                                    UBaseType_t uxPriority,
6                                    TaskHandle_t * const pxCreatedTask )
7 {
8   TCB_t * pxNewTCB;
9
10
11   StackType_t * pxStack;
12
13   /* 在堆栈管理的文章中有介绍过,申请内存
14      * #define pvPortMallocStack    pvPortMalloc
15      * #define vPortFreeStack       vPortFree */
16   pxStack = pvPortMallocStack( ( ( ( size_t ) uxStackDepth ) * sizeof( StackType_t ) ) );
17
18   if( pxStack != NULL )
19   {
20         /* Allocate space for the TCB. */
21         pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
22
23         if( pxNewTCB != NULL )
24         {
25             ( void ) memset( ( void * ) pxNewTCB, 0x00, sizeof( TCB_t ) );
26
27             /* Store the stack location in the TCB. */
28             pxNewTCB->pxStack = pxStack;
29         }
30         else
31         {
32             /* The stack cannot be used as the TCB was not created.Free
33            * it again. */
34             vPortFreeStack( pxStack );
35         }
36   }
37   else
38   {
39         pxNewTCB = NULL;
40   }
41
42   if( pxNewTCB != NULL )
43   {
44         #if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
45         {
46             /* Tasks can be created statically or dynamically, so note this
47            * task was created dynamically in case it is later deleted. */
48             /* 标记任务是动态创建的 */
49             pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB;
50         }
51         #endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */
52
53         /* 初始化任务参数,后面会讲到 */
54         prvInitialiseNewTask( pxTaskCode, pcName, uxStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL );
55   }
56
57   return pxNewTCB;
58 }
59 /*-----------------------------------------------------------*/
60
61 /* 这里的形参就不介绍了,应该都比较清楚 */
62 BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
63                           const char * const pcName,
64                           const configSTACK_DEPTH_TYPE uxStackDepth,
65                           void * const pvParameters,
66                           UBaseType_t uxPriority,
67                           TaskHandle_t * const pxCreatedTask )
68 {
69   TCB_t * pxNewTCB;
70   BaseType_t xReturn;
71
72   /* 设置任务,初始化参数 */
73   pxNewTCB = prvCreateTask( pxTaskCode, pcName, uxStackDepth, pvParameters, uxPriority, pxCreatedTask );
74
75   if( pxNewTCB != NULL )
76   {
77         prvAddNewTaskToReadyList( pxNewTCB );   /* 加入到就绪列表中,后面会讲到 */
78         xReturn = pdPASS;
79   }
80   else
81   {
82         xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
83   }
84
85   return xReturn;
86 }xTaskCreate4.2.3 初始化任务--prvInitialiseNewTask

这个函数比较复杂,是在创建任务的时候调用的,基本逻辑比较清晰,去除了一些多核、MPU的代码就简化很多。有一些列表的值也许暂时不清楚为何如此设置,但到使用时应该就清楚这个初始值的含义了。
1 static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
2                                 const char * const pcName,
3                                 const configSTACK_DEPTH_TYPE uxStackDepth,
4                                 void * const pvParameters,
5                                 UBaseType_t uxPriority,
6                                 TaskHandle_t * const pxCreatedTask,
7                                 TCB_t * pxNewTCB,
8                                 const MemoryRegion_t * const xRegions )
9 {
10   StackType_t * pxTopOfStack;
11   UBaseType_t x;
12
13   /* Calculate the top of stack address.This depends on whether the stack
14      * grows from high memory to low (as per the 80x86) or vice versa.
15      * portSTACK_GROWTH is used to make the result positive or negative as required
16      * by the port. */
17   #if ( portSTACK_GROWTH < 0 )
18   {
19         /* 往前走4个字节,因为这个栈是先存值,再移动指针,所以需要确保栈顶指针指向栈空间的最后一个有效位置 */
20         pxTopOfStack = &( pxNewTCB->pxStack[ uxStackDepth - ( configSTACK_DEPTH_TYPE ) 1 ] );
21         /* 栈需要对齐 */
22         pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
23
24         /* Check the alignment of the calculated top of stack is correct. */
25         configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0U ) );
26   }
27   #endif
28
29   /* Store the task name in the TCB. */
30   if( pcName != NULL )
31   {
32         for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
33         {
34             pxNewTCB->pcTaskName[ x ] = pcName[ x ];
35
36             /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than
37            * configMAX_TASK_NAME_LEN characters just in case the memory after the
38            * string is not accessible (extremely unlikely). */
39             if( pcName[ x ] == ( char ) 0x00 )
40             {
41               break;
42             }
43             else
44             {
45               mtCOVERAGE_TEST_MARKER();
46             }
47         }
48
49         /* Ensure the name string is terminated in the case that the string length
50          * was greater or equal to configMAX_TASK_NAME_LEN. */
51         pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1U ] = '\0';
52   }
53   else
54   {
55         mtCOVERAGE_TEST_MARKER();
56   }
57
58   /* This is used as an array index so must ensure it's not too large. */
59   configASSERT( uxPriority < configMAX_PRIORITIES );
60
61   if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
62   {
63         uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
64   }
65   else
66   {
67         mtCOVERAGE_TEST_MARKER();
68   }
69
70   pxNewTCB->uxPriority = uxPriority;
71 #if ( configUSE_MUTEXES == 1 )
72   {
73         pxNewTCB->uxBasePriority = uxPriority;    /* 用于优先级继承机制 */
74   }
75 #endif /* configUSE_MUTEXES */
76
77   vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
78   vListInitialiseItem( &( pxNewTCB->xEventListItem ) );
79
80   /* Set the pxNewTCB as a link back from the ListItem_t.This is so we can get
81      * back tothe containing TCB from a generic item in a list. */
82   /* 设置ListItem_t的持有者,这样可以从Item处获取到TCB */
83   listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );
84
85   /* Event lists are always in priority order. */
86   /* 事件列表总是按优先级排序,具体的可以等解析事件的时候再会过来看为什么这么设置 */
87   listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority );
88   listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB );
89
90   /* Initialize the TCB stack to look as if the task was already running,
91      * but had been interrupted by the scheduler.The return address is set
92      * to the start of the task function. Once the stack has been initialised
93      * the top of stack variable is updated. */
94   #if ( portUSING_MPU_WRAPPERS == 0 )
95   {
96         /* If the port has capability to detect stack overflow,
97          * pass the stack end address to the stack initialization
98          * function as well. */
99         #if ( portHAS_STACK_OVERFLOW_CHECKING == 0 )
100         {
101             /* 初始化栈,伪造一个现场 */
102             pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
103         }
104         #endif /* portHAS_STACK_OVERFLOW_CHECKING */
105   }
106   #endif /* portUSING_MPU_WRAPPERS */
107
108   if( pxCreatedTask != NULL )
109   {
110         /* Pass the handle out in an anonymous way.The handle can be used to
111          * change the created task's priority, delete the created task, etc.*/
112         *pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
113   }
114   else
115   {
116         mtCOVERAGE_TEST_MARKER();
117   }
118 }prvInitialiseNewTask4.2.4 加入到就绪列表--prvAddNewTaskToReadyList

1 static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB )
2 {
3   /* Ensure interrupts don't access the task lists while the lists are being
4      * updated. */
5   /* 会操作任务列表,所以需要进入临界区,防止有系统中断打断 */
6   taskENTER_CRITICAL();
7   {
8         uxCurrentNumberOfTasks = ( UBaseType_t ) ( uxCurrentNumberOfTasks + 1U );
9
10         if( pxCurrentTCB == NULL )
11         {
12             /* There are no other tasks, or all the other tasks are in
13            * the suspended state - make this the current task. */
14             pxCurrentTCB = pxNewTCB;
15
16             if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )
17             {
18               /* This is the first task to be created so do the preliminary
19                  * initialisation required.We will not recover if this call
20                  * fails, but we will report the failure. */
21               /* 第一个任务被创建,需要先初始化任务列表,具体流程后面会解析 */
22               prvInitialiseTaskLists();
23             }
24             else
25             {
26               mtCOVERAGE_TEST_MARKER();
27             }
28         }
29         else
30         {
31             /* If the scheduler is not already running, make this task the
32            * current task if it is the highest priority task to be created
33            * so far. */
34             /*
35             如果调度器未被运行且这是至今为止创建的最高优先级的任务,则把此任务作为当前任务 */
36             if( xSchedulerRunning == pdFALSE )
37             {
38               if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority )
39               {
40                     pxCurrentTCB = pxNewTCB;
41               }
42               else
43               {
44                     mtCOVERAGE_TEST_MARKER();
45               }
46             }
47             else
48             {
49               mtCOVERAGE_TEST_MARKER();
50             }
51         }
52
53         uxTaskNumber++;
54
55         prvAddTaskToReadyList( pxNewTCB );    // 真正的操作列表,放进去
56
57         portSETUP_TCB( pxNewTCB );
58   }
59   taskEXIT_CRITICAL();
60
61   if( xSchedulerRunning != pdFALSE )
62   {
63         /* If the created task is of a higher priority than the current task
64          * then it should run now. */
65         /* 如果创建的任务优先级比当前任务高,则yield */
66         taskYIELD_ANY_CORE_IF_USING_PREEMPTION( pxNewTCB );
67   }
68   else
69   {
70         mtCOVERAGE_TEST_MARKER();
71   }
72 }prvAddNewTaskToReadyList4.2.5 初始化任务列表--prvInitialiseTaskLists

1 static void prvInitialiseTaskLists( void )
2 {
3   UBaseType_t uxPriority;
4
5   /* 初始化所有的任务列表,包括就绪、阻塞、停止列表等 */
6   for( uxPriority = ( UBaseType_t ) 0U; uxPriority < ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ )
7   {
8         vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) );
9   }
10
11   vListInitialise( &xDelayedTaskList1 );
12   vListInitialise( &xDelayedTaskList2 );
13   vListInitialise( &xPendingReadyList );
14
15   #if ( INCLUDE_vTaskDelete == 1 )
16   {
17         vListInitialise( &xTasksWaitingTermination );
18   }
19   #endif /* INCLUDE_vTaskDelete */
20
21   #if ( INCLUDE_vTaskSuspend == 1 )
22   {
23         vListInitialise( &xSuspendedTaskList );
24   }
25   #endif /* INCLUDE_vTaskSuspend */
26
27   /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
28      * using list2. */
29   pxDelayedTaskList = &xDelayedTaskList1;
30   pxOverflowDelayedTaskList = &xDelayedTaskList2;
31 }prvInitialiseTaskLists 
  补充一下流程图:

 
 
到这里,创建任务所涉及到的接口都已解析过了,可能还遗留有一些小问题,但我相信在后面的解析过程中,这些问题都会有所解答。
下次开始任务删除相关的接口解析了。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: freeRTOS源码解析4--tasks.c 2