freeRTOS源码解析4--tasks.c 4
cnblogs 2024-09-11 08:15:00 阅读 54
4.2.9 周期任务用的延迟--xTaskDelayUntil
接口:BaseType_t xTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement )
形参1:pxPreviousWakeTime,上一次唤醒时间,第一次需要用接口xTaskGetTickCount()获取;
形参2:xTimeIncrement,想要延迟的时间。
返回值:用于判读任务是否确实需要delay。
1 BaseType_t xTaskDelayUntil( TickType_t * const pxPreviousWakeTime,
2 const TickType_t xTimeIncrement )
3 {
4 TickType_t xTimeToWake;
5 BaseType_t xAlreadyYielded, xShouldDelay = pdFALSE;
6
7 configASSERT( pxPreviousWakeTime );
8 configASSERT( ( xTimeIncrement > 0U ) );
9
10 vTaskSuspendAll();
11 {
12 /* Minor optimisation. The tick count cannot change in this
13 * block. */
14 const TickType_t xConstTickCount = xTickCount;
15
16 configASSERT( uxSchedulerSuspended == 1U );
17
18 /* Generate the tick time at which the task wants to wake. */
19 /* 计算任务下次唤醒的时间 */
20 xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
21
22 if( xConstTickCount < *pxPreviousWakeTime )
23 {
24 /* The tick count has overflowed since this function was
25 * lasted called. In this case the only time we should ever
26 * actually delay is if the wake time has also overflowed,
27 * and the wake time is greater than the tick time. When this
28 * is the case it is as if neither time had overflowed. */
29 /* tick值已经溢出了, 只有xTimeToWake也溢出并大于xConstTickCount
30 * 时, 才需要延迟 */
31 /* 假设tick是8位的, 当前值为0x5(从FF加到5), pxPreviousWakeTime为0xFD,
32 * 当xTimeIncrement为1时, xTimeToWake未溢出, 当xTimeIncrement为0x15时,
33 * xTimeToWake溢出。 显然当xTimeIncrement为1时, xTimeToWake比
34 * pxPreviousWakeTime和xConstTickCount都大, 但不需要延迟, 因为tick已过,
35 * 当xTimeIncrement为0x15时, xTimeToWake比pxPreviousWakeTime小但比xConstTickCount
36 * 大, tick要等到0x12才到延迟时间, 所以需要进行延迟. */
37 if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xConstTickCount ) )
38 {
39 xShouldDelay = pdTRUE;
40 }
41 else
42 {
43 mtCOVERAGE_TEST_MARKER();
44 }
45 }
46 else
47 {
48 /* The tick time has not overflowed. In this case we will
49 * delay if either the wake time has overflowed, and/or the
50 * tick time is less than the wake time. */
51 /* tick没有溢出, 那么xTimeToWake溢出或比xConstTickCount小,
52 * 必然是需要延迟的. */
53 if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xConstTickCount ) )
54 {
55 xShouldDelay = pdTRUE;
56 }
57 else
58 {
59 mtCOVERAGE_TEST_MARKER();
60 }
61 }
62
63 /* Update the wake time ready for the next call. */
64 *pxPreviousWakeTime = xTimeToWake;
65
66 if( xShouldDelay != pdFALSE )
67 {
68 /* prvAddCurrentTaskToDelayedList() needs the block time, not
69 * the time to wake, so subtract the current tick count. */
70 /* 延迟列表记录的是阻塞时间而不是唤醒时间, 所以需要减去tick. */
71 prvAddCurrentTaskToDelayedList( xTimeToWake - xConstTickCount, pdFALSE );
72 }
73 else
74 {
75 mtCOVERAGE_TEST_MARKER();
76 }
77 }
78 xAlreadyYielded = xTaskResumeAll();
79
80 /* Force a reschedule if xTaskResumeAll has not already done so, we may
81 * have put ourselves to sleep. */
82 if( xAlreadyYielded == pdFALSE )
83 {
84 taskYIELD_WITHIN_API();
85 }
86 else
87 {
88 mtCOVERAGE_TEST_MARKER();
89 }
90
91 return xShouldDelay;
92 }
xTaskDelayUntil
4.2.10 成对的信息获取接口,一般的和带有FromISR后缀的
这类接口比较简单,主要用于获取TCB中的某些参数,这里挑选任务优先级获取接口为例,重点在于带有FromISR的接口。一般的接口很简单,这里就直接放出来即可。
1 UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask )
2 {
3 TCB_t const * pxTCB;
4 UBaseType_t uxReturn;
5
6 taskENTER_CRITICAL();
7 {
8 /* If null is passed in here then it is the priority of the task
9 * that called uxTaskPriorityGet() that is being queried. */
10 pxTCB = prvGetTCBFromHandle( xTask );
11 uxReturn = pxTCB->uxPriority;
12 }
13 taskEXIT_CRITICAL();
14
15 return uxReturn;
16 }
1 UBaseType_t uxTaskPriorityGetFromISR( const TaskHandle_t xTask )
2 {
3 TCB_t const * pxTCB;
4 UBaseType_t uxReturn;
5 UBaseType_t uxSavedInterruptStatus;
6
7 /* RTOS ports that support interrupt nesting have the concept of a
8 * maximum system call (or maximum API call) interrupt priority.
9 * Interrupts that are above the maximum system call priority are keep
10 * permanently enabled, even when the RTOS kernel is in a critical section,
11 * but cannot make any calls to FreeRTOS API functions. If configASSERT()
12 * is defined in FreeRTOSConfig.h then
13 * portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
14 * failure if a FreeRTOS API function is called from an interrupt that has
15 * been assigned a priority above the configured maximum system call
16 * priority. Only FreeRTOS functions that end in FromISR can be called
17 * from interrupts that have been assigned a priority at or (logically)
18 * below the maximum system call interrupt priority. FreeRTOS maintains a
19 * separate interrupt safe API to ensure interrupt entry is as fast and as
20 * simple as possible. More information (albeit Cortex-M specific) is
21 * provided on the following link:
22 * https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
23 /* 检查调用带有FromISR后缀的中断优先级是否高于
24 * configMAX_SYSCALL_INTERRUPT_PRIORITY, 是的话会进入assert */
25 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
26
27 /* MISRA Ref 4.7.1 [Return value shall be checked] */
28 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */
29 /* coverity[misra_c_2012_directive_4_7_violation] */
30 /* 获取当前中断屏蔽优先级, 并设置中断屏蔽优先级为configMAX_SYSCALL_INTERRUPT_PRIORITY
31 * 相当于进入了临界区并返回了当前中断屏蔽优先级 */
32 uxSavedInterruptStatus = ( UBaseType_t ) taskENTER_CRITICAL_FROM_ISR();
33 {
34 /* If null is passed in here then it is the priority of the calling
35 * task that is being queried. */
36 pxTCB = prvGetTCBFromHandle( xTask );
37 uxReturn = pxTCB->uxPriority;
38 }
39 /* 将保存的中断屏蔽优先级设置回去, 相当于退出临界区 */
40 taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
41
42 return uxReturn;
43 }
4.2.11 设置任务优先级--vTaskPrioritySet
接口虽然较长,但注释较多,且逻辑较为简单,直接看代码里的注释即可。
1 void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority )
2 {
3 TCB_t * pxTCB;
4 UBaseType_t uxCurrentBasePriority, uxPriorityUsedOnEntry;
5 BaseType_t xYieldRequired = pdFALSE;
6
7 configASSERT( uxNewPriority < configMAX_PRIORITIES );
8
9 /* Ensure the new priority is valid. */
10 if( uxNewPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
11 {
12 uxNewPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
13 }
14 else
15 {
16 mtCOVERAGE_TEST_MARKER();
17 }
18
19 taskENTER_CRITICAL();
20 {
21 /* If null is passed in here then it is the priority of the calling
22 * task that is being changed. */
23 pxTCB = prvGetTCBFromHandle( xTask );
24
25 #if ( configUSE_MUTEXES == 1 )
26 {
27 uxCurrentBasePriority = pxTCB->uxBasePriority;
28 }
29 #else
30 {
31 uxCurrentBasePriority = pxTCB->uxPriority;
32 }
33 #endif
34
35 if( uxCurrentBasePriority != uxNewPriority )
36 {
37 /* The priority change may have readied a task of higher
38 * priority than a running task. */
39 if( uxNewPriority > uxCurrentBasePriority )
40 {
41 /* 提升优先级 */
42 #if ( configNUMBER_OF_CORES == 1 )
43 {
44 if( pxTCB != pxCurrentTCB )
45 {
46 /* The priority of a task other than the currently
47 * running task is being raised. Is the priority being
48 * raised above that of the running task? */
49 /* 设置的优先级比当前运行的任务高, 需要yield */
50 if( uxNewPriority > pxCurrentTCB->uxPriority )
51 {
52 xYieldRequired = pdTRUE;
53 }
54 else
55 {
56 mtCOVERAGE_TEST_MARKER();
57 }
58 }
59 else
60 {
61 /* The priority of the running task is being raised,
62 * but the running task must already be the highest
63 * priority task able to run so no yield is required. */
64 }
65 }
66 #endif /* #if ( configNUMBER_OF_CORES == 1 ) */
67 }
68 else if( taskTASK_IS_RUNNING( pxTCB ) == pdTRUE )
69 {
70 /* Setting the priority of a running task down means
71 * there may now be another task of higher priority that
72 * is ready to execute. */
73 /* 降低当前运行任务的优先级, 则更高优先级的就绪任务需要抢占 */
74 #if ( configUSE_TASK_PREEMPTION_DISABLE == 1 )
75 if( pxTCB->xPreemptionDisable == pdFALSE )
76 #endif
77 {
78 xYieldRequired = pdTRUE;
79 }
80 }
81 else
82 {
83 /* Setting the priority of any other task down does not
84 * require a yield as the running task must be above the
85 * new priority of the task being modified. */
86 }
87
88 /* Remember the ready list the task might be referenced from
89 * before its uxPriority member is changed so the
90 * taskRESET_READY_PRIORITY() macro can function correctly. */
91 /* 获取任务当前的优先级, 有可能是继承来的优先级 */
92 uxPriorityUsedOnEntry = pxTCB->uxPriority;
93
94 #if ( configUSE_MUTEXES == 1 )
95 {
96 /* Only change the priority being used if the task is not
97 * currently using an inherited priority or the new priority
98 * is bigger than the inherited priority. */
99 /* 只有非继承来的优先级, 或提升优先级才可以直接修改pxTCB->uxPriority */
100 if( ( pxTCB->uxBasePriority == pxTCB->uxPriority ) || ( uxNewPriority > pxTCB->uxPriority ) )
101 {
102 pxTCB->uxPriority = uxNewPriority;
103 }
104 else
105 {
106 mtCOVERAGE_TEST_MARKER();
107 }
108
109 /* The base priority gets set whatever. */
110 pxTCB->uxBasePriority = uxNewPriority;
111 }
112 #else /* if ( configUSE_MUTEXES == 1 ) */
113 {
114 pxTCB->uxPriority = uxNewPriority;
115 }
116 #endif /* if ( configUSE_MUTEXES == 1 ) */
117
118 /* Only reset the event list item value if the value is not
119 * being used for anything else. */
120 /* xEventListItem的值未被使用, 才允许更新这个值 */
121 if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == ( ( TickType_t ) 0U ) )
122 {
123 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxNewPriority ) );
124 }
125 else
126 {
127 mtCOVERAGE_TEST_MARKER();
128 }
129
130 /* If the task is in the blocked or suspended list we need do
131 * nothing more than change its priority variable. However, if
132 * the task is in a ready list it needs to be removed and placed
133 * in the list appropriate to its new priority. */
134 /* 如果任务处于就绪列表, 则需要将其放到修改后的优先级就绪列表 */
135 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
136 {
137 /* The task is currently in its ready list - remove before
138 * adding it to its new ready list. As we are in a critical
139 * section we can do this even if the scheduler is suspended. */
140 if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
141 {
142 /* It is known that the task is in its ready list so
143 * there is no need to check again and the port level
144 * reset macro can be called directly. */
145 portRESET_READY_PRIORITY( uxPriorityUsedOnEntry, uxTopReadyPriority );
146 }
147 else
148 {
149 mtCOVERAGE_TEST_MARKER();
150 }
151
152 prvAddTaskToReadyList( pxTCB );
153 }
154 else
155 {
156 #if ( configNUMBER_OF_CORES == 1 )
157 {
158 mtCOVERAGE_TEST_MARKER();
159 }
160 #endif
161 }
162
163 if( xYieldRequired != pdFALSE )
164 {
165 /* The running task priority is set down. Request the task to yield. */
166 /* 开始yield, 但是在退出临界区后才会进入sv中断? */
167 taskYIELD_TASK_CORE_IF_USING_PREEMPTION( pxTCB );
168 }
169 else
170 {
171 mtCOVERAGE_TEST_MARKER();
172 }
173
174 /* Remove compiler warning about unused variables when the port
175 * optimised task selection is not being used. */
176 ( void ) uxPriorityUsedOnEntry;
177 }
178 }
179 taskEXIT_CRITICAL();
180 }
vTaskPrioritySet
4.2.12 挂起任务--vTaskSuspend
还是直接看代码注释,解释得比较清楚了,接口功能可以顾名思义,逻辑也还好不复杂。
1 void vTaskSuspend( TaskHandle_t xTaskToSuspend )
2 {
3 TCB_t * pxTCB;
4
5 taskENTER_CRITICAL();
6 {
7 /* If null is passed in here then it is the running task that is
8 * being suspended. */
9 pxTCB = prvGetTCBFromHandle( xTaskToSuspend );
10
11 /* Remove task from the ready/delayed list and place in the
12 * suspended list. */
13 if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
14 {
15 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
16 }
17 else
18 {
19 mtCOVERAGE_TEST_MARKER();
20 }
21
22 /* Is the task waiting on an event also? */
23 /* 任务挂起, 任务就不管是否在等待事件 */
24 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
25 {
26 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
27 }
28 else
29 {
30 mtCOVERAGE_TEST_MARKER();
31 }
32
33 vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
34
35 /* 如果在等待通知, 也直接退出等待 */
36 #if ( configUSE_TASK_NOTIFICATIONS == 1 )
37 {
38 BaseType_t x;
39
40 for( x = ( BaseType_t ) 0; x < ( BaseType_t ) configTASK_NOTIFICATION_ARRAY_ENTRIES; x++ )
41 {
42 if( pxTCB->ucNotifyState[ x ] == taskWAITING_NOTIFICATION )
43 {
44 /* The task was blocked to wait for a notification, but is
45 * now suspended, so no notification was received. */
46 pxTCB->ucNotifyState[ x ] = taskNOT_WAITING_NOTIFICATION;
47 }
48 }
49 }
50 #endif /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */
51 }
52 taskEXIT_CRITICAL();
53
54 #if ( configNUMBER_OF_CORES == 1 )
55 {
56 UBaseType_t uxCurrentListLength;
57
58 if( xSchedulerRunning != pdFALSE )
59 {
60 /* Reset the next expected unblock time in case it referred to the
61 * task that is now in the Suspended state. */
62 /* 如果下个解除阻塞的时间对应的任务正好是挂起的任务,
63 * 无论如何重置一下下个解除阻塞的时间 */
64 taskENTER_CRITICAL();
65 {
66 prvResetNextTaskUnblockTime();
67 }
68 taskEXIT_CRITICAL();
69 }
70 else
71 {
72 mtCOVERAGE_TEST_MARKER();
73 }
74
75 if( pxTCB == pxCurrentTCB )
76 {
77 if( xSchedulerRunning != pdFALSE )
78 {
79 /* The current task has just been suspended. */
80 /* 当前运行的任务挂起, 需要yield */
81 configASSERT( uxSchedulerSuspended == 0 );
82 portYIELD_WITHIN_API();
83 }
84 else
85 {
86 /* The scheduler is not running, but the task that was pointed
87 * to by pxCurrentTCB has just been suspended and pxCurrentTCB
88 * must be adjusted to point to a different task. */
89
90 /* Use a temp variable as a distinct sequence point for reading
91 * volatile variables prior to a comparison to ensure compliance
92 * with MISRA C 2012 Rule 13.2. */
93 uxCurrentListLength = listCURRENT_LIST_LENGTH( &xSuspendedTaskList );
94
95 if( uxCurrentListLength == uxCurrentNumberOfTasks )
96 {
97 /* No other tasks are ready, so set pxCurrentTCB back to
98 * NULL so when the next task is created pxCurrentTCB will
99 * be set to point to it no matter what its relative priority
100 * is. */
101 /* 所有创建的任务处于挂起状态, 只能等新任务创建了 */
102 pxCurrentTCB = NULL;
103 }
104 else
105 {
106 /* 切换下上下文, 因为挂起的是当前任务, 也有可能就绪列表为空,
107 * 会导致pxCurrentTCB = idle, 否则会选择就绪列表中优先级最高
108 * 任务, 这个接口在这里只是设置了pxCurrentTCB参数, 并pend了
109 * yield, 因为当前调度器处于暂停状态 */
110 vTaskSwitchContext();
111 }
112 }
113 }
114 else
115 {
116 mtCOVERAGE_TEST_MARKER();
117 }
118 }
119 #endif /* #if ( configNUMBER_OF_CORES == 1 ) */
120 }
vTaskSuspend
这篇就到这里了,内容也比较多,下篇开始vTaskResume和vTaskStartScheduler。
下篇再见!
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。