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中调用的最后一个接口。
这里补充一下,下面代码注释里说的禁止中断,在启动任务的时候会自动使能中断,是因为任务栈中最底层的第一个值就是XPSR的值为0x01000000,这里把xpsr里的primask清0了,就是表示使能中断。
这在《Cortex M3与M4权威指南》中描述XPSR寄存器的章节下有说明。
- 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接口,这两个接口较为复杂。
下篇再见。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |