在实时操作系统uC/OS-III中,调度器是核心组件之一,它负责管理任务的执行顺序和优先级。本文将详细解析uC/OS-III内核中的调度函数OSSched。
OSSched函数简介
OSSched函数用于检查并确定是否有更高优先级的任务需要运行。该函数通常在任务级别代码中调用,而不是在中断服务程序(ISR)中调用。中断服务程序的任务调度由OSIntExit()函数处理。OSSched函数主要完成以下任务:
- 检查操作系统运行状态。
- 检查中断嵌套计数器。
- 检查调度器是否被锁定。
- 获取最高优先级任务。
- 执行任务级别的上下文切换。
OSSched函数流程图
详细步骤解析
1. 操作系统运行状态检查
在OSSched函数中,首先会检查操作系统是否正在运行。如果操作系统未启动,则直接返回。这一步的目的是确保在操作系统初始化过程中不会进行不必要的操作。
#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u)
if (OSRunning != OS_STATE_OS_RUNNING) {
return;
}
#endif
2. 中断嵌套计数器检查
检查中断嵌套计数器,如果有嵌套的中断正在处理,则直接返回,不进行任务调度。
if (OSIntNestingCtr > 0u) {
return;
}
3. 调度器锁定检查
检查调度器是否被锁定,如果是,则直接返回,不进行任务切换。
if (OSSchedLockNestingCtr > 0u) {
return;
}
4. 获取最高优先级任务
获取最高优先级的任务,并进行任务切换。如果当前任务就是最高优先级任务,则直接返回。
CPU_INT_DIS();
OSPrioHighRdy = OS_PrioGetHighest();
#if (OS_CFG_TASK_IDLE_EN > 0u)
OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;
if (OSTCBHighRdyPtr == OSTCBCurPtr) {
CPU_INT_EN();
return;
}
#else
if (OSPrioHighRdy != (OS_CFG_PRIO_MAX - 1u)) {
OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;
if (OSTCBHighRdyPtr == OSTCBCurPtr) {
CPU_INT_EN();
return;
}
}
#endif
5. 执行任务级别的上下文切换
增加上下文切换计数器的值,调用OS_TASK_SW()函数进行任务级别的上下文切换,最后使能中断。
OS_TRACE_TASK_PREEMPT(OSTCBCurPtr);
#if (OS_CFG_TASK_PROFILE_EN > 0u)
OSTCBHighRdyPtr->CtxSwCtr++;
#endif
#if ((OS_CFG_TASK_PROFILE_EN > 0u) || (OS_CFG_DBG_EN > 0u))
OSTaskCtxSwCtr++;
#endif
#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u)
OS_TLS_TaskSw();
#endif
#if (OS_CFG_TASK_IDLE_EN > 0u)
OS_TASK_SW();
CPU_INT_EN();
#else
if ((OSPrioHighRdy != (OS_CFG_PRIO_MAX - 1u))) {
OS_TASK_SW();
CPU_INT_EN();
} else {
OSTCBHighRdyPtr = OSTCBCurPtr;
CPU_INT_EN();
for (;;) {
#if ((OS_CFG_DBG_EN > 0u) || (OS_CFG_STAT_TASK_EN > 0u))
CPU_CRITICAL_ENTER();
#if (OS_CFG_DBG_EN > 0u)
OSIdleTaskCtr++;
#endif
#if (OS_CFG_STAT_TASK_EN > 0u)
OSStatTaskCtr++;
#endif
CPU_CRITICAL_EXIT();
#endif
#if (OS_CFG_APP_HOOKS_EN > 0u)
OSIdleTaskHook();
#endif
if ((*((volatile OS_PRIO *)&OSPrioHighRdy) != (OS_CFG_PRIO_MAX - 1u))) {
break;
}
}
}
#endif
以下接口调用OSSched
OSSchedUnlock
OSFlagDel
OSFlagPend
OSFlagPendAbort
OSFlagPost(可以使用OS_OPT_POST_NO_SCHED禁止调度)
OSMutexDel
OSMutexPend
OSMutexPendAbort
OSMutexPost(可以使用OS_OPT_POST_NO_SCHED禁止调度)
OSQDel
OSQPend
OSQPendAbort
OSQPost(可以使用OS_OPT_POST_NO_SCHED禁止调度)
OSSemDel
OSSemPend
OSSemPendAbort
OSSemPost(可以使用OS_OPT_POST_NO_SCHED禁止调度)
OSTaskChangePrio
OSTaskCreate
OSTaskDel
OSTaskQPend
OSTaskQPendAbort
OSTaskQPost
OSTaskResume
OSTaskSemPend
OSTaskSemPendAbort
OSTaskSemPost
OSTaskSuspend
OSTimeDly
OSTimeDlyHMSM
OSTimeDlyResume
OS_TmrTask
注意事项
- OSSched函数,不能在ISR中调用,应用程序也不建议调用此接口。
- 调用OSSched函数前应确保中断已禁用。
- 中断嵌套或调度器锁定期间,任务调度将被禁止。