freeRTOS源码解析4--tasks.c 5
cnblogs 2024-09-30 09:45:00 阅读 96
4.2.13 继续任务--vTaskResume
接口:
void vTaskResume( TaskHandle_t xTaskToResume )
形参1:xTaskToResume ,想要继续的任务handle;
首先是vTaskResume调用的一个内部函数:static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ),用于检查任务是否是挂起状态,只有挂起的任务才能继续,否则是等待事件、通知等处于阻塞态,那就不能放到就绪列表,必须继续等待。这个接口逻辑非常简单,就直接看代码即可。
1 static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask )
2 {
3 BaseType_t xReturn = pdFALSE;
4 const TCB_t * const pxTCB = xTask;
5
6 /* Accesses xPendingReadyList so must be called from a critical
7 * section. */
8
9 /* It does not make sense to check if the calling task is suspended. */
10 configASSERT( xTask );
11
12 /* Is the task being resumed actually in the suspended list? */
13 /* 检查任务是否在挂起列表, 不在则说明任务未挂起 */
14 if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xStateListItem ) ) != pdFALSE )
15 {
16 /* Has the task already been resumed from within an ISR? */
17 /* 任务在挂起列表里, 但在调度器暂停时被移至等待就绪列表中, 则说明任务未挂起 */
18 if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) == pdFALSE )
19 {
20 /* Is it in the suspended list because it is in the Suspended
21 * state, or because it is blocked with no timeout? */
22 /* 任务在挂起列表里, 但在等待事件, 则说明任务未挂起 */
23 if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) != pdFALSE )
24 {
25 #if ( configUSE_TASK_NOTIFICATIONS == 1 )
26 {
27 BaseType_t x;
28
29 /* The task does not appear on the event list item of
30 * and of the RTOS objects, but could still be in the
31 * blocked state if it is waiting on its notification
32 * rather than waiting on an object. If not, is
33 * suspended. */
34 /* 任务在挂起列表里, 且未等待事件, 那么如果在等待通知则未挂起, 否则挂起 */
35 xReturn = pdTRUE;
36
37 for( x = ( BaseType_t ) 0; x < ( BaseType_t ) configTASK_NOTIFICATION_ARRAY_ENTRIES; x++ )
38 {
39 if( pxTCB->ucNotifyState[ x ] == taskWAITING_NOTIFICATION )
40 {
41 xReturn = pdFALSE;
42 break;
43 }
44 }
45 }
46 #else /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */
47 {
48 xReturn = pdTRUE;
49 }
50 #endif /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */
51 }
52 else
53 {
54 mtCOVERAGE_TEST_MARKER();
55 }
56 }
57 else
58 {
59 mtCOVERAGE_TEST_MARKER();
60 }
61 }
62 else
63 {
64 mtCOVERAGE_TEST_MARKER();
65 }
66
67 /* 总结下来就是任务若在挂起列表里, 如果不是在等待事件或通知, 则是挂起状态, 否则不是 */
68
69 return xReturn;
70 }
prvTaskIsTaskSuspended
1 void vTaskResume( TaskHandle_t xTaskToResume )
2 {
3 TCB_t * const pxTCB = xTaskToResume;
4
5 /* It does not make sense to resume the calling task. */
6 configASSERT( xTaskToResume );
7
8 #if ( configNUMBER_OF_CORES == 1 )
9 /* The parameter cannot be NULL as it is impossible to resume the
10 * currently executing task. */
11 if( ( pxTCB != pxCurrentTCB ) && ( pxTCB != NULL ) )
12 #endif
13 {
14 taskENTER_CRITICAL();
15 {
16 if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
17 {
18 /* The ready list can be accessed even if the scheduler is
19 * suspended because this is inside a critical section. */
20 /* 只有任务处于挂起状态才能继续 */
21 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
22 prvAddTaskToReadyList( pxTCB );
23
24 /* This yield may not cause the task just resumed to run,
25 * but will leave the lists in the correct state for the
26 * next yield. */
27 /* 保证各任务列表处于正常的状态 */
28 taskYIELD_ANY_CORE_IF_USING_PREEMPTION( pxTCB );
29 }
30 else
31 {
32 mtCOVERAGE_TEST_MARKER();
33 }
34 }
35 taskEXIT_CRITICAL();
36 }
37 else
38 {
39 mtCOVERAGE_TEST_MARKER();
40 }
41 }
vTaskResume
4.2.14 启动调度--vTaskStartScheduler
这个接口会创建空闲任务和软定时器任务,之后就是允许第一个任务,这个接口永远也不会返回,也是main中调用的最后一个接口。
1 void vTaskStartScheduler( void )
2 {
3 BaseType_t xReturn;
4
5 /* 创建空闲任务 */
6 xReturn = prvCreateIdleTasks();
7
8 #if ( configUSE_TIMERS == 1 )
9 {
10 if( xReturn == pdPASS )
11 {
12 xReturn = xTimerCreateTimerTask(); // 创建软定时器任务
13 }
14 else
15 {
16 mtCOVERAGE_TEST_MARKER();
17 }
18 }
19 #endif /* configUSE_TIMERS */
20
21 if( xReturn == pdPASS )
22 {
23 /* Interrupts are turned off here, to ensure a tick does not occur
24 * before or during the call to xPortStartScheduler(). The stacks of
25 * the created tasks contain a status word with interrupts switched on
26 * so interrupts will automatically get re-enabled when the first task
27 * starts to run. */
28 /* 关闭中断, 保证在调用xPortStartScheduler前不会发生tick中断, 所有创建
29 * 的任务的栈中都包含一个中断开启的状态字, 所以第一个任务运行时, 中断
30 * 会自动开启 */
31 /* 暂时没看懂这个注释的意思, 但这个接口只是设置了中断优先级屏蔽寄存器,
32 * 实际的中断并未关闭, 系统中断被屏蔽了 */
33 portDISABLE_INTERRUPTS();
34
35 xNextTaskUnblockTime = portMAX_DELAY;
36 xSchedulerRunning = pdTRUE;
37 xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT;
38
39 /* If configGENERATE_RUN_TIME_STATS is defined then the following
40 * macro must be defined to configure the timer/counter used to generate
41 * the run time counter time base. NOTE: If configGENERATE_RUN_TIME_STATS
42 * is set to 0 and the following line fails to build then ensure you do not
43 * have portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() defined in your
44 * FreeRTOSConfig.h file. */
45 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();
46
47 /* Setting up the timer tick is hardware specific and thus in the
48 * portable interface. */
49
50 /* The return value for xPortStartScheduler is not required
51 * hence using a void datatype. */
52 /* 真正的启动调度器, 即启动了第一个任务 */
53 ( void ) xPortStartScheduler();
54
55 /* In most cases, xPortStartScheduler() will not return. If it
56 * returns pdTRUE then there was not enough heap memory available
57 * to create either the Idle or the Timer task. If it returned
58 * pdFALSE, then the application called xTaskEndScheduler().
59 * Most ports don't implement xTaskEndScheduler() as there is
60 * nothing to return to. */
61 }
62 else
63 {
64 /* This line will only be reached if the kernel could not be started,
65 * because there was not enough FreeRTOS heap to create the idle task
66 * or the timer task. */
67 configASSERT( xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY );
68 }
69
70 /* Prevent compiler warnings if INCLUDE_xTaskGetIdleTaskHandle is set to 0,
71 * meaning xIdleTaskHandles are not used anywhere else. */
72 ( void ) xIdleTaskHandles;
73
74 /* OpenOCD makes use of uxTopUsedPriority for thread debugging. Prevent uxTopUsedPriority
75 * from getting optimized out as it is no longer used by the kernel. */
76 ( void ) uxTopUsedPriority;
77 }
vTaskStartScheduler
4.2.15 停止调度--vTaskEndScheduler
这个接口和上一个相对,而且这个接口一定是在某个任务中调用的,因为系统不会主动停止调度器,而正常运行中始终只有某个任务和系统在运行,所以必然是某个任务主动调用的。
1 void vTaskEndScheduler( void )
2 {
3 #if ( INCLUDE_vTaskDelete == 1 )
4 {
5 BaseType_t xCoreID;
6
7 #if ( configUSE_TIMERS == 1 )
8 {
9 /* Delete the timer task created by the kernel. */
10 /* 删除软定时器任务 */
11 vTaskDelete( xTimerGetTimerDaemonTaskHandle() );
12 }
13 #endif /* #if ( configUSE_TIMERS == 1 ) */
14
15 /* Delete Idle tasks created by the kernel.*/
16 for( xCoreID = 0; xCoreID < ( BaseType_t ) configNUMBER_OF_CORES; xCoreID++ )
17 {
18 vTaskDelete( xIdleTaskHandles[ xCoreID ] ); // 删除空闲任务
19 }
20
21 /* Idle task is responsible for reclaiming the resources of the tasks in
22 * xTasksWaitingTermination list. Since the idle task is now deleted and
23 * no longer going to run, we need to reclaim resources of all the tasks
24 * in the xTasksWaitingTermination list. */
25 /* 本应由空闲任务回收待删除任务的资源, 但现在空闲任务被删除了, 就在这里处理 */
26 prvCheckTasksWaitingTermination();
27 }
28 #endif /* #if ( INCLUDE_vTaskDelete == 1 ) */
29
30 /* Stop the scheduler interrupts and call the portable scheduler end
31 * routine so the original ISRs can be restored if necessary. The port
32 * layer must ensure interrupts enable bit is left in the correct state. */
33 /* 这跟启动调度器时关中断一样的疑问 */
34 portDISABLE_INTERRUPTS();
35 xSchedulerRunning = pdFALSE;
36
37 /* This function must be called from a task and the application is
38 * responsible for deleting that task after the scheduler is stopped. */
39 vPortEndScheduler();
40 }
vTaskEndScheduler
好了,下一篇讲xTaskAbortDelay和xTaskIncrementTick接口,这两个接口较为复杂。
下篇再见。
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。