基于ARM Cortex-M4的mbedOS调度机制剖析

2022-12-16 09:44刘长勇王宜怀
吉林大学学报(信息科学版) 2022年4期
关键词:寄存器线程内核

刘长勇,王宜怀

(1.武夷学院 a.数学与计算机学院;b.认知计算与智能信息处理福建省高校重点实验室,福建 武夷山 354300;2.苏州大学 计算机科学与技术学院,苏州 215006)

0 引 言

实时操作系统(RTOS:Real-Time Operating System)是应用于嵌入式系统中的一种系统软件,能提供多任务管理、同步与通信机制、中断处理等功能,大多应用于对实时性要求较高的场合。在基于RTOS的编程模式下,任务是按照一定规则划分的功能相对独立的小工程,它由RTOS进行管理与调度。调度是RTOS最重要的职责,其本质上就是通过列表管理任务并进行上下文切换。任务在有些RTOS中也称为线程。

目前,已有一些研究者对RTOS的调度策略进行分析。例如,张玉鲁[1]指出RT-Thread支持优先级抢占和时间片轮转两种调度策略,采用线程调度器实现线程调度。徐丽华等[2]指出MQX(Message Queue Xecutive)调度策略包括优先级抢占和时间片轮询方式。马霁壮[3]指出FreeRTOS通过任务控制块进行任务的管理,调度算法包括优先级的抢占式和同优先级下的轮转式,由任务调度器实现任务的切换与保护。张楠[4]指出μC/OS-Ⅱ的调度方式为静态优先级抢占式,依据任务的优先级实现对任务的管理和调度。陈国良等[5]对Linux实时操作系统的EDF(Earliest Deadline First)任务调度算法进行改进,提出了LLF(Least Laxity First)调度算法。何涛[6]阐述了AUTOSAR OS(AU Tomotive Open System Architecture Operaing System)调度策略包括完全抢占、不可抢调度和混合调度策略,由任务调度函数OS_Sched根据任务的运行状态,选择某种调度策略完成对任务的调度。马运南[7]指出在Minicore实时操作系统中,任务调度使用基于优先级和时间片的设计。Huang等[8]指出OSEK-OS(Offene Systeme and deren Schnittstellen fur dieElektronikim Kraftfahr-zeug-Operaing System)的任务具有静态分配的优先级,允许使用所有系统服务,并根据固定优先级调用抢占式调度策略。笔者通过阐述ARM Cortex-M4内核对RTOS的支持特性,分析了RTOS最常用的优先级抢占调度机制和时间片轮询调度机制,展示了mbedOS实现线程调度的具体方法,并以意法半导体的STM32L431芯片为例给出了mbedOS的线程调度剖析实践。实践表明,SVC(Supervisor Call)中断、PendSV(Pendable Supervisor)中断和SysTick中断能很好地实现对线程的调度。通过对mbedOS调度策略的剖析,有助于加深对mbedOS的理解与应用,也有利于对其他RTOS的分析。

1 ARM Cortex-M4内核对RTOS的支持特性

ARM Cortex-M4是ARM(Advanced RISC Machines)公司2010年推出的32位处理器,主要应用于数字信号控制方面[9],该处理器在设计时就考虑了对嵌入式实时操作系统的高效支持[10]。

1.1 操作模式

为进一步提高嵌入式系统的可靠性,ARM Cortex-M4支持独立处理和线程两种模式,存在调试和Thumb两种状态,允许特权和非特权两种访问等级。处理模式即Handler模式,是指处理器在执行中断服务程序等异常的一种模式,具有特权访问等级;线程模式是指当使用实时操作系统且执行用户线程时的一种模式,提供特权和非特权访问等级。调试状态是指当处理器被暂停指令执行后所处的状态;Thumb状态是指处理器在执行Thumb指令(程序代码)时所处的状态。

1.2 寄存器及双栈指针

ARM Cortex-M4处理器提供了数据处理与控制寄存器、特殊功能寄存器和浮点寄存器,其中R0-R12作为通用目的寄存器。在mbedOS中,R12存放被调用函数的入口地址;R13为栈指针,即可作为主栈指针MSP(Main Stack Pointer)使用,也可作为线程栈指针PSP(Process Stack Pointer)使用,MSP用于处理模式,PSP用于线程模式;R14即连接寄存器LR(Link Register),用于保存函数或子程序调用时的返回地址;R15即程序计数器PC(Program Counter),其内容是下一条将要执行指令的地址;xPSR即程序状态字寄存器,存放程序执行过程中的各种状态信息。ARM架构定义了一个特殊值EXC_RETURN,用于异常返回机制。该值在异常被接收并且压栈完成后自动存储到连接寄存器LR(R14)中。EXC_RETURN值为32位,但高27位都为1,在Cortex-M4中,第0位是保留位,且必须为1,EXC_RETURN的合法值有6个,如表1所示。

