分析的内核版本截止到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使用的双向链表是这样定义的
/*
* 双向链表
*/
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;
}
2.系统任务创建
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;
}
3.系统初始化
好,有上两步的基础,接下来看看系统初始化做了哪些工作
看来做了相当多的工作啊啊啊啊啊......直接看代码注释吧,说多也无益,这里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;
}
4.系统启动
最后就是启动系统,寻找第一个最高优先级任务,开始任务调度,这里说说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;
}