分析的内核版本截止到2014-04-15,基于1.05正式版,blogs会及时跟进最新版本的内核开发进度,若源码注释出现”???”字样,则是未深究理解部分。
Raw-OS官方网站:http://www.raw-os.org/
Raw-OS托管地址:https://github.com/jorya/raw-os/
首先关注Raw-OS源码中的/include/list.h,这个文件描述系统使用的关于双向链表的定义和操作,学SW的数据结构都接触过,无奈骚年我学的是电子专业,出来之后混的是软件方面,所以现在各种纠结。
下面就对这些关于链表的操作抽象出来理解
Raw-OS使用的双向链表是这样定义的
/* * 双向链表 */ typedef struct LIST { /* 链表后向指针 */ struct LIST *next; /* 链表后继指针 */ struct LIST *previous; } LIST;
关于链表的初始化,插入,删除的常规操作都有定义,非常简单
初始化:
/* * 链表初始化,链表头前向和后继指针均指向链表头 */ RAW_INLINE void list_init(LIST *list_head) { list_head->next = list_head; list_head->previous = list_head; }
双向链表插入:
/* * 在链表头前向增加element,从图里面观察得到,其实在head之前插入, * 就是插入到以head为头的双向链表的末端 * * 那么head->next会是双向链表的第一个元素,head->previous则是最后一个元素 */ RAW_INLINE void list_insert(LIST *head, LIST *element) { element->previous = head->previous; element->next = head; head->previous->next = element; head->previous = element; }
简化之后:
删除操作简单得多:
RAW_INLINE void list_delete(LIST *element) { element->previous->next = element->next; element->next->previous = element->previous; }
raw_task_create(......)函数是Raw-OS系统API级的函数,目的是创建任务控制块
例如创建一个autorun的任务:
创建任务时创建任务控制块,然后初始化TCB内容,然后加入到就绪队列中,就绪队列类似hash表,具体形式如下:
就绪队列的表大小系统默认是256项,而每一项是一个双向List表头,由此可见就绪队列是有256项的双向链表。
那么,加入现在创建一个优先级是2的任务,创建任务的时候,就会在raw_ready_queue[2]中添加对应的element,如果再创建一个优先级是2的任务时,又会在raw_ready_queue[2]中添加一项
至于具体的任务建立的代码如下,添加了注释:
RAW_U16 raw_task_create(RAW_TASK_OBJ *task_obj, RAW_U8 *task_name, RAW_VOID *task_arg, RAW_U8 task_prio, RAW_U32 time_slice, PORT_STACK *task_stack_base, RAW_U32 stack_size, RAW_TASK_ENTRY task_entry, RAW_U8 auto_start) { PORT_STACK *p_stack; RAW_U32 i; /* 移植相关,定义存放一个CPU状态寄存器的临时变量,一般是unsigned int */ RAW_SR_ALLOC(); #if (RAW_TASK_FUNCTION_CHECK > 0) /* 检查任务obj,未定义任务控制块时返回 */ if (task_obj == 0) { return RAW_NULL_OBJECT; } /* 检查任务优先级范围大小,越界返回 */ if (task_prio >= CONFIG_RAW_PRIO_MAX) { return RAW_BYOND_MAX_PRIORITY; } /* 检查任务堆栈地址,未定义堆栈时返回 */ if (task_stack_base == 0) { return RAW_NULL_POINTER; } /* 检查任务函数实体,未定义任务入口函数时返回 */ if (task_entry == 0) { return RAW_NULL_POINTER; } /* 检查是否在中断嵌套中,不能在中断中创建任务??? */ if (raw_int_nesting) { return RAW_NOT_CALLED_BY_ISR; } #endif /* 禁止系统中断,作用??? */ RAW_CRITICAL_ENTER(); /* 检查是否创建系统IDLE任务,如果IDLE任务已创建,返回,只允许一个IDLE任务存在 */ if (task_prio == IDLE_PRIORITY) { if (idle_task_exit) { /* 使能系统中断 */ RAW_CRITICAL_EXIT(); return RAW_IDLE_EXIT; } idle_task_exit = 1u; } /* 同IDLE任务,系统只允许一个task 0存在 */ #if (CONFIG_RAW_TASK_0 > 0) if (task_prio == 0) { if (task_0_exit) { RAW_CRITICAL_EXIT(); return RAW_TASK_0_EXIT; } task_0_exit = 1u; } #endif /* 使能系统中断 */ RAW_CRITICAL_EXIT(); /* 对分配的任务控制块的内存空间初始化为全0 */ raw_memset(task_obj, 0, sizeof(RAW_TASK_OBJ)); /* 系统调度方式FIFO无时间片???RR方式按时间片??? */ #if (CONFIG_SCHED_FIFO_RR > 0) /* 如果创建任务提供有time_slice参数,则初始化任务时间片为自定义时间片,否则系统默认50 */ if (time_slice) { task_obj->time_total = time_slice; } else { task_obj->time_total = TIME_SLICE_DEFAULT; } task_obj->time_slice = task_obj->time_total; /* 设置任务调度方式 */ task_obj->sched_way = SCHED_RR; #endif /* 如果定义任务时设置autorun为1,任务状态设为就绪态,否则设为挂起态,在应用层要手动唤醒任务 */ if (auto_start) { task_obj->task_state = RAW_RDY; } else { task_obj->task_state = RAW_SUSPENDED; /* 挂起时任务挂起计数+1 */ task_obj->suspend_count = 1u; } /* 初始化任务堆栈内存空间为0 */ task_obj->task_stack_base = task_stack_base; p_stack = task_stack_base; for (i = 0; i < stack_size; i++) { *p_stack++ = 0; } /* 调用创建任务的hook函数 */ #if (CONFIG_RAW_USER_HOOK > 0) task_create_hook(task_obj); #endif /* 移植相关,任务创建时的手动模拟堆栈初始化 */ task_obj->task_stack = port_stack_init(task_stack_base, stack_size, task_arg, task_entry); /* 设置TCB中任务名称、优先级、堆栈大小信息 */ task_obj->task_name = task_name; task_obj->priority = task_prio; task_obj->bpriority = task_prio; task_obj->stack_size = stack_size; /* 向trace系统加入当前任务调试代码??? */ TRACE_TASK_CREATE(task_obj); /* 又禁止系统中断,作用??? */ RAW_CRITICAL_ENTER(); /* 将任务堆栈检查list加入系统监控??? */ #if (RAW_SYSTEM_CHECK > 0) list_insert(&(system_debug.task_head), &task_obj->stack_check_list); #endif /* 如果创建任务时选择任务自动运行,立即添加到系统就绪链表的末端等待系统调度 */ if (auto_start) { add_ready_list_end(&raw_ready_queue, task_obj); } /* 如果此时系统状态为stopped,即未运行时,返回 */ if (raw_os_active != RAW_OS_RUNNING) { RAW_CRITICAL_EXIT(); return RAW_OS_STOPPED; } RAW_CRITICAL_EXIT(); /* 如果系统状态为RAW_OS_RUNNING,则马上进行系统调度,即系统运行时创建任务会马上执行调度 */ if (auto_start) { raw_sched(); } return RAW_SUCCESS; }
好,有上两步的基础,接下来看看系统初始化做了哪些工作
看来做了相当多的工作啊啊啊啊啊......直接看代码注释吧,说多也无益,这里tick list和就绪队列的形式是相似的,不过系统默认大小为8,这个tick list和任务超时有关,后续分析会分析到
RAW_U16 raw_os_init(void) { /* trace系统初始化,还不知道作用在哪??? */ TRACE_INIT(); /* 此时系统未运行,设置系统运行状态为stopped */ raw_os_active = RAW_OS_STOPPED; /* 初始化就绪队列 */ run_queue_init(&raw_ready_queue); /* 初始化tick链表 */ tick_list_init(); /* 初始化系统调试XX表,这是神马东西?有毛作用??? */ #if (RAW_SYSTEM_CHECK > 0) list_init(&(system_debug.task_head)); #endif /* 调用自定义系统初始化hook函数 */ #if (CONFIG_RAW_USER_HOOK > 0) raw_os_init_hook(); #endif /* 创建系统空闲任务,IDLE任务是最低优先级任务,必须存在IDLE任务??? */ raw_task_create(&raw_idle_obj, (RAW_U8 *)"idle_task", 0, IDLE_PRIORITY, 0, idle_stack, IDLE_STACK_SIZE, raw_idle_task, 1); /* 系统软件定时器初始化??? */ #if (CONFIG_RAW_TIMER > 0) raw_timer_init(); #endif /* 系统最高优先级任务task 0初始化???这又有毛用??? */ #if (CONFIG_RAW_TASK_0 > 0) raw_task_0_init(); #endif /* 系统时钟任务(tick任务)初始化,tick任务优先级为1,单独封装tick任务好处??? */ #if (CONFIG_RAW_TICK_TASK > 0) tick_task_start(); #endif /* CPU统计任务初始化??? */ #if (RAW_CONFIG_CPU_TASK > 0) cpu_task_start(); #endif return RAW_SUCCESS; }
最后就是启动系统,寻找第一个最高优先级任务,开始任务调度,这里说说list_entry这个宏,稍微看过linux代码的同学们就知道container_of这个宏,目的是通过某个结构体中的成员逆运算得出成员所属结构的地址,在Raw-OS中的list_entry作用是类似的
例如,注意到就绪队列中链表的元素是List,也就是说,创建自动运行任务时不是直接吧任务控制块直接添加到就绪队列中,而是把TCB中的tasklist成员添加到就绪队列,那么当从就绪队列中找到最高优先级任务的TCB时,就需要通过tasklist成员逆运算找到TCB的入口地址,所以整个过程如下:
那么在系统启动时就有这样的过程
具体看系统启动的代码
RAW_U16 raw_os_start(void) { /* 如果当前系统处于stopped状态,开始任务调度 */ if (raw_os_active == RAW_OS_STOPPED) { /* 从就绪队列取出队列中的最高优先级任务 */ get_ready_task(&raw_ready_queue); /* 移植部分相关,当前活动任务设为最高优先级任务,系统状态为running */ raw_task_active = high_ready_obj; raw_os_active = RAW_OS_RUNNING; /* 移植部分相关,执行第一个最高优先级任务调度 */ raw_start_first_task(); } else { /* 如果系统处于运行状态,调用此函数时,返回running标志 */ return RAW_OS_RUNNING; } /* 永不执行返回? */ return RAW_SYSTEM_ERROR; }
那么,整个系统初始化过程就可以这样理解
而在应用层代码中,必要的初始化代码就这样写:
int main(void){ /* 硬件初始化代码 */ ...... /* Raw-OS系统初始化 */ raw_os_init(); /* 建立自定义任务 */ ...... /* Raw-OS系统启动 */ raw_os_start(); /* 永不执行返回操作 */ return 0; }