表1 EXC_RETURN的值Tab.1 Value of EXC_RETURN

1.3 SysTick中断

ARM Cortex-M4系列内核中包含了一个24位的“嘀嗒”定时器SysTick,采用减1计数方式,其异常编号为15,IRQ(Interrupt Request)号为-1,且优先级可编程设置,中断触发示例如图1所示。在带有实时操作系统的嵌入式工程中,使用SysTick中断可定期触发RTOS内核,实现任务的管理与调度,也使同一个RTOS可用在多种ARM Cortex-M微控制器上。

1.4 SVC中断

为实现用户程序对系统硬件的间接访问,ARM Cortex-M4系列内核支持系统服务调用(SVC)方式,由RTOS内核为用户提供系统服务函数,让用户通过SVC指令的方式实现对其的调用请求。通常SVC中断被触发后会被立即执行,精确性较高,常用于上下文切换,其异常编号为11,IRQ号为-5,且优先级可编程设置,中断触发示例如图2所示。

图1 SysTick中断触发的简单示例 图2 SVC中断触发的简单示例 Fig.1 Simple example of SysTick interrupt trigger Fig.2 Simple example of SVC interrupt trigger

1.5 PendSV中断

可挂起系统调用(PendSV)在功能上与SVC类似,但它是不精确的,常用于上下文切换,其异常编号为14,IRQ号为-2,且优先级可编程设置。通常将PendSV设置为较低的优先级,当在一个中断中或中断被屏蔽的情况下调用了一个可允许在中断中执行的操作函数时(如在中断中调用线程信号设置函数),系统会在更高优先级中断内将其设置为挂起状态,直到该高优先级中断处理结束,被推迟的PendSV中断才会被触发并开始执行,中断触发示例如图3所示。

图3 PendSV中断触发的简单示例Fig.3 Simple example of PendSV interrupt trigger

1.6 上下文切换

任务上下文是指任务在运行的任一时刻,ARM Cortex-M4处理器内部寄存器的值[11]。这些寄存器包括通用寄存器R0-R12、连接寄存器LR、程序计数器PC和程序状态字寄存器xPSR。

在RTOS中,当内核需调度运行其他任务时,要将正在运行任务(上文)的状态信息保存到自己的任务堆栈中,然后把下一个将要运行任务(下文)的状态信息从其任务堆栈中恢复到CPU的寄存器,这个过程称为上下文切换。在此过程中,R0-R3、R12、R14(LR)、R15(PC)和xPSR 8个寄存器的内容由硬件自动完成进栈和出栈,而R4-R11 8个寄存器内容则由用户自行保存进栈和恢复出栈。

2 RTOS调度策略

由于嵌入式系统的资源相对PC机比较匮乏,要在嵌入式系统中运行RTOS实现多任务的管理,首要考虑任务调度策略问题,其好坏直接影响到系统的实时性能。目前,RTOS的调度策略主要有:优先级抢占调度、时间片轮转调度、零星调度和显示调度等,包括mbedOS在内的大多数RTOS都采用前两者调度策略,Nuttx除采用前两种调度外,还采用了零星调度策略[12],显示调度的方式是用命令直接让其运行,在RTOS中很少用到。下面将分析优先级抢占调度和时间片轮转调度这两种最常用的调度策略。

2.1 优先级抢占调度

为便于RTOS根据任务的轻重缓急进行调度,在任务创建时会为每个任务设置一个优先级(即优先等级参数),RTOS会根据各个任务的优先级高低,决定处理各个任务的先后次序。不同的RTOS,对任务优先级数值的大小与任务优先级的高低关系的定义不同,如在mbedOS中,优先级数值越大表示线程的优先级越高;而优先级数值越小表示任务的优先级越高的RTOS有MQX[13]和RT-Thread[14]。优先级抢占调度是指,总是让优先级最高的处于就绪态的任务最先运行。

2.2 时间片轮询调度

时间片轮询调度策略是指为了能让各个任务都能得到调度运行,对优先级相同的任务采用时间片轮询方式,给各个任务分配固定的时间片分享CPU的使用。在mbedOS的时间片轮询调度策略中,一个时间片为5个时间嘀嗒。

