浅析μC/OS-II v2.85内核调度函数
文章来源:http://gliethttp.cublog.cn[转载请声明出处]
//---------------------------------------------------------------------- //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(),启动中断.
|