新闻  |   论坛  |   博客  |   在线研讨会
浅析μC/OS-II v2.85内核调度函数
transformer | 2008-03-17 13:11:48    阅读:2306   发布文章

浅析μ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(),启动中断.

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
这样的事情是我们所需要的
最近文章
遇龙河沿途的风景
2008-05-28 18:04:21
test
2008-05-28 14:10:42
推荐文章
最近访客