Raw-OS源码分析之任务挂起与唤醒

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

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

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


        这节讨论一下Raw-OS中的任务挂起操作的实现,但是系统对于任务挂起操作的情况是很多的,就绪任务可以被挂起,休眠的任务可以被挂起,等待任务可以被挂起,已经被挂起的任务也可以再次被挂起,这里仅仅给出就绪任务被挂起的情况,先看挂起操作的流程:


        就绪任务的挂起:找到任务所属的就绪链表的位置,然后执行list_remove()操作,这个操作在之前讨论过,那么通过list_enrty宏设置任务控制块中的任务指示标志位为suspended状态,从就绪队列删除这个任务信息即可,具体代码:

RAW_U16 raw_task_suspend(RAW_TASK_OBJ *task_ptr)
{
	#if (RAW_TASK_FUNCTION_CHECK > 0)
	/* 检查任务控制块是否为空,为空即任务不存在,无所谓挂不挂起 */
	if (task_ptr == 0) {
		return RAW_NULL_OBJECT;
	}
	#endif
	/* 检查任务优先级,这里检查是否是IDEL任务优先级,即IDEL任务不能被挂起??? */
	if (task_ptr->priority == IDLE_PRIORITY) {
		return RAW_SUSPEND_TASK_NOT_ALLOWED;
	}

	#if (CONFIG_RAW_TASK_0 > 0)
	/* 检查任务优先级,开启Task 0任务相关宏后,同样task 0不能被挂起??? */
	if (task_ptr->priority == 0) {
		return RAW_SUSPEND_TASK_NOT_ALLOWED;
	}
	#endif

	#if (CONFIG_RAW_ZERO_INTERRUPT > 0)
	/* 开启0中断特性后,任务挂起消息通过task 0转发??? */
	if (raw_int_nesting) {
		/* ??? */
		return int_msg_post(RAW_TYPE_SUSPEND, task_ptr, 0, 0, 0, 0);
	}
	#endif
	/* 挂起任务操作 */
	return task_suspend(task_ptr);
}


/* 挂起任务操作 */
RAW_U16 task_suspend(RAW_TASK_OBJ *task_ptr)
{
	RAW_SR_ALLOC();
	/*
	 * 这个宏跟是否实现0中断特性有关,按照之前的配置,不实现0中断特性
	 * 因为没研究过,不好解释,后续分析再不上
	 *
	 * 不实现0中断特性,这个宏就是简单禁止CPU中断,然后把状态字保存起来
	 */
	RAW_CRITICAL_ENTER();

	/* 如果挂起的是当前系统运行中的任务,必须先给系统解锁,开放系统调度??? */
	if (task_ptr == raw_task_active) {
		SYSTEM_LOCK_PROCESS();
	}
	/* 读取被挂起任务的任务状态 */
	switch (task_ptr->task_state) {
		/* 任务为就绪态时 */
		case RAW_RDY:
			/* 任务挂起次数=1 */
			task_ptr->suspend_count = 1;
			/* 挂起后,设置任务状态为挂起态 */
			task_ptr->task_state  =  RAW_SUSPENDED;
			/* 把就绪任务从就绪队列中删除 */
			remove_ready_list(&raw_ready_queue, task_ptr);
			break;
		/* 任务为休眠状态 */
		case RAW_DLY:
			task_ptr->suspend_count = 1;
			/* 挂起后,变为休眠挂起状态 */
			task_ptr->task_state  = RAW_DLY_SUSPENDED;
			break;
		/* 任务为阻塞状态 */
		case RAW_PEND:
			task_ptr->suspend_count = 1;
			/* 挂起后,设置任务状态为阻塞挂起态 */
			task_ptr->task_state  = RAW_PEND_SUSPENDED;
			break;
		/* 任务为阻塞超时状态 */
		case RAW_PEND_TIMEOUT:
			task_ptr->suspend_count = 1;
			/* 挂起后,设置任务状态为阻塞超时挂起态 */
			task_ptr->task_state  = RAW_PEND_TIMEOUT_SUSPENDED;
			break;

		/* 下面的是已经被挂起的状态,在Raw-OS中允许挂起的任务再一次被挂起 */
		case RAW_SUSPENDED:
		case RAW_DLY_SUSPENDED:
		case RAW_PEND_SUSPENDED:
		case RAW_PEND_TIMEOUT_SUSPENDED:
			/* 再次被挂起的任务在挂起嵌套层变量++ */
			task_ptr->suspend_count++;
			/* 可以看出允许任务重复挂起249次,谁那么无聊会挂起这么多次??? */
			if (task_ptr->suspend_count >= 250u) {
				RAW_CRITICAL_EXIT();
				return RAW_SUSPENDED_COUNT_OVERFLOWED;
			}
			break;

		default:
			RAW_CRITICAL_EXIT();
			return RAW_STATE_UNKNOWN;
	}

	RAW_CRITICAL_EXIT();
	/* 又是trace调试系统??? */
	TRACE_TASK_SUSPEND(raw_task_active, task_ptr);
	/* 这里就是系统调度,任务挂起后会马上执行任务调度 */
	raw_sched();
	/* 函数没有检查中断嵌套的情况,那么在中断是可以执行任务挂起操作的 */
	return RAW_SUCCESS;
}


        那么对于唤醒一个仅仅是简单挂起状态的任务,就是唤醒任务的逆操作,什么是简单挂起,开始的时候说明过,任务挂起的状态是可以叠加的,休眠的任务可以被挂起,等待任务可以被挂起,已经被挂起的任务也可以再次被挂起,这是我个人理解的非简单挂起,那么对于简单挂起的唤醒操作,流程是这样的:



        唤醒操作,先设置任务TCB里面的任务状态标志为ready,然后通过TCB中的tasklist信息加入到就绪队列的适当位置,至于就绪队列的insert操作,在系统初始化阶段讨论过,可参考之前的blog,那么内核实现的代码是:

