本篇主要内容

本篇的主要内容为:按照老师提供的实现路线进行开发时的设计、实现以及所遇到的问题

一、二阶段开发记录

关于入队列的变动

embassy里面是直接采用头插法将新的task_ref插入,从而更新run-queue链表,而仔细想想,我们的抢占式设计是不需要一个run-queue链表的,我们通过arena分配给taskstorage相应的空间过后,只需要保存它的指针到以数组里面即可(这个数组就相当于ucosii的OSTCBPRIO数组)

之所以没有了一个freelist和tcblist维护分配信息,是因为分配的过程是由arena进行动态分配的,因为任务的大小不一样,但是很致命的一点是arena没办法对分配的任务(taskstorage)进行回收,尽管在嵌入式的情况来看,的确不需要,因为每个任务应该都是一个死循环,永远不会退出,所以也就不存在回收的问题。

如果是这样的话,我们目前可以去掉下面这两个TCB的成员,因为不需要维护一个tcb的链表

 OSTCBNext: SyncUnsafeCell<Option<OS_TCB_REF>>, /* Pointer to next     TCB in the TCB list                 */
 OSTCBPrev: SyncUnsafeCell<Option<OS_TCB_REF>>, /* Pointer to previous TCB in the TCB list                 */

所以我们只需要一个以优先级为下标索引到OS_TCB_REF的数组,这个数组可以就放到全局的executor里面,同时还有位图的部分也应该放进去,主要是OSRdyGrp和OSRdyTbl

Poll to UNready

在执行器里面采取这样的机制:

原来的embassy是poll的时候将整个队列里面的元素都按顺序poll一遍,并且从就绪队列里面删除。现在的思路是:

  1. 首先没有抢占的情况:所有的任务都会poll一次,然后poll到await点的地方,就会返回,然后由executor将该任务重新设置为非就绪状态(i.e. 更新位图),然后根据位图找到下一个最高优先级任务去执行
  2. 再考虑加上抢占的情况:任务如果是在poll过程中被打断,executor不会更新它的位图,仍然该任务处于就绪状态,保存上下文后,切换到更高优先级任务执行。而如果在poll执行完,由执行器正在处理更新位图,以及查找下一个最高优先级的调度过程的时候,我们打算将这个地方设置为临界区,这样保证这里不会发生中断,中断只能发生在查找到并且转入下一个最高优先级任务之后的时候。

执行流程

原来的embassy的方式是:一次执行器的poll执行当前runqueue的所有任务,中途有就绪的任务会加入到“新”的runqueue(其实是原来的runqueue,只是runqueue在执行第一个任务时就会被清空),然后被poll的任务如果await了,就会自然的走到下一个任务执行。

而我们这里取消掉一次性poll完任务,而是一次poll一个任务,完成之后,将该任务设置为非就绪态,然后转到最高优先级任务执行,这里很重要的一点就是这里对于临界区的设置:

对于位图的所有操作都需要加在临界区里面完成:

我们的临界区应该这里需要包含:设置当前任务在位图中为非就绪, 查找位图找到最高优先级,并且设置OSCURPRIO为这个优先级