现在的位置: 首页 > 综合 > 正文

ucos-II 任务调度源码分析(一)

2012年10月05日 ⁄ 综合 ⁄ 共 2096字 ⁄ 字号 评论关闭

ucos-II 源码概述

操作系统最原始的功能在于对上层应用提供统一的硬件资源管理,这里的硬件资源包括CPU、内存、存储(文件系统)、外设(驱动管理)等等。从这个角度讲,ucos-II操作系统(针对v2.0版本的源码)只管理了两个资源:CPU的计算能力和内存。因此,个人理解可以把ucos-II的内核代码从功能角度分成以下几块:

  • 针对CPU计算能力的管理:主要是任务调度和中断的支持;在ucos-II内核中触发任务的转换主要有三种情况:

    • 任务状态的改变,主要由任务间同步和通信的功能,在等待某一个资源时触发(XXPend),在释放某一个资源时结束(XXPost);
    • 延时,通过改变任务结构体中的延时标志变量,在OSTimeDly中触发,在系统周期的时钟回调OSTimeTick中轮询判断是否结束;
    • 中断,此中断由用户自己实现;
  • 在任务调度基础上增加的任务同步(信号量、互斥信号量、事件标志组)与任务间通信(消息队列、消息邮箱);
  • 内存管理,这块在ucos-II里非常简单,只是支持将连续内存设计成一个内存块的链表进行管理;
  • 将上述功能模块中,与CPU强相关的提取出来,主要是上下文切换中寄存器、堆栈的处理;

此系列文章主要记录个人对ucos-II源码的理解和《嵌入式实时操作系统ucos-II》的笔记。

1. ucos-II中的任务

ucos-II中的任务有两个特点或者说约束和它内核的实现是强相关的,一是任务必须是无限循环的,因为系统在运行的过程中永远是从一个任务的代码段跳转到另外一个任务的代码段;二是每个任务对应一个优先级,这个优先级是全局唯一的。ucos-II中的每个任务定义成一个有限状态机:

  • 睡眠态:初始状态,任务还为被加载;
  • 就绪态:调用OSTaskCreate,任务被初始化等待内核选择并运行;
  • 运行态:OSStat调用后,就绪态中优先级最高的任务进入运行态;
  • 等待状态:运行态的任务调用了延时、任务同步/通信(XXpend)后进入等待状态;(这是ucos进行任务调度的主要机制,否则高优先级的任务就一直运行了。但mutex除外,它是依靠优先级的调整触发调度的)
  • 中断服务状态:这个状态感觉没有用到??

2. ucos-II的任务调度

ucos-II任务调度相关的全局变量:

OS_EXT  OS_TCB  *OSTCBCur;    /* Pointer to currently running TCB         */
OS_EXT  OS_TCB *OSTCBFreeList;  /* Pointer to list of free TCBs             */
OS_EXT  OS_TCB *OSTCBHighRdy;  /* Pointer to highest priority TCB R-to-R   */
OS_EXT  OS_TCB *OSTCBList;  /* Pointer to doubly linked list of TCBs    */
OS_EXT  OS_TCB *OSTCBPrioTbl[OS_LOWEST_PRIO + 1]; /* Table of pointers to created TCBs        */
OS_EXT  OS_TCB OSTCBTbl[OS_MAX_TASKS + OS_N_SYS_TASKS];   /* Table of TCBs                  */
OS_EXT  INT8U OSPrioCur; /* Priority of current task                        */
OS_EXT  INT8U OSPrioHighRdy;  /* Priority of highest priority task */

OS_EXT  INT8U OSRdyGrp;  /* Ready list group                         */
OS_EXT  INT8U OSRdyTbl[OS_RDY_TBL_SIZE];   /* Table of tasks which are ready to run    */

ucos利用上述全局变量进行任务调度,原理如下:

1. OSRdyTbl[OS_RDY_TBL_SIZE]:优先级这换成一个8*8的2维数组,代表该优先级是否存在就绪的任务;

2. OSRdyGrp: 00 yyy xxx,Y和X分别对应OSRDYTbl中的纵坐标和横坐标的索引;

举例:当前新增优先级为20的任务,0x00010100, yyy = 010, xxx = 100

通过查找OSMapTbl常量表,得出OSRdyTbl坐标索引为第三行、第五列;置位表相应位置为1;

再新增优先级为30的任务,0x00011110,yyy = 011,xxx = 110,置位表第四行、第七列为1;

OSRdyGrp更新为0x00011110,(0x00010100与0x00011110取或)。

当任务调度时,通过OSRdyGrp和OSRdyTbl的值,查找OSUnMapTbl常量表得到当前就绪表中的最高优先级。

 y  = OSUnMapTbl[OSRdyGrp]; /* Get pointer to HPT ready to run              */
//得到高优先级就绪态的任务指针
OSPrioHighRdy = (INT8U)((y << 3) +OSUnMapTbl[OSRdyTbl[y]]);

上述就是ucos-II判断当前最高优先级就绪任务的算法,本质上它也可以去选择遍历就绪队列链表,但由于RTOS的实时性要求采用了这样一个非常巧妙的查表算法。

 

 

 

 

 

抱歉!评论已关闭.