RAW_U16 raw_task_resume(RAW_TASK_OBJ *task_ptr)
{
	#if (RAW_TASK_FUNCTION_CHECK > 0)
	/* 检查任务控制块是否为空,为空即任务不存在,无所谓唤不唤醒 */
	if (task_ptr == 0) {
		return RAW_NULL_OBJECT;
	}
	#endif

	#if (CONFIG_RAW_ZERO_INTERRUPT > 0)
	/* 开启0中断特性后,系统处理中断或调度被上锁时,唤醒操作通过task 0 转发??? */
	if (raw_int_nesting && raw_sched_lock) {
		return int_msg_post(RAW_TYPE_RESUME, task_ptr, 0, 0, 0, 0);
	}

	#endif
	/* 唤醒任务 */
	return task_resume(task_ptr);
}

RAW_U16 task_resume(RAW_TASK_OBJ *task_ptr)
{
	/* task 0不实现时,保存CPU状态字,禁止CPU中断 */
	RAW_SR_ALLOC();
	RAW_CRITICAL_ENTER();
	/* 检查被唤醒任务状态 */
	switch (task_ptr->task_state) {
		/* 就绪,睡眠,阻塞,阻塞超时状态不是挂起状态,所以无所谓唤不唤醒 */
		case RAW_RDY:
		case RAW_DLY:
		case RAW_PEND:
		case RAW_PEND_TIMEOUT:
			/* 使能CPU中断后返回 */
			RAW_CRITICAL_EXIT();
			return HAS_NOT_SUSPENDED;

		/* 如果当前任务为挂起态 */
		case RAW_SUSPENDED:
			/* 之前讲过Raw-OS允许任务挂起嵌套的,这里嵌套层数-1 */
			task_ptr->suspend_count--;
			/* 当被唤醒任务嵌套挂起计数器=0时,唤醒任务 */
			if (task_ptr->suspend_count == 0) {
				/* 更改任务状态为就绪态 */
				task_ptr->task_state = RAW_RDY;
				/* 调度到就绪队列,等待系统调度 */
				add_ready_list(&raw_ready_queue, task_ptr);
			}
			break;
		/* 如果当前任务为休眠挂起态 */
		case RAW_DLY_SUSPENDED:
			/* 这里嵌套层数-1 */
			task_ptr->suspend_count--;
			if (task_ptr->suspend_count == 0) {
				/* 更改任务状态为休眠态 */
				task_ptr->task_state = RAW_DLY;
			}
			break;
		/* 如果当前任务为阻塞挂起态 */
		case RAW_PEND_SUSPENDED:
			/* 这里嵌套层数-1 */
			task_ptr->suspend_count--;
			if (task_ptr->suspend_count == 0) {
				/* 更改任务状态为阻塞态 */
				task_ptr->task_state = RAW_PEND;
			}
			break;
		/* 如果当前任务为阻塞超时挂起态 */
		case RAW_PEND_TIMEOUT_SUSPENDED:
			/* 这里嵌套层数-1 */
			task_ptr->suspend_count--;
			if (task_ptr->suspend_count == 0) {
				/* 更改任务状态为阻塞超时态 */
				task_ptr->task_state = RAW_PEND_TIMEOUT;
			}
			break;

		default:
			RAW_CRITICAL_EXIT();
			return RAW_STATE_UNKNOWN;

	}

	RAW_CRITICAL_EXIT();
	/* 又是trace调试系统??? */
	TRACE_TASK_RESUME(raw_task_active, task_ptr);
	/* 执行系统调度了,那么任务唤醒操作时会进行系统调度 */
	raw_sched();
	return RAW_SUCCESS;
}


        那么需要注意的一点是,讨论中是Raw-OS的配置头文件是不涉及CONFIG_RAW_ZERO_INTERRUPT宏和CONFIG_RAW_TASK_0的实现的,以后会另外讨论系统task 0和0中断特性的作用。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值