操作系统的调度方法是其核心,下面是μc的调度函数
- /*
- *********************************************************************************************************
- * SCHEDULER
- *
- * Description: This function is called by other uC/OS-II services to determine whether a new, high
- * priority task has been made ready to run. This function is invoked by TASK level code
- * and is not used to reschedule tasks from ISRs (see OSIntExit() for ISR rescheduling).
- *
- * Arguments : none
- *
- * Returns : none
- *
- * Notes : 1) This function is INTERNAL to uC/OS-II and your application should not call it.
- * 2) Rescheduling is prevented when the scheduler is locked (see OS_SchedLock())
- *********************************************************************************************************
- */
- void OS_Sched (void)
- {
- #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
- OS_CPU_SR cpu_sr = 0;
- #endif
- OS_ENTER_CRITICAL();
- if (OSIntNesting == 0) { /* Schedule only if all ISRs done and ... */
- if (OSLockNesting == 0) { /* ... scheduler is not locked */
- OS_SchedNew();
- if (OSPrioHighRdy != OSPrioCur) { /* No Ctx Sw if current task is highest rdy */
- OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
- #if OS_TASK_PROFILE_EN > 0
- OSTCBHighRdy->OSTCBCtxSwCtr++; /* Inc. # of context switches to this task */
- #endif
- OSCtxSwCtr++; /* Increment context switch counter */
- OS_TASK_SW(); /* Perform a context switch */
- }
- }
- }
- OS_EXIT_CRITICAL();
- }
首先,关中断,判断是否在IRQ中(是否嵌套大于0),如果不在,可以执行调度
然后,判断调度是否被禁止OSLockNesting == 0
调用OS_SchedNew();函数调度
- /*
- *********************************************************************************************************
- * FIND HIGHEST PRIORITY TASK READY TO RUN
- *
- * Description: This function is called by other uC/OS-II services to determine the highest priority task
- * that is ready to run. The global variable 'OSPrioHighRdy' is changed accordingly.
- *
- * Arguments : none
- *
- * Returns : none
- *
- * Notes : 1) This function is INTERNAL to uC/OS-II and your application should not call it.
- * 2) Interrupts are assumed to be disabled when this function is called.
- *********************************************************************************************************
- */
- static void OS_SchedNew (void)
- {
- #if OS_LOWEST_PRIO <= 63 /* See if we support up to 64 tasks */
- INT8U y;
- y = OSUnMapTbl[OSRdyGrp];
- OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
- #else /* We support up to 256 tasks */
- INT8U y;
- INT16U *ptbl;
- if ((OSRdyGrp & 0xFF) != 0) {
- y = OSUnMapTbl[OSRdyGrp & 0xFF];
- } else {
- y = OSUnMapTbl[(OSRdyGrp >> 8) & 0xFF] + 8;
- }
- ptbl = &OSRdyTbl[y];
- if ((*ptbl & 0xFF) != 0) {
- OSPrioHighRdy = (INT8U)((y << 4) + OSUnMapTbl[(*ptbl & 0xFF)]);
- } else {
- OSPrioHighRdy = (INT8U)((y << 4) + OSUnMapTbl[(*ptbl >> 8) & 0xFF] + 8);
- }
- #endif
- }
当最低优先级小于63时,即优先级只有0-63,那么执行就绪表最高优先级查找算法OSUnMapTbl[]
当优先级大于63时,4位表示一个表元素,
最后都将最高优先级写入OSPrioHighRdy变量
检查OSPrioHighRdy和现在运行的任务的优先级是不是匹配,如果不是当前运行的程序
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy],修改要运行的最高优先级TCB
如果使能Ext,OSTCBHighRdy->OSTCBCtxSwCtr++;将切换次数变量自加
OSCtxSwCtr++;系统上下文切换计数器自加
OS_TASK_SW();切换任务
- ;**********************************************************************************************************
- ; PERFORM A CONTEXT SWITCH (From task level)
- ; void OSCtxSw(void)
- ;
- ; Note(s): 1) Upon entry:
- ; OSTCBCur points to the OS_TCB of the task to suspend
- ; OSTCBHighRdy points to the OS_TCB of the task to resume
- ;
- ; 2) The stack frame of the task to suspend looks as follows:
- ;
- ; PC (High memory)
- ; LR(R14)
- ; R12
- ; R11
- ; R10
- ; R9
- ; R8
- ; R7
- ; R6
- ; R5
- ; R4
- ; R3
- ; R2
- ; R1
- ; R0
- ; OSTCBCur->OSTCBStkPtr ----> CPSR (Low memory)
- ;
- ;
- ; 3) The stack frame of the task to resume looks as follows:
- ;
- ; PC (High memory)
- ; LR(R14)
- ; R12
- ; R11
- ; R10
- ; R9
- ; R8
- ; R7
- ; R6
- ; R5
- ; R4
- ; R3
- ; R2
- ; R1
- ; R0
- ; OSTCBHighRdy->OSTCBStkPtr ----> CPSR (Low memory)
- ;*********************************************************************************************************/
- OSCtxSw
- STMFD SP!, {LR} ;PC
- STMFD SP!, {R0-R12, LR} ;R0-R12 LR
- MRS R0, CPSR ;Push CPSR
- STMFD SP!, {R0}
- ;----------------------------------------------------------------------------------
- ; OSTCBCur->OSTCBStkPtr = SP
- ;----------------------------------------------------------------------------------
- LDR R0, =OSTCBCur
- LDR R0, [R0]
- STR SP, [R0]
- ;----------------------------------------------------------------------------------
- ; OSTaskSwHook();
- ;---------------------------------------------------------------------------------
- BL OSTaskSwHook
- ;----------------------------------------------------------------------------------
- ; OSTCBCur = OSTCBHighRdy;
- ;----------------------------------------------------------------------------------
- LDR R0, =OSTCBHighRdy
- LDR R1, =OSTCBCur
- LDR R0, [R0]
- STR R0, [R1]
- ;----------------------------------------------------------------------------------
- ; OSPrioCur = OSPrioHighRdy;
- ;----------------------------------------------------------------------------------
- LDR R0, =OSPrioHighRdy
- LDR R1, =OSPrioCur
- LDRB R0, [R0]
- STRB R0, [R1]
- ;----------------------------------------------------------------------------------
- ; OSTCBHighRdy->OSTCBStkPtr;
- ;----------------------------------------------------------------------------------
- LDR R0, =OSTCBHighRdy
- LDR R0, [R0]
- LDR SP, [R0]
- ;----------------------------------------------------------------------------------
- ;Restore New task context
- ;----------------------------------------------------------------------------------
- LDMFD SP!, {R0} ;POP CPSR
- MSR SPSR_cxsf, R0
- LDMFD SP!, {R0-R12, LR, PC}^
完成三个任务,
第一,OSTCBCur修改指向将要被挂起任务的TCB,将OSTCBHighRdy指向将要被运行的任务的TCB
。。。
以前看过的ARM体系结构和指令集都忘记了,必经没有实际使用过,没有深刻的印象,今天对照着指令集从新看过这个汇编函数:
这个函数做了三件事情
第一步,把当前任务对应的R0-R12压栈,使用STMFD指令将PC写入LR(R14)寄存器,使用回写‘!’指令使其写入的地址递增,将寄存器值压入栈的顺序为FD满栈递减,从栈底开始向低地址写入寄存器值
第二步,OSTCBCur = OSTCBHighRdy;OSPrioCur = OSPrioHighRdy; SP=OSTCBHighRdy->OSTCBStkPtr;
具体实现了最高优先级prio和TCB对现在运行的prio和TCB的同步
将SP(R13)指向现在要运行的TCB的栈指针
第三步,对切换后的任务TCB的栈进行弹栈操作,使用LDMFD弹出CPSR到R0 使用MSR将R0写入SPSR,弹出R0-R12 R14 R15
阅读(1411) | 评论(0) | 转发(0) |