温馨提示:本文不描述与浮点相关的寄存器的内容,如需了解自行查阅
调度器的基本概念
TencentOS tiny
中提供的任务调度器是基于优先级的全抢占式调度,在系统运行过程中,当有比当前任务优先级更高的任务就绪时,当前任务将立刻被切出
,高优先级任务抢占
处理器运行。
TencentOS tiny
内核中也允许创建相同优先级的任务。相同优先级的任务采用时间片轮转方式进行调度(也就是通常说的分时调度器),时间片轮转调度仅在当前系统中无更高优先级就绪任务的情况下才有效。
为了保证系统的实时性,系统尽最大可能地保证高优先级的任务得以运行。任务调度的原则是一旦任务状态发生了改变,并且当前运行的任务优先级小于优先级队列中任务最高优先级时,立刻进行任务切换(除非当前系统处于中断处理程序中或禁止任务切换的状态)。
调度器是操作系统的核心
,其主要功能就是实现任务的切换
,即从就绪列表里面找到
优先级最高的任务,然后去执行
该任务。
启动调度器
调度器的启动由cpu_sched_start
函数来完成,它会被tos_knl_start
函数调用,这个函数中主要做两件事,首先通过readyqueue_highest_ready_task_get
函数获取当前系统中处于最高优先级的就绪任务,并且将它赋值给指向当前任务控制块的指针k_curr_task
,然后设置一下系统的状态为运行态KNL_STATE_RUNNING
。
当然最重要的是调用汇编代码写的函数cpu_sched_start
启动调度器,该函数在源码的arch\arm\arm-v7m
目录下的port_s.S
汇编文件下,TencentOS tiny
支持多种内核的芯片,如M3/M4/M7
等,不同的芯片该函数的实现方式不同,port_s.S
也是TencentOS tiny
作为软件与CPU硬件连接的桥梁
。以M4的cpu_sched_start
举个例子:
__API__ k_err_t tos_knl_start(void)
{
if (tos_knl_is_running()) {
return K_ERR_KNL_RUNNING;
}
k_next_task = readyqueue_highest_ready_task_get();
k_curr_task = k_next_task;
k_knl_state = KNL_STATE_RUNNING;
cpu_sched_start();
return K_ERR_NONE;
}
port_sched_start
CPSID I
; set pendsv priority lowest
; otherwise trigger pendsv in port_irq_context_switch will cause a context swich in irq
; that would be a disaster
MOV32 R0, NVIC_SYSPRI14
MOV32 R1, NVIC_PENDSV_PRI
STRB R1, [R0]
LDR R0, =SCB_VTOR
LDR R0, [R0]
LDR R0, [R0]
MSR MSP, R0
; k_curr_task = k_next_task
MOV32 R0, k_curr_task
MOV32 R1, k_next_task
LDR R2, [R1]
STR R2, [R0]
; sp = k_next_task->sp
LDR R0, [R2]
; PSP = sp
MSR PSP, R0
; using PSP
MRS R0, CONTROL
ORR R0, R0, #2
MSR CONTROL, R0
ISB
; restore r4-11 from new process stack
LDMFD SP!, {R4 - R11}
IF {FPU} != "SoftVFP"
; ignore EXC_RETURN the first switch
LDMFD SP!, {R0}
ENDIF
; restore r0, r3
LDMFD SP!, {R0 - R3}
; load R12 and LR
LDMFD SP!, {R12, LR}
; load PC and discard xPSR
LDMFD SP!, {R1, R2}
CPSIE I
BX R1
Cortex-M内核关中断指令
从上面的汇编代码,我又想介绍一下Cortex-M
内核关中断指令,唉~感觉还是有点麻烦!
为了快速地开关中断, Cortex-M内核专门设置了一条 CPS 指令
,用于操作PRIMASK
寄存器跟FAULTMASK
寄存器的,这两个寄存器是与屏蔽中断有关的,除此之外Cortex-M
内核还存在BASEPRI
寄存器也是与中断有关的,也顺带介绍一下吧。
CPSID I ;PRIMASK=1 ;关中断
CPSIE I ;PRIMASK=0 ;开中断
CPSID F ;FAULTMASK=1 ;关异常
CPSIE F ;FAULTMASK=0 ;开异常