zl程序教程

您现在的位置是:首页 >  硬件

当前栏目

嵌入式操作系统内核原理和开发(线程状态)

内核状态线程原理开发 嵌入式操作系统
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函数就明白了。