嵌入式操作系统内核原理和开发(线程状态)
2023-09-27 14:27:10 时间
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
从第一篇的os博客以来,谈了很多内容,有中断、切换、调度、内存、互斥和延时等等,但是线程的状态却没有涉及到,今天我们要好好说一说。说到线程的状态,按照一般的说法,主要包括就绪、延时、阻塞、阻塞超时四个状态。如果线程没有死亡的话,那么这几个状态也够用了,但是我们后来发现可能需要对某些线程进行挂起处理,这可能是出现了故障或者是为了调试使用。因此,除了上面的四个状态,我们还要补充对应的四个挂起状态,分别是挂起、延时挂起、阻塞挂起、阻塞延时挂起。
说到了线程状态,下面我们就看看常见的线程处理函数有哪些,无外乎线程创建、线程延时、线程挂起、线程恢复和线程删除等等。
RAW_U16 raw_task_create(RAW_TASK_OBJ *task_obj, RAW_U8 *task_name, RAW_VOID *task_arg,
RAW_U8 task_prio, RAW_U16 time_slice, PORT_STACK *task_stack_base,
RAW_U32 stack_size, RAW_TASK_ENTRY task_entry, RAW_U8 auto_start)
{
#if (RAW_TASK_STACK_CHECK > 0)
PORT_STACK *p_stack;
RAW_U32 i;
#endif
RAW_SR_ALLOC();
#if (RAW_TASK_FUNCTION_CHECK > 0)
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;
}
#endif
RAW_CRITICAL_ENTER();
if (task_prio == IDLE_PRIORITY) {
if (idle_task_exit) {
RAW_CRITICAL_EXIT();
return RAW_IDLE_EXIT;
}
idle_task_exit = 1;
}
RAW_CRITICAL_EXIT();
raw_memset(task_obj, 0, sizeof(RAW_TASK_OBJ));
#if (CONFIG_ROUND_ROBIN > 0)
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;
#endif
if (auto_start)
task_obj->task_state = RAW_RDY;
else
task_obj->task_state = RAW_SUSPENDED;
#if (RAW_TASK_STACK_CHECK > 0)
task_obj->task_stack_base = task_stack_base;
p_stack = task_stack_base;
for (i = 0; i < stack_size; i++) {
*p_stack++ =0;
}
#endif
task_obj->task_stack = port_stack_init(task_stack_base, stack_size, task_arg, task_entry);
task_obj->task_name = task_name;
task_obj->priority = task_prio;
task_create_hook(task_obj);
RAW_CRITICAL_ENTER();
#if (RAW_TASK_STACK_CHECK > 0)
task_obj->stack_size = stack_size;
list_insert(&task_head, &task_obj->stack_check_list);
#endif
if (auto_start) {
add_ready_list_end(&raw_ready_queue, task_obj);
}
if (raw_os_active != RAW_OS_RUNNING) { /* Return if multitasking has not started */
RAW_CRITICAL_EXIT();
return RAW_OS_STOPPED;
}
RAW_CRITICAL_EXIT();
if (auto_start) {
raw_sched();
}
return RAW_SUCCESS;
}
创建线程的函数是比较复杂的,内容长一些,参数也多一些。首先看看有哪些参数,虽然很多,但是慢慢梳理一下也不难理解,有名称、参数、优先级、时间片、堆栈起始指针、堆栈大小、入口函数和标志。整个函数基本上都是赋值的过程,最重要的其实就两个部分,一个是port_stack_init,另一个就是add_ready_list_end。前者可以对堆栈进行默认处理,比如压入一些寄存器、压入函数参数、函数指针等等,后者就是把线程加入到就绪队列。
RAW_U16 raw_sleep(RAW_U32 dly)
{
RAW_U16 error_status;
RAW_SR_ALLOC();
#if (RAW_TASK_FUNCTION_CHECK > 0)
if (raw_int_nesting) {
return RAW_NOT_CALLED_BY_ISR;
}
#endif
RAW_CRITICAL_ENTER();
if (dly) {
/*system is locked so task can not sleep just return immediately*/
if (raw_sched_lock) {
RAW_CRITICAL_EXIT();
return RAW_SCHED_DISABLE;
}
raw_task_active->task_state = RAW_DLY;
tick_list_insert(raw_task_active, dly);
remove_ready_list(&raw_ready_queue, raw_task_active);
}
else {
/*make current task to the end of ready list*/
move_to_ready_list_end(&raw_ready_queue, raw_task_active);
}
RAW_CRITICAL_EXIT();
raw_sched();
if (dly) {
/*task is timeout after sleep*/
error_status = block_state_post_process(raw_task_active, 0);
}
else {
error_status = RAW_SUCCESS;
}
return error_status;
}
我们之前也介绍过系统的延时功能。延时,就是把线程暂时从就绪队列清除出来,添加到延时队列中。当然如果参数为0,那表示作者只是希望暂时释放cpu的使用权,如果此时没有同等优先级的任务,那么下一个运行的线程还是它自己。
RAW_U16 raw_task_suspend(RAW_TASK_OBJ *task_ptr)
{
RAW_SR_ALLOC();
#if (RAW_TASK_FUNCTION_CHECK > 0)
if (task_ptr == 0) {
return RAW_NULL_OBJECT;
}
#endif
if (task_ptr->priority == IDLE_PRIORITY) {
return RAW_SUSPEND_TASK_NOT_ALLOWED;
}
RAW_CRITICAL_ENTER();
if (task_ptr == raw_task_active) {
if (raw_sched_lock) {
RAW_CRITICAL_EXIT();
return RAW_SCHED_LOCKED;
}
}
switch (task_ptr->task_state) {
case RAW_RDY:
task_ptr->task_state = RAW_SUSPENDED;
remove_ready_list(&raw_ready_queue, task_ptr);
break;
case RAW_DLY:
task_ptr->task_state = RAW_DLY_SUSPENDED;
break;
case RAW_PEND:
task_ptr->task_state = RAW_PEND_SUSPENDED;
break;
case RAW_PEND_TIMEOUT:
task_ptr->task_state = RAW_PEND_TIMEOUT_SUSPENDED;
break;
case RAW_DLY_SUSPENDED:
case RAW_PEND_SUSPENDED:
case RAW_PEND_TIMEOUT_SUSPENDED:
RAW_CRITICAL_EXIT();
return RAW_SUSPENDED_AGAIN;
default:
#if (CONFIG_RAW_ASSERT > 0)
RAW_ASSERT(0);
#endif
RAW_CRITICAL_EXIT();
return RAW_STATE_UNKNOWN;
}
RAW_CRITICAL_EXIT();
raw_sched();
return RAW_SUCCESS;
}
挂起任务的动作其实是比较残暴的,因为此时你不知道线程处于什么状态。当然任务如果已经被挂起了,那什么也不用做了,否则就需要把任务修改为对应的挂起状态就可以了。当然如果任务是就绪态的,还得把任务清除处理来。在函数结束的时候,我们需要重新进行调度,因为很有可能当前最高优先级的线程已经发生了改变。
RAW_U16 raw_task_resume(RAW_TASK_OBJ *task_ptr)
{
RAW_SR_ALLOC();
#if (RAW_TASK_FUNCTION_CHECK > 0)
if (task_ptr == 0) {
return RAW_NULL_OBJECT;
}
#endif
RAW_CRITICAL_ENTER();
switch (task_ptr->task_state) {
case RAW_RDY:
case RAW_DLY:
case RAW_PEND:
case RAW_PEND_TIMEOUT:
RAW_CRITICAL_EXIT();
return HAS_NOT_SUSPENDED;
case RAW_SUSPENDED:
task_ptr->task_state = RAW_RDY;
add_ready_list(&raw_ready_queue, task_ptr);
break;
case RAW_DLY_SUSPENDED:
task_ptr->task_state = RAW_DLY;
break;
case RAW_PEND_SUSPENDED:
task_ptr->task_state = RAW_PEND;
break;
case RAW_PEND_TIMEOUT_SUSPENDED:
task_ptr->task_state = RAW_PEND_TIMEOUT;
break;
default:
#if (CONFIG_RAW_ASSERT > 0)
RAW_ASSERT(0);
#endif
RAW_CRITICAL_EXIT();
return RAW_STATE_UNKNOWN;
}
RAW_CRITICAL_EXIT();
raw_sched();
return RAW_SUCCESS;
}
恢复函数其实就是挂起函数的逆向操作。如果任务没有被挂起,那么什么也不用做。否则就需要把任务的状态修改为对应的非挂起状态,当然该就绪的线程还得加入到就绪队列当中去。同时在函数结束之前不忘调度一下,说不定刚刚释放的这个线程就是优先级最高的那个线程。
RAW_U16 raw_task_delete(RAW_TASK_OBJ *task_ptr)
{
RAW_SR_ALLOC();
#if (RAW_TASK_FUNCTION_CHECK > 0)
if (task_ptr == 0) {
return RAW_NULL_OBJECT;
}
if (raw_int_nesting) {
return RAW_NOT_CALLED_BY_ISR;
}
#endif
if (task_ptr->priority == IDLE_PRIORITY) {
return RAW_DELETE_TASK_NOT_ALLOWED;
}
RAW_CRITICAL_ENTER();
if (task_ptr == raw_task_active) {
if (raw_sched_lock) {
RAW_CRITICAL_EXIT();
return RAW_SCHED_LOCKED;
}
}
switch (task_ptr->task_state) {
case RAW_RDY:
remove_ready_list(&raw_ready_queue, task_ptr);
break;
case RAW_SUSPENDED:
break;
case RAW_DLY: /* Task is only delayed, not on any wait list */
case RAW_DLY_SUSPENDED:
tick_list_remove(task_ptr);
break;
case RAW_PEND:
case RAW_PEND_SUSPENDED:
case RAW_PEND_TIMEOUT:
case RAW_PEND_TIMEOUT_SUSPENDED:
tick_list_remove(task_ptr);
list_delete(&task_ptr->task_list);
break;
default:
#if (CONFIG_RAW_ASSERT > 0)
RAW_ASSERT(0);
#endif
RAW_CRITICAL_EXIT();
return RAW_STATE_UNKNOWN;
}
task_ptr->task_state = RAW_DELETED;
#if (RAW_TASK_STACK_CHECK > 0)
/*make after_delete_list to right position*/
after_delete_list = task_ptr->stack_check_list.next;
if (after_delete_list == &task_head) {
after_delete_list = task_head.next;
}
list_delete(&task_ptr->stack_check_list);
#endif
RAW_CRITICAL_EXIT();
raw_sched();
return RAW_SUCCESS;
}
删除函数的动作其实是比较残忍的,因为此时你不清楚线程已经执行到哪一步了,拥有了那些资源,正在处理哪些资源,所以没事不要用这个函数。这里做的只是把任务从就绪队列、等待队列和阻塞队列清除出来,但是真正善后的工作要比这多得多,如果有兴趣,你看看linux的exit函数就明白了。
相关文章
- linux的内核bug引起线程挂起
- 【Linux开发】linux设备驱动归纳总结(七):1.时间管理与内核延时
- 64位内核开发第十讲,日期时间与定时器
- c#网络通信框架networkcomms内核解析之一 消息传送
- 如何向 Linux 内核提交驱动
- Linux内核源代码
- linux内核及其模块的查询,加载,卸载 lsusb等
- Windows内核再次出现0Day漏洞 影响win2000到win10所有版本 反病毒软件恐成瞎子
- 浏览器内核及渲染过程杂谈
- Advanced Python系列之协程Coroutines架构内核与源码实战
- 【内核】探究linux内核,超详细解析子系统
- linode下更换内核(debian,ubuntu,centos)
- UNIX内核(5):内核开发的特点
- Docker背后的内核知识:命名空间资源隔离---亲测
- linux内核自旋锁API
- 深入理解Linux内核-进程地址空间
- u-boot向linux内核传递启动参数(详细)
- u-boot中分区和内核MTD分区关系
- uboot从SD卡烧写内核和文件系统