FreeRTOS调度器挂起与解除
生活随笔
收集整理的这篇文章主要介绍了
FreeRTOS调度器挂起与解除
小编觉得挺不错的,现在分享给大家,帮大家做个参考.
通过分析任务切换,我们知道任务切换的两种方法:系统节拍器中断、调用portYIELD产生PendSV中断。
在系统节拍器中断中,如果调度器被挂起,仅仅将调度器挂起时间加一(在解除挂起后需要补偿这些节拍),并不会检查是否有任务需要切换。
/* 系统节拍加一 */ BaseType_t xTaskIncrementTick(void) {BaseType_t xSwitchRequired = pdFALSE;/* 调度器没有被挂起 */if(uxSchedulerSuspended == (UBaseType_t)pdFALSE){......}/* 调度器被挂起 */else{/* 挂起时间加一 */++uxPendedTicks;}/* 前面有程序因为各种原因,要求延迟到现在切换 */if(xYieldPending != pdFALSE){/* 请求切换任务,最终进入PendSV异常,是否切换上下文还是在于PendSV */xSwitchRequired = pdTRUE;}return xSwitchRequired; }在PendSV中断中,如果调度器被挂起,则不进行上下文切换,通过xYieldPending将任务切换延迟到下一个节拍。
/* 任务切换上下文 */ void vTaskSwitchContext(void) {/* 调度器被挂起 */if(uxSchedulerSuspended != (UBaseType_t)pdFALSE){/* 等到下一次节拍的时候再切换上下文 */xYieldPending = pdTRUE;}/* 调度器没有挂起 */else{......} }也就是说,只要将调度器挂起,就肯定不会进行任务切换。
挂起调度器非常简单,只要让uxSchedulerSuspended不等于pdFALSE(0)即可。调度器可以多次挂起,但是对应的也要进行多次解除挂起。
/* 挂起调度器 */ void vTaskSuspendAll(void) {/* 挂起层数加一 */++uxSchedulerSuspended; }当完全解除调度器挂起时,需要进行如下工作:
检查在调度器挂起期间是否有任务进入就绪态,有则要将其从挂起期间就绪任务列表中移除,重新挂接到就绪任务列表
更新下一个需要解除阻塞的任务,的解除时间
要对之前调度器挂起期间产生的节拍进行补偿
对于延迟切换任务到下一个节拍的请求,在这里提供一次切换机会
/* 解除调度器挂起 */ BaseType_t xTaskResumeAll( void ) {TCB_t *pxTCB = NULL;BaseType_t xAlreadyYielded = pdFALSE;configASSERT(uxSchedulerSuspended);/* 进入临界区 */taskENTER_CRITICAL();{/* 调度器挂起层数减一 */--uxSchedulerSuspended;/* 调度器挂起完全解除 */if(uxSchedulerSuspended == (UBaseType_t)pdFALSE){/* 系统当前任务数大于0 */if(uxCurrentNumberOfTasks > (UBaseType_t)0U){/* 挂起时进入就绪的任务列表不为空 */while(listLIST_IS_EMPTY(&xPendingReadyList) == pdFALSE){/* 从挂起时进入就绪的任务列表中取出一个任务 */pxTCB = listGET_OWNER_OF_HEAD_ENTRY((&xPendingReadyList));/* 将任务从事件列表中移除 */(void)uxListRemove(&(pxTCB->xEventListItem));/* 将任务从状态列表中移除 */(void)uxListRemove(&(pxTCB->xStateListItem));/* 将任务加入就绪任务列表 */prvAddTaskToReadyList(pxTCB);/* 如果任务优先级高于当前任务优先级,则请求在下一个节拍时切换 */if(pxTCB->uxPriority >= pxCurrentTCB->uxPriority){xYieldPending = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}}/* 有任务在挂起期间就绪 */if(pxTCB != NULL){/* 更新下一个要解除阻塞的时间 */prvResetNextTaskUnblockTime();}{/* 调度器挂起时间 */UBaseType_t uxPendedCounts = uxPendedTicks;/* 调度器挂起时间大于1个节拍 */if(uxPendedCounts > (UBaseType_t)0U){/* 将所有节拍重新补上 */do{/* 节拍数加一,如果需要切换任务,则请求在下一个节拍时切换 */if(xTaskIncrementTick() != pdFALSE){xYieldPending = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}--uxPendedCounts;}while(uxPendedCounts > (UBaseType_t)0U);uxPendedTicks = 0;}else{mtCOVERAGE_TEST_MARKER();}}/* 原来请求在下一个节拍时切换的任务,在这里直接请求切换 */if(xYieldPending != pdFALSE){#if (configUSE_PREEMPTION != 0){/* 已经切换过任务 */xAlreadyYielded = pdTRUE;}#endiftaskYIELD_IF_USING_PREEMPTION();}else{mtCOVERAGE_TEST_MARKER();}}}else{mtCOVERAGE_TEST_MARKER();}}/* 退出临界区 */taskEXIT_CRITICAL();/* 返回是否已经切换过任务 */return xAlreadyYielded; }
总结
以上是生活随笔为你收集整理的FreeRTOS调度器挂起与解除的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 结不起婚生不起娃的低欲望社会来了?这份自
- 下一篇: makefile之伪目标(6)