"); //-->
浅析μC/OS-II v2.85内核调度函数
//----------------------------------------------------------------------
//1.μC/OS-II v2.85调度函数
void OS_Sched (void)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr = 0;
#endif
OS_ENTER_CRITICAL();
if (OSIntNesting == 0) {
if (OSLockNesting == 0) {
OS_SchedNew();//计算当前优先级最高的就绪进程对应的OSPrioHighRdy--task管理结构体指针
if (OSPrioHighRdy != OSPrioCur) {
//确实是一个全新的最值得占有cpu的task就绪了
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
#if OS_TASK_PROFILE_EN > 0
OSTCBHighRdy->OSTCBCtxSwCtr++;
#endif
OSCtxSwCtr++;
//假设当前执行的进程为A,那个更高优先级的进程为B,那么[gliethttp]
//当前进程A让出cpu,让更有能力持有cpu的进程B持有cpu,此时当前进程A的执行代码将终止于此,
//A的返回地址---函数OS_EXIT_CRITICAL();被OS_TASK_SW()函数推入堆栈,
//下一次因为A的优先级最高切换回来的时候,进程A继续执行的代码是OS_EXIT_CRITICAL();打开中断,
//所以OS_TASK_SW()代码执行的过程中,最后切换到新进程,新进程还没执行语句之前,ISR中断始终关闭,直到
OS_TASK_SW();
//直到切换到的新进程恢复到这里,继续向下执行
}
}
}
//新进程将调用OS_EXIT_CRITICAL()重新打开cpu的ISR中断系统,这时cpu的ISR中断才算是打开[gliethttp]
OS_EXIT_CRITICAL();
}
//----------------------------------------------------------------------
//2.OS_SchedNew()--巧妙的采用μC/OS-II v2.7之前的8位图方式,计算就绪task的优先级
static void OS_SchedNew (void)
{
#if OS_LOWEST_PRIO <= 63//如果定义的任务个数小于63个,那么还使用计算速度很快的μC/OS-II v2.7之前方式
INT8U y;
//OSRdyGrp位8bit,每一个bit代表优先级计算中行、列矩阵的某一组,
//如bit0为1,那么矩阵数组的第0组有就绪进程
// bit1为1,那么矩阵数组的第1组有就绪进程
// ...
// bit7为1,那么矩阵数组的第7组有就绪进程
y = OSUnMapTbl[OSRdyGrp];//通过优先级码表,获得最有持有cpu权限的task对应的矩形组号y
//OSRdyTbl[y]也为8bit数据,每一个bit代码一个进程的低8位值,使用位图码表,返回该y组内的进程中,
//进程号最小的那个进程号低8位,这样合成出新的进程号OSPrioHighRdy
//[使用位图码表的方式使得计算优先级的耗时为常数,不受进程数量的影响,但位图码表要占用255个字节空间gliethttp]
OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
#else
//以下为超过63,小于256个进程的优先级计算方法,计算效率不如上面的64个进程
INT8U y;
INT16U *ptbl;
//OSRdyGrp为16位
if ((OSRdyGrp & 0xFF) != 0) {
//y值越小,它的优先级越高,所以如果低8位有了需要调度的程序,那么没有必要再去考虑高8位情况
//优先级0~127中有就绪的进程
//如果OS_LOWEST_PRIO = 60,那么OS_TaskIdle()进程将在这里
y = OSUnMapTbl[OSRdyGrp & 0xFF];
} else {
//优先级0~127中有没有就绪的进程
//那么128~255中一定有就绪进程
//如果OS_LOWEST_PRIO = 132,那么OS_TaskIdle()进程将在这里
y = OSUnMapTbl[(OSRdyGrp >> 8) & 0xFF] + 8;//矩形组号y>=8
}
ptbl = &OSRdyTbl[y];//取出x方向的16bit数据
if ((*ptbl & 0xFF) != 0) {
//x值越小,它的优先级越高,所以如果低8位有了需要调度的程序,那么没有必要再去考虑高8位情况
//合成OSPrioHighRdy
OSPrioHighRdy = (INT8U)((y << 4) + OSUnMapTbl[(*ptbl & 0xFF)]);
} else {
//x方向低8位对应的进程可能因为OSSemPend()、OSTimeDly()之类的原因,悬停在某个地方,
//现在让x方向的高8位中优先级最高的进程成为最值得占用cpu的task
OSPrioHighRdy = (INT8U)((y << 4) + OSUnMapTbl[(*ptbl >> 8) & 0xFF] + 8);
}
#endif
}
//----------------------------------------------------------------------
//3.AT91RM9200处理器的OS_TASK_SW()定义如下[ADS1.2汇编代码gliethttp]
OSCtxSw
;// SAVE CURRENT TASK'S CONTEXT
STMFD {LR} ;//Push return address
STMFD {LR}
STMFD {R0-R12} ;// Push registers
MRS R4, CPSR ;// Push current CPSR
;//TST LR, #1 ;// See if called from Thumb mode
;//ORRNE R4, R4, #0x20 ;// If yes, Set the T-bit
STMFD {R4}
LDR R4, =OSTCBCur ;// OSTCBCur->OSTCBStkPtr = SP;
LDR R5, [R4]
STR SP, [R5]
LDR R4, =OSPrioCur ;// OSPrioCur = OSPrioHighRdy
LDR R5, =OSPrioHighRdy
LDRB R6, [R5]
STRB R6, [R4]
LDR R4, =OSTCBCur ;// OSTCBCur = OSTCBHighRdy;
LDR R6, =OSTCBHighRdy
LDR R6, [R6]
STR R6, [R4]
LDR SP, [R6] ;// SP = OSTCBHighRdy->OSTCBStkPtr;
;// RESTORE NEW TASK'S CONTEXT
LDMFD {R4} ;// Pop new task's CPSR
MSR SPSR_cxsf, R4
LDMFD {R0-R12,LR,PC}^;//返回到新的task,新task将要执行的第一个语句是OS_EXIT_CRITICAL(),启动中断.
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。