3 mbedOS调度实现

不同RTOS对调度策略的实现不同。在RT-Thread中,调度策略采用PendSV中断和SysTick中断实现[15]。在MQX中,调度策略采用SVC中断和PendSV中断实现[16]。在mbedOS中,调度策略通过SVC中断、PendSV中断和SysTick中断实现,它们都能对线程进行管理、调度以及上下文切换,其中上下文切换都采用相同的代码,该代码在SVC中断处理程序SVC_Handler中。下面将剖析这3种中断的具体实现方法。

3.1 SVC中断的实现

图4 SVC_Handler函数执行流程Fig.4 Flow chart of SVC_Handler function execution

在mbedOS中,SVC中断是通过执行SVC 0指令产生的,SVC 0就是调用0号系统服务,在SVC指令执行完后会触发SVC中断处理程序SVC_Handler,在程序中会根据这个系统服务号(0)决定执行相应操作。

3.1.1 SVC_Handler函数主要功能

SVC中断处理程序SVC_Handler的主要功能包括根据EXC_RETURN值判断是使用主栈(MSP)还是线程栈(PSP),取出SVC指令的调用号(0);调用触发SVC异常函数,即R12中的函数;根据当前OS实时状态osRtxInfo中的线程运行信息,决定是否进行上下文切换与线程切换;使用不同EXC_RETURN返回。其执行流程如图4所示。

3.1.2 上下文切换的关键代码分析

SVC_Handler函数中上下文切换主要是判断当前运行线程与下一线程是否不同。若不同,则需要保存当前线程的上下文,恢复下一线程的上下文,然后进行线程切换,其关键代码分析如下。

SVC_Context:

LDR R3,=osRtxInfo+I_T_RUN_OFS //R3←当前运行线程存放的地址

LDM R3,{R1,R2} //R1←当前运行线程;R2←下一个线程

CMP R1,R2 //判断是否需要线程切换

IT EQ

BXEQ LR //线程相同,不需要切换

CBNZ R1,SVC_ContextSave //不同,进行线程切换

TST LR,#0x10

BNE SVC_ContextSwitch //存在扩展堆栈帧,跳线程切换

SVC_ContextSave: //保存当前线程(R1)的上下文、栈指针和栈帧信息

STMDB R12!,{R4-R11} //保存当前线程(R1)的上下文

