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

cnblogs 2024-09-05 08:15:00 阅读 53

4、task.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 [Misaligned access] */

56 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-113 */

57 /* coverity[misra_c_2012_rule_11_3_violation] */

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 }

xTaskCreate

4.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 to the 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 }

prvInitialiseNewTask

4.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 }

prvAddNewTaskToReadyList

4.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

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

下次开始任务删除相关的接口解析了。


上一篇: Linux 进程概念

下一篇: ubuntu 查看联网配置

本文标签

task    freeRTOS源码解析    freeRTOS   


声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。