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接口,这两个接口较为复杂。

下篇再见。



声明

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