STR R12,[R1,#TCB_SP_OFS] //保存R1的栈指针

STRB LR,[R1,#TCB_SF_OFS] //保存R1的栈帧信息

SVC_ContextSwitch://线程切换

STR R2,[R3] //下一线程R2作为当前线程

SVC_ContextRestore://恢复下一线程(R2)的上下文

LDRB R1,[R2,#TCB_SF_OFS] //恢复下一线程R2的栈帧信息

LDR R0,[R2,#TCB_SP_OFS] //恢复R2的栈指针

ORR LR,R1,#0xFFFFFF00 //设置返回线程模式

LDMIA R0!,{R4-R11} //恢复R2的上下文

MSR PSP,R0 //使用PSP栈指针

BX LR //退出

3.2 PendSV中断的实现

在mbedOS中,PendSV中断一般出现在:当在一个中断函数中或中断被屏蔽的情况下调用了一个可以允许在中断上下文中执行的操作函数时,系统会进入该操作函数,执行推迟PendSV中断操作,而当中断程序执行完后才会转到执行PendSV中断。PendSV_Handler函数主要功能包括调用osRtxPendSV_Handler函数(完成从中断队列中取对象类型,根据对象的类型执行相应处理函数,取就绪列表中最高优先级线程)、跳到SVC_Handler函数中的SVC_Context处开始上下文切换,其执行流程如图5所示。

图5 PendSV_Handler函数执行流程Fig.5 Flow chart of PendSV_ Handler function execution

3.3 SysTick中断的实现

在mbedOS中,内核时钟频率采用48 MHz,1个时间嘀嗒为1 ms,每个时间片为5个时间嘀嗒。当一个时间嘀嗒到时,则产生SysTick中断一次,在中断服务程序SysTick_Handler中完成对线程的管理和调度。SysTick_Handler主要功能包括:从延时列表移出到期线程,并加到就绪列表中;若就绪列表最高优先级线程的优先级高于正在运行的线程优先级,则抢占当前运行的线程;当时间片到,则优先级相同的线程之间采用轮询调度策略;跳到SVC_Handler函数中的SVC_Context处开始上下文切换,其执行流程如图6所示。

图6 SysTick_Handler函数执行流程Fig.6 SysTick_ Handler function execution flow

4 mbedOS线程调度实践分析

2014年ARM公司推出了mbedOS,它是一种专为物联网(IoT)中的“物体”设计的开源嵌入式实时操作系统(RTOS)[17],具备一般RTOS的基本功能,其在物联网设备平台[18]、物联网应用[19]、通信技术与安全访问服务机制[20]、协议栈与IP网络组件[21]等方面得到广泛应用。现针对mbedOS实时操作系统,给出具体延时响应的实践分析。

mbedOS的延时响应测试工程采用SD-mbedOS工程框架[22],在Kinetis Design Studio 3.0.0 IDE集成开发环境和基于Cortex-M4内核的STM32微控制器[23]上进行测试。Stm32片内Flash大小为256 kByte,主要用于中断向量和程序代码等的保存;片内RAM大小为32 kByte,主要用于各类变量的存储。

4.1 功能设计

测试工程的功能是由主线程创建3个优先级相同的用户线程,分别为红灯线程、蓝灯线程和绿灯线程,红灯线程与串口采用事件进行通信,绿灯线程每隔10 s实现绿灯闪烁一次;蓝灯线程每隔5 s实现蓝灯闪烁一次,测试工程的执行流程如图7所示。

图7 测试工程执行流程Fig.7 Test engineering execution process

4.2 流程分析

在测试工程中,先后共创建了6个线程,其相关信息如表2所示。在启动mbedOS的过程中依次创建了主线程、空闲线程和定时器线程,且为就绪态,都被放入到就绪队列中[24]。由于此时内核中无其他线程,且定时器线程的优先级最高,因此会触发SVC中断进行第1次上下文切换,将定时器线程作为当前线程且恢复其上下文信息。当定时器线程被调度执行时,会因为获取消息失败而被阻塞,此时从就绪队列取出主线程作为当前线程,触发SVC中断进行第2次上下文切换,保存定时器线程的上下文,同时恢复主线程的上下文。当主线程被调度执行时,依次创建和启动红灯线程、蓝灯线程和绿灯线程3个优先级相同的线程,之后主线程也被阻塞。此时,在就绪队列中剩下红灯线程、蓝灯线程、绿灯线程和空闲线程这4个线程。

表2 线程信息一览表Tab.2 Thread information list

由于红灯线程最先被启动且优先级与蓝灯线程、绿灯线程相同,因此它被最先取出触发SVC中断与主线程进行第3次上下文切换,然后被调度执行。之后,红灯线程、蓝灯线程和绿灯线程由于优先级相同将按时间片轮询方式被调度执行,当这3个线程因延时或等待事件位,会被放入到延时等待列表和事件阻塞列表,此时空闲线程被调度执行。当蓝灯线程和绿灯线程因延时到期,由于它们的优先级大于空闲线程的优先级,所以会在SysTick中断期间从延时列表移出并放到就绪列表中,按优先级抢占方式进行上下文切换,之后被调度执行。当产生串口接收中断时,先挂起PendSV中断,当串口中断执行结束后,会触发PendSV中断设置红灯线程等待的事件位,将红灯线程从等待列表和事件阻塞列表移出并放到就绪列表中,然后进行上下文切换,之后红灯线程被调度执行。整个测试工程的运行结果如图8所示,从图8中可以看到SVC中断、PendSV中断和SysTick中断对线程的调度情况。

图8 3种中断的线程调度情况Fig.8 Thread scheduling of three interrupts

5 结 语

RTOS的最主要功能之一就是线程调度,调度策略的优劣直接影响到RTOS的实时性。笔者在分析ARM Cortex-M4内核对RTOS的支持特性和分析RTOS常用调度机制的基础上,给出了mbedOS对调度策略的实现方法。实践表明,SVC中断、PendSV中断和SysTick中断3种调度实现方法能有效地实现线程上下文切换。通过对mbedOS的调度策略和实现方法的剖析,有助于加深对线程调度的理解,为分析其他实时操作系统提供借鉴。

猜你喜欢
寄存器线程内核
5G终端模拟系统随机接入过程的设计与实现
多内核操作系统综述①
实时操作系统mbedOS 互斥量调度机制剖析
浅析体育赛事售票系统错票问题的对策研究
强化『高新』内核 打造农业『硅谷』
活化非遗文化 承启设计内核
Lite寄存器模型的设计与实现
常用电子测速法在某数字信号处理器中的应用*
微软发布新Edge浏览器预览版下载换装Chrome内核
移位寄存器及算术运算应用