Bootstrap

24、【OS】【Nuttx】最小系统初始化分析(3):任务调度(一)

背景

回顾之前wiki:
22、【OS】【Nuttx】最小系统初始化分析(1):任务创建
23、【OS】【Nuttx】最小系统初始化分析(2):任务跳转
已经分析了任务创建时,如何分配空间;以及轮到任务执行时,如何跳转。
这里主要分析如何轮到任务执行,即任务调度策略

任务状态

在任务列表初始化函数 tasklist_initialize 中,可以看到各任务状态列表所用的变量,这里最小系统主要关注前两个任务状态 ready to run (Ready任务)和 pending tasks(Pending任务)。
在这里插入图片描述在这里插入图片描述
查看 g_readytorun 定义,可以了解到 Ready 任务是一个按优先级排序的列表,其头部 head 里存放的永远是最高优先级的任务,而尾部 tail 里存放的,永远是 idle 任务(优先级最低)。
在这里插入图片描述
Ready 任务意味着该任务已经完全做好了运行准备,只要时机一到,比如某个任务执行完退出,调度器开始寻找下一个任务时,就会直接从 Ready 任务里面取出下一个任务执行。
在这里插入图片描述
查看 g_readytorun 的类型声明,为双链表的数据结构,这里 dq 表示 double queue,sq 表示 single queue。由于链表内存放的是任务控制块 tcb_s,故在使用时,需将 flink 和 blink,head 和 tail 指针强转成 tcb_s 类型
在这里插入图片描述
如果查看 tcb_s 的类型声明,可以发现其本质也是双链表的数据结构,所以为什么不直接用 tcb_s 类型定义 g_readytorun 呢?
在这里插入图片描述
其实观察 tcb_s 类型和 dq_queue_s 不难发现,其前两个成员都是相同的,都是 flink 和 blink,都是指向下一个和上一个链表的指针,所以实际上,dq_queue_s 类型就是 tcb_s 类型的阉割版,dq_queue_s 类型能完成的功能,tcb_s类型当然也能完成。但是从设计上说,tcb_s 的主要职责是负责存储任务控制信息,而不是充当任务队列;如果 tcb_s 既存储任务控制信息,又负责任务队列,就违反了软件工程中的单一职责原则。将任务队列管理与任务控制块本身分离,可以更容易地专注于各自功能领域,提高代码可读性和可维护性,是更好的设计实践。
在这里插入图片描述

Ready任务

下面来分析Nuttx中 Ready 任务比较关键的部分,任务更新
1、在 idle_task_initalize 中,ready 任务队列迎来第一个任务 idle task
在这里插入图片描述
2、下面对 Ready 任务最关键的,nxsched_merge_pending:
该任务会将 Pending 队列中满足条件的任务合入到 Ready 队列中,并按优先级从高到低对任务进行排序。如果 Ready 队列中的 head 任务发生改变,意味着有任务已经准备就绪,CPU 应该立刻切换上下文,并立刻执行该 head 任务(这里切换上下文就意味着任务跳转,对任务跳转不熟悉的可以参考上一篇wiki 23、【OS】【Nuttx】最小系统初始化分析(2):任务跳转
这里函数有个很重要的假设,即调用者需进入临界区(就是关中断),防止在任务进行优先级排序的时候,有中断进来,往 Ready 队列里面插任务,导致队列优先级紊乱,这对于优先级队列很重要。
在这里插入图片描述
首先从 Ready 队列里面,取出 head 任务,能调用到这个函数,说明调用者已经使用完了CPU资源,现在正准备释放,而此时调用者就是这个 head 任务(对于单核系统来说,目前 SIM 环境为单核)。取出 head 任务后,首先查看此时 head 任务是否被抢占,至于这个 islocked 函数和抢占有什么关系?下面会分析
在这里插入图片描述
这里 SMP 的英文全称是 Symmetric MultiProcessing:

  • Symmetric:对称的,意味着每个处理器在系统中具有相同的地位和功能。
  • MultiProcessing:多处理,指的是使用多个处理器来执行任务

!defined(CONFIG_SMP) 即非多核,这里默认分析单核系统
在这里插入图片描述
查看 islocked 定义,可以看到当 lockcount 为0时,当前的 head 任务才可被抢占,意思是这时候调度器才可以把 Pending 队列里面的任务搬运到 Ready 任务里边来,否则 head 任务就会一直执行,即使调了 nxsched_merge_pending 这个任务也不行,直到 lockcount 等于0为止,才会允许调度器把 CPU 资源分配给其他任务。
在这里插入图片描述
在这里插入图片描述
lockcount 机制也叫抢占锁定机制(Preemption Locking),这机制允许同一个任务可以进行嵌套锁操作,即多次对同一个任务进行资源锁定。这样保证了特定任务可以不被其他任务打断,以确保某些关键操作能够原子性地完成,不受到其他任务的干扰。
在这里插入图片描述
暂时先分析到这儿,后面再接着分析

;