您的位置:首页 > 其它

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

2014-04-16 15:04 381 查看
分析的内核版本截止到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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: