打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Raw-OS源码分析之系统初始化

        分析的内核版本截止到2014-04-15,基于1.05正式版,blogs会及时跟进最新版本的内核开发进度,若源码注释出现”???”字样,则是未深究理解部分。

        Raw-OS官方网站:http://www.raw-os.org/

        Raw-OS托管地址:https://github.com/jorya/raw-os/


        1.双向链表定义

        首先关注Raw-OS源码中的/include/list.h,这个文件描述系统使用的关于双向链表的定义和操作,学SW的数据结构都接触过,无奈骚年我学的是电子专业,出来之后混的是软件方面,所以现在各种纠结。

        下面就对这些关于链表的操作抽象出来理解

        Raw-OS使用的双向链表是这样定义的

  1. /* 
  2.  * 双向链表 
  3.  */  
  4. typedef struct LIST {  
  5.   /* 链表后向指针 */  
  6.     struct LIST *next;  
  7.   /* 链表后继指针 */  
  8.     struct LIST *previous;  
  9. } LIST;  



        关于链表的初始化,插入,删除的常规操作都有定义,非常简单

        初始化:

  1. /* 
  2.  * 链表初始化,链表头前向和后继指针均指向链表头 
  3.  */  
  4. RAW_INLINE void list_init(LIST *list_head)  
  5. {  
  6.     list_head->next = list_head;  
  7.     list_head->previous = list_head;  
  8. }  

        双向链表插入:

  1. /* 
  2.  * 在链表头前向增加element,从图里面观察得到,其实在head之前插入, 
  3.  * 就是插入到以head为头的双向链表的末端 
  4.  * 
  5.  * 那么head->next会是双向链表的第一个元素,head->previous则是最后一个元素 
  6.  */  
  7. RAW_INLINE void list_insert(LIST *head, LIST *element)  
  8. {  
  9.   
  10.     element->previous = head->previous;  
  11.     element->next = head;  
  12.   
  13.     head->previous->next = element;  
  14.     head->previous = element;  
  15. }  



        简化之后:



        删除操作简单得多:

  1. RAW_INLINE void list_delete(LIST *element)  
  2. {  
  3.   
  4.     element->previous->next = element->next;  
  5.     element->next->previous = element->previous;  
  6.   
  7. }  


        2.系统任务创建

        raw_task_create(......)函数是Raw-OS系统API级的函数,目的是创建任务控制块

        例如创建一个autorun的任务:



        创建任务时创建任务控制块,然后初始化TCB内容,然后加入到就绪队列中,就绪队列类似hash表,具体形式如下:



        就绪队列的表大小系统默认是256项,而每一项是一个双向List表头,由此可见就绪队列是有256项的双向链表。

        那么,加入现在创建一个优先级是2的任务,创建任务的时候,就会在raw_ready_queue[2]中添加对应的element,如果再创建一个优先级是2的任务时,又会在raw_ready_queue[2]中添加一项


        至于具体的任务建立的代码如下,添加了注释:

  1. RAW_U16 raw_task_create(RAW_TASK_OBJ  *task_obj, RAW_U8  *task_name,  RAW_VOID   *task_arg,  
  2.                              RAW_U8  task_prio,  RAW_U32  time_slice,  PORT_STACK  *task_stack_base,  
  3.                              RAW_U32 stack_size, RAW_TASK_ENTRY task_entry, RAW_U8 auto_start)  
  4.   
  5. {  
  6.     PORT_STACK *p_stack;  
  7.     RAW_U32 i;  
  8.   
  9.     /* 移植相关,定义存放一个CPU状态寄存器的临时变量,一般是unsigned int */  
  10.     RAW_SR_ALLOC();  
  11.   
  12.     #if (RAW_TASK_FUNCTION_CHECK > 0)  
  13.     /* 检查任务obj,未定义任务控制块时返回 */  
  14.     if (task_obj == 0) {  
  15.         return RAW_NULL_OBJECT;  
  16.     }  
  17.     /* 检查任务优先级范围大小,越界返回 */  
  18.     if (task_prio >= CONFIG_RAW_PRIO_MAX) {  
  19.         return RAW_BYOND_MAX_PRIORITY;  
  20.     }  
  21.     /* 检查任务堆栈地址,未定义堆栈时返回 */  
  22.     if (task_stack_base == 0) {  
  23.         return RAW_NULL_POINTER;  
  24.     }  
  25.     /* 检查任务函数实体,未定义任务入口函数时返回 */  
  26.     if (task_entry == 0) {  
  27.         return RAW_NULL_POINTER;  
  28.     }  
  29.     /* 检查是否在中断嵌套中,不能在中断中创建任务??? */  
  30.     if (raw_int_nesting) {  
  31.         return RAW_NOT_CALLED_BY_ISR;  
  32.     }  
  33.     #endif  
  34.   
  35.     /* 禁止系统中断,作用??? */  
  36.     RAW_CRITICAL_ENTER();  
  37.     /* 检查是否创建系统IDLE任务,如果IDLE任务已创建,返回,只允许一个IDLE任务存在 */  
  38.      if (task_prio == IDLE_PRIORITY) {  
  39.         if (idle_task_exit) {  
  40.             /* 使能系统中断 */  
  41.             RAW_CRITICAL_EXIT();  
  42.             return RAW_IDLE_EXIT;  
  43.         }  
  44.         idle_task_exit = 1u;  
  45.     }  
  46.   
  47.     /* 同IDLE任务,系统只允许一个task 0存在 */  
  48.     #if (CONFIG_RAW_TASK_0 > 0)  
  49.      if (task_prio == 0) {  
  50.         if (task_0_exit) {  
  51.             RAW_CRITICAL_EXIT();  
  52.             return RAW_TASK_0_EXIT;  
  53.         }  
  54.         task_0_exit = 1u;  
  55.     }  
  56.     #endif  
  57.   
  58.     /* 使能系统中断 */  
  59.     RAW_CRITICAL_EXIT();  
  60.   
  61.     /* 对分配的任务控制块的内存空间初始化为全0 */  
  62.     raw_memset(task_obj, 0, sizeof(RAW_TASK_OBJ));  
  63.   
  64.     /* 系统调度方式FIFO无时间片???RR方式按时间片??? */  
  65.     #if (CONFIG_SCHED_FIFO_RR > 0)  
  66.     /* 如果创建任务提供有time_slice参数,则初始化任务时间片为自定义时间片,否则系统默认50 */  
  67.     if (time_slice) {  
  68.         task_obj->time_total        = time_slice;  
  69.     }  
  70.     else  {  
  71.         task_obj->time_total        = TIME_SLICE_DEFAULT;  
  72.     }  
  73.     task_obj->time_slice = task_obj->time_total;  
  74.     /* 设置任务调度方式 */  
  75.     task_obj->sched_way = SCHED_RR;  
  76.     #endif  
  77.   
  78.     /* 如果定义任务时设置autorun为1,任务状态设为就绪态,否则设为挂起态,在应用层要手动唤醒任务 */  
  79.     if (auto_start) {  
  80.         task_obj->task_state = RAW_RDY;  
  81.     }  
  82.     else {  
  83.         task_obj->task_state = RAW_SUSPENDED;  
  84.         /* 挂起时任务挂起计数+1 */  
  85.         task_obj->suspend_count = 1u;  
  86.     }  
  87.   
  88.     /* 初始化任务堆栈内存空间为0 */  
  89.     task_obj->task_stack_base = task_stack_base;  
  90.     p_stack = task_stack_base;  
  91.     for (i = 0; i < stack_size; i++) {  
  92.         *p_stack++ = 0;  
  93.     }  
  94.   
  95.     /* 调用创建任务的hook函数 */  
  96.     #if (CONFIG_RAW_USER_HOOK > 0)  
  97.     task_create_hook(task_obj);  
  98.     #endif  
  99.   
  100.     /* 移植相关,任务创建时的手动模拟堆栈初始化 */  
  101.     task_obj->task_stack = port_stack_init(task_stack_base, stack_size, task_arg, task_entry);  
  102.     /* 设置TCB中任务名称、优先级、堆栈大小信息 */  
  103.     task_obj->task_name  = task_name;  
  104.     task_obj->priority   = task_prio;  
  105.     task_obj->bpriority  = task_prio;  
  106.     task_obj->stack_size = stack_size;  
  107.   
  108.     /* 向trace系统加入当前任务调试代码??? */  
  109.     TRACE_TASK_CREATE(task_obj);  
  110.   
  111.     /* 又禁止系统中断,作用??? */  
  112.     RAW_CRITICAL_ENTER();  
  113.   
  114.     /* 将任务堆栈检查list加入系统监控??? */  
  115.     #if (RAW_SYSTEM_CHECK > 0)  
  116.     list_insert(&(system_debug.task_head), &task_obj->stack_check_list);  
  117.     #endif  
  118.   
  119.     /* 如果创建任务时选择任务自动运行,立即添加到系统就绪链表的末端等待系统调度 */  
  120.     if (auto_start) {  
  121.         add_ready_list_end(&raw_ready_queue, task_obj);  
  122.     }  
  123.   
  124.     /* 如果此时系统状态为stopped,即未运行时,返回 */  
  125.     if (raw_os_active !=  RAW_OS_RUNNING) {  
  126.         RAW_CRITICAL_EXIT();  
  127.         return RAW_OS_STOPPED;  
  128.     }  
  129.   
  130.     RAW_CRITICAL_EXIT();  
  131.   
  132.     /* 如果系统状态为RAW_OS_RUNNING,则马上进行系统调度,即系统运行时创建任务会马上执行调度 */  
  133.     if (auto_start) {  
  134.         raw_sched();  
  135.     }  
  136.   
  137.     return RAW_SUCCESS;  
  138. }  

        3.系统初始化

        好,有上两步的基础,接下来看看系统初始化做了哪些工作




        看来做了相当多的工作啊啊啊啊啊......直接看代码注释吧,说多也无益,这里tick list和就绪队列的形式是相似的,不过系统默认大小为8,这个tick list和任务超时有关,后续分析会分析到



  1. RAW_U16 raw_os_init(void)  
  2. {  
  3.     /* trace系统初始化,还不知道作用在哪??? */  
  4.     TRACE_INIT();  
  5.   
  6.     /* 此时系统未运行,设置系统运行状态为stopped */  
  7.     raw_os_active = RAW_OS_STOPPED;  
  8.     /* 初始化就绪队列 */  
  9.     run_queue_init(&raw_ready_queue);  
  10.   
  11.     /* 初始化tick链表 */  
  12.     tick_list_init();  
  13.   
  14.     /* 初始化系统调试XX表,这是神马东西?有毛作用??? */  
  15.     #if (RAW_SYSTEM_CHECK > 0)  
  16.     list_init(&(system_debug.task_head));  
  17.     #endif  
  18.   
  19.     /* 调用自定义系统初始化hook函数 */  
  20.     #if (CONFIG_RAW_USER_HOOK > 0)  
  21.     raw_os_init_hook();  
  22.     #endif  
  23.   
  24.     /* 创建系统空闲任务,IDLE任务是最低优先级任务,必须存在IDLE任务??? */  
  25.     raw_task_create(&raw_idle_obj, (RAW_U8  *)"idle_task",  0,  
  26.                                     IDLE_PRIORITY, 0,  idle_stack,  
  27.                                     IDLE_STACK_SIZE,  raw_idle_task, 1);  
  28.   
  29.     /* 系统软件定时器初始化??? */  
  30.     #if (CONFIG_RAW_TIMER > 0)  
  31.     raw_timer_init();  
  32.     #endif  
  33.   
  34.     /* 系统最高优先级任务task 0初始化???这又有毛用??? */  
  35.     #if (CONFIG_RAW_TASK_0 > 0)  
  36.     raw_task_0_init();  
  37.     #endif  
  38.   
  39.     /* 系统时钟任务(tick任务)初始化,tick任务优先级为1,单独封装tick任务好处??? */  
  40.     #if (CONFIG_RAW_TICK_TASK > 0)  
  41.     tick_task_start();  
  42.     #endif  
  43.   
  44.     /* CPU统计任务初始化??? */  
  45.     #if (RAW_CONFIG_CPU_TASK > 0)  
  46.     cpu_task_start();  
  47.     #endif  
  48.   
  49.     return RAW_SUCCESS;  
  50. }  

        4.系统启动

        最后就是启动系统,寻找第一个最高优先级任务,开始任务调度,这里说说list_entry这个宏,稍微看过linux代码的同学们就知道container_of这个宏,目的是通过某个结构体中的成员逆运算得出成员所属结构的地址,在Raw-OS中的list_entry作用是类似的

        例如,注意到就绪队列中链表的元素是List,也就是说,创建自动运行任务时不是直接吧任务控制块直接添加到就绪队列中,而是把TCB中的tasklist成员添加到就绪队列,那么当从就绪队列中找到最高优先级任务的TCB时,就需要通过tasklist成员逆运算找到TCB的入口地址,所以整个过程如下:



        那么在系统启动时就有这样的过程



        具体看系统启动的代码

  1. RAW_U16 raw_os_start(void)  
  2. {  
  3.     /* 如果当前系统处于stopped状态,开始任务调度 */  
  4.     if (raw_os_active == RAW_OS_STOPPED) {  
  5.         /* 从就绪队列取出队列中的最高优先级任务 */  
  6.         get_ready_task(&raw_ready_queue);  
  7.   
  8.         /* 移植部分相关,当前活动任务设为最高优先级任务,系统状态为running */  
  9.         raw_task_active = high_ready_obj;  
  10.         raw_os_active = RAW_OS_RUNNING;  
  11.         /* 移植部分相关,执行第一个最高优先级任务调度 */  
  12.         raw_start_first_task();  
  13.     }  
  14.   
  15.     else {  
  16.         /* 如果系统处于运行状态,调用此函数时,返回running标志 */  
  17.         return RAW_OS_RUNNING;  
  18.   
  19.     }  
  20.   
  21.     /* 永不执行返回? */  
  22.     return RAW_SYSTEM_ERROR;  
  23.   
  24. }  


        那么,整个系统初始化过程就可以这样理解



        而在应用层代码中,必要的初始化代码就这样写:

  1. int main(void){  
  2.     /* 硬件初始化代码 */  
  3.     ......  
  4.   
  5.     /* Raw-OS系统初始化 */  
  6.     raw_os_init();  
  7.   
  8.     /* 建立自定义任务 */  
  9.     ......  
  10.   
  11.     /* Raw-OS系统启动 */  
  12.     raw_os_start();  
  13.   
  14.     /* 永不执行返回操作 */  
  15.     return 0;  
  16. }  


本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
μC/OS-Ⅱ的主要特点_μC/OS-II实时操作系统概述
ucos 任务的基本概念
Task之任务的创建
基于ARM和μC/OS-II的人造提花毛皮机控制系统 - 21IC中国电子网
AUTOSAR之操作系统概览
基于MSP430单片机的实时多任务操作系统
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服