讹过畔 发表于 13 小时前

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

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 alsooverflowed,
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      * maximumsystem call (or maximum API call) interrupt priority.
9      * Interrupts that areabove 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 interruptsthat 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 */
28   /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */
29   /* coverity */
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。
下篇再见!

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