LiteOS的任务是调度执行的最小单元,主要按照优先级抢占,辅以时间片轮转的方式进行调度。任务的操作和维护保护创建、删除、调用、挂起、恢复、切换、sleep等等。任务间的交互可以通过消息或事件进行,同时支持使用互斥锁MUX或信号量semphore来进行活动的互斥同步。任务可以分为不同的优先级,优先级用0-31表示,其中0为最高优先级。
系统的启动
理解上从vendor.s文件__vector_table开始运行,首先初始化MSP的地址,然后调用Reset_Handler函数,在reset函数中跳转__iar_program_start,然后进入main函数,没有找到__iar_program_start具体的说明?在main函数中进行了内存、任务等初始化,随后启动系统任务开始调度。
vendor.s只是系统刚启动时运行,而对于中断向量函数表,在初始化时配置OS_NVIC_VTOR寄存器进行重新定位。
关于中断
在CortexM4上存在256中断号,支持多个优先级配置,16-255为可配置的IRQ,0-15依次分别为栈顶位置(MSP?)、复位、NMI(不可屏蔽中断)、硬件错误、memory管理错误、总线错误、使用错误(指令或处理器状态转换)、7-10保留、SVC、调用监控(用于软件调试)、13保留、PendSV(用于任务上下文切换)、sysTick(系统时间片调度)。
为了某些特殊情况下禁止中断的响应,M4有三个特殊的寄存器PRIMASK\FAULTMASK\BASEPRI,能够在特权模式下访问;其中PRIMASK可用来禁止除了NMI和HardFault以外中断;FAULTMASK用来屏蔽除了NMI以外的中断;而BASEPRI用于禁止一些优先级比较低的中断。
任务优先级实现
#define LOS_PRIORITY_QUEUE_PRIORITYNUM 32
LITE_OS_SEC_BSS LOS_DL_LIST *g_pstLosPriorityQueueList;//g_pstLosPriorityQueueList通过malloc对应LOS_PRIORITY_QUEUE_PRIORITYNUM大小的存储块。LiteOS实现中对每一个优先级的任务使用了一个链表,当任务需要切换时,则从g_pstLosPriorityQueueList高优先级任务队列开始查找需要执行的任务。
时间片轮转
关于时间片:基于Tick来处理,Tick时钟在Cortex M4环境中通过SysTick Control的相关寄存器来配置。SysTick是基于clk来计数,所以配置SysTick时根据系统的主频以及自定义的Tick时长来计算。在正确配置SysTick寄存器的基础上,每个Tick会产生一个中断,中断号为15。在Tick的中断服务程序中,进行时间片的计算,软件定时器的处理等,所以软件定时器的精度和Tick的精度有一定依赖性。
在任务运行达到系统设定的时间片Tick数目时,可进行显示的放权,进而调用其他任务,已达到时间片轮转的目的。
互斥锁与信号量
liteOS中都采用PV操作,即PV操作(pend post)。主要差别在于信号量允许多个任务重入,在创建信号量时,可以设置最大重入次数。
任务上下文的切换
所谓任务的上下文切换,理解上是在任务切换时,对任务当前环境变量进行保存,以便于任务切换回来时恢复现有状态。
任务的上下文切换,在中断PendSV的服务程序中实现,理解上好处:在中断处理避免了在线程中处理时,中断打断上下文切换的需要处理情况。ICSR(Interrupt Control and State Register)使得用户在需要进行上下文切换时可以配置相应寄存器,以达到触发PendSV中断的目的。
任务堆栈的实现
在cortexM4系统中存在两种堆栈:MSP、PSP,亦即主堆栈指针及进程堆栈指针,在进入中断处理服务程序时用MSP,而在用户线程运行时需要使用PSP。在cortexM4中可以通过配置CONTROL寄存器的方式来选择MSP或PSP。CONTROL寄存器的定义:CONTROL[0]:0-特权级线程,1-用户级线程,在中断处理服务程序中用于为特权级线程;CONTROL[1]:0-选择主堆栈指针MSP,1-选择进程堆栈指针PSP。对于特殊寄存器的控制需要使用特殊的MSR/MRS指令进行操作,所以一般相关代码需要汇编实现,在liteOS中最底层任务相关汇编函数放在dispatch.s中。
消息队列与事件
消息队列顾名思义就是先进先出FIFO,LiteOS中消息队列可以用来在不同任务之间进行数据的交互。而事件event用来各个任务的同步,相对每个任务只能读取一个消息队列的限制,事件没有这样的要求,但同时事件不提供任务间的数据传输功能。理解上事件更像与多个任务的独立的存在,而消息队列却具有一定的相关性。在LiteOS中消息队列和事件都支持超时机制,当然超时可以设置成两种极限情形:立即响应和用于等待。