嵌入式操作系统内核原理和开发(事件)

【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】 


    在很多操作系统的书上,其实互斥和同步是放在一起进行介绍的。互斥,比较简单,就是对某一份资源或者几份资源进行抢占获取。而同步是什么意思呢,就是某一个线程等待另外一个线程的通知,只有收到了通知,它才会去干某些事情。


     通常情况下,如果是抢占的话,那么两个人使用的必须是同一个锁,而同步的话,则需要好几个锁,因为一般情况下大家等待的东西都是不一样的,所以好几个锁是不可避免的。那么,有没有什么办法,可以用一个锁实现几个事情的并发和同步呢?这就是我们今天所要说的事件。可以从一个例子说明一下。


     比方说,我们现在打算进行八宝饭的烹饪。那么,在此之前需要进行各个辅料的准备工作,等到这些辅料都准备好了,就可以开始煮八宝饭了。因为辅料之间是相互独立的,所以完全可以分开独立完成,而在所有辅料都没有完成之前,我们只能等待。等到材料全部准备好,我们就可以开始烹饪的工作了。当然,在烹饪的时候,我们又可以准备进行下一轮工作了,也就是说进行下一次八宝饭的辅料准备。在这个地方,辅料的准备是由各个子线程完成的,而煮饭这个工作是主线程完成的,主线程和子线程之间就是通过事件进行沟通的。主线程需要知道当前各个材料准备好了没,而子线程需要知道八宝饭烧好了没,是不是该进行下一轮辅料的准备了。这个中间就存在一个同步的问题了。


     如果大家对之前的信号量还有印象的话,当初我们是用count来表示资源的个数。而今天,我们用flags来表示事件状态,而其中的bit则表示了一个一个具体的事件。只不过有的线程在等待多个事件,而有的线程在等待一个事件,有的线程在获取事件后bit位立即清除,有的线程在获取事件后继续留存。


    所以下面,我们就看看raw-os上面的事件是怎么设计的。当然,我们首先看到的还是关于事件的基本数据结构,

typedef struct RAW_EVENT
 { 
 	RAW_COMMON_BLOCK_OBJECT       common_block_obj;
 	RAW_U32  flags;
 	
 } RAW_EVENT;
 
 
    这和我们之前介绍的没什么不一样,就是通用结构加上flag标志。关于事件的基本处理函数也不复杂,主要就是创建、申请、设置和删除四个基本操作。我们来看看每一步分别是怎么实现的,首先介绍的还是事件的创建过程,

RAW_U16 raw_event_create(RAW_EVENT *event_ptr, RAW_U8 *name_ptr, RAW_U32 flags_init)
 {
 	#if (RAW_EVENT_FUNCTION_CHECK > 0)
 	
 	if (event_ptr == 0) {
 		
 		return RAW_NULL_OBJECT;
 	}
 	
 	#endif
 
 	/*Init the list*/
 	list_init(&event_ptr->common_block_obj.block_list);
 	event_ptr->common_block_obj.block_way = 0;
 	event_ptr->common_block_obj.name = name_ptr;  
 	event_ptr->flags = flags_init ;
 	
 	return RAW_SUCCESS;
 }
 

    看了代码,相信要说的部分不是很多,关键就是flags的赋值部分,其他的都和信号量差不太多。这里的flags代表了某一个起始状态,也就是说当前可以干什么事情、满足哪些条件等等。下面,我们继续看事件的获取函数,稍微复杂一些,

RAW_U16 raw_event_get(RAW_EVENT *event_ptr, RAW_U32  requested_flags, RAW_U8 get_option, RAW_U32 wait_option)
 {
    	RAW_U16 error_status;
    
     RAW_U8 status;
 	RAW_SR_ALLOC();
 
 	#if (RAW_EVENT_FUNCTION_CHECK > 0)
 
 	if (raw_int_nesting) {
 
 		return RAW_NOT_CALLED_BY_ISR;
 		
 	}
 
 	if ((get_option  != RAW_AND) && (get_option  != RAW_OR) && (get_option  != RAW_AND_CLEAR) && (get_option  != RAW_OR_CLEAR)) {
 
 		return RAW_NO_THIS_OPTION;
 	}
 	
 	#endif
 	
     RAW_CRITICAL_ENTER();
 
 	/*if option is and flag*/
     if (get_option & RAW_FLAGS_AND_MASK) {
    
         if ((event_ptr->flags & requested_flags) == requested_flags) {
     
             status = RAW_TRUE;
         }
 				
         else {
             status =  RAW_FALSE;
         }
 				
     }
 	/*if option is or flag*/
     else {
     
         if (event_ptr->flags & requested_flags) {
 
            
             status =  RAW_TRUE;
         }
 				
         else {
  
             status =  RAW_FALSE;
         }
 				
     }
 
 
 		
     if (status) {
 
 		/*does it need to clear the flags*/
 		if (get_option & RAW_FLAGS_CLEAR_MASK) {
 			event_ptr->flags  &=  ~requested_flags;
 		}
 		
 		RAW_CRITICAL_EXIT();	
 		return RAW_SUCCESS;
                
     }
 		
 	/*Cann't get event, and return immediately if wait_option is  RAW_NO_WAIT*/
 	if (wait_option == RAW_NO_WAIT) { 
 		RAW_CRITICAL_EXIT();
 		return RAW_NO_PEND_WAIT;
 	}   
 
 	/*system is locked so task can not be blocked just return immediately*/
 	if (raw_sched_lock) {   
 		RAW_CRITICAL_EXIT();	
 		return RAW_SCHED_DISABLE;
 	}
  
    /*Remember the passed information*/
 	raw_task_active->raw_suspend_option =  get_option;
 	raw_task_active->raw_suspend_flags = requested_flags;
 	
 	raw_pend_object(&event_ptr->common_block_obj, raw_task_active, wait_option);
 	RAW_CRITICAL_EXIT();
 
 	raw_sched(); 
 	
 	RAW_CRITICAL_ENTER();
 	
 	/*does it need to clear the flags*/
 	if (get_option & RAW_FLAGS_CLEAR_MASK) {
 		event_ptr->flags  &=  ~requested_flags;
 	}
 	
 	RAW_CRITICAL_EXIT();
 	
 	/*So the task is waked up, need know which reason cause wake up.*/
 	error_status = block_state_post_process(raw_task_active, 0);
 	return error_status;
 
 	
 }
 
    注意,这里事件和其他get函数的最大差别就是,函数多了一个get_option,它表示当前是同时申请多个事件还是多个事件中的一个事件,申请后是否需要进行clear置位等等,我们不妨看看具体细节,

    (1)判断函数是否在中断中;

    (2)判断get_option是否合法;

    (3)判断是否存在可以获取的事件,and或者是or;

    (4)如果事件可以获取,那么再判断是否需要置位操作,函数返回;

    (5)判断是否愿意等待,否则返回;

    (6)判断是否禁止调度,是则返回;

    (7)将自己pend到等待队列中;

    (8)调用公共调度函数转到其他线程继续运行;

    (9)当前线程重新得到运行的机会,根据选项清除标志位,函数返回。


    看完了事件的申请,下面就可以看看事件的设置函数了,

RAW_U16 raw_event_set(RAW_EVENT *event_ptr, RAW_U32  flags_to_set, RAW_U8 set_option)
 {
 	LIST    									 *iter;
 	LIST    									 *event_head_ptr;
 	LIST 										 *iter_temp;
 	struct RAW_TASK_OBJ          *task_ptr;
 	
 	RAW_U8 status;
 	RAW_U8 need_sche = 0;
 	
 	RAW_SR_ALLOC();
 
 	#if (RAW_EVENT_FUNCTION_CHECK > 0)
 
 	if (event_ptr == 0) {
 		return RAW_NULL_OBJECT;
 	}
 	
 	if ((set_option  != RAW_AND) && (set_option  != RAW_OR)) {
 		return RAW_NO_THIS_OPTION;
 	}
 	
 	#endif
 
 	event_head_ptr =  &event_ptr->common_block_obj.block_list;
 	
 	status = RAW_FALSE;
 	
 	RAW_CRITICAL_ENTER();
 
     /*if the set_option is AND_MASK, it just clear the flags and will return immediately!*/
     if (set_option & RAW_FLAGS_AND_MASK)  {
    
 		event_ptr->flags  &=  flags_to_set;
 
 		RAW_CRITICAL_EXIT();
 		return  RAW_SUCCESS;
     }
 	/*if it is or mask then set the flag and continue.........*/
     else  {
 			
 		event_ptr->flags |= flags_to_set;    
     }
 
 	iter = event_head_ptr->next;
 
 	/*if list is not empty*/
  	while (iter !=event_head_ptr) {
 
 		task_ptr =  list_entry(iter, RAW_TASK_OBJ, task_list);
 		iter_temp =  iter->next;
 		
 		if (task_ptr->raw_suspend_option & RAW_FLAGS_AND_MASK)  {
 
 			if ((event_ptr->flags  & task_ptr ->raw_suspend_flags) == task_ptr ->raw_suspend_flags)
 				status =  RAW_TRUE;
 			else
 
 				status =   RAW_FALSE;
 		}
 
 		
 		else {
 
 			if (event_ptr->flags  &  task_ptr ->raw_suspend_flags)
 				
 				status =  RAW_TRUE;
 			else
 				
 				status =  RAW_FALSE;
 		}
 
 		
 		if  (status)  {
 			
 			/*Ok the task condition is met, just wake this task*/
 			raw_wake_object(task_ptr);
 	
 			/*if  task is waken up*/
 			need_sche = 1;
 		}
 
 		iter = iter_temp;
 
  	}
 
 	RAW_CRITICAL_EXIT();
 
 	if (need_sche) {
 		
 		raw_sched();
 	}
 	
 	return RAW_SUCCESS;
 		
 	 
 }
 
    从函数上也看得出来,这里有一个set_option的选项,主要是为了供调用者选择是进行and设置还是or设置,细节如下所示,

    (1)判断参数合法性;

    (2)判断set_option合法性;

    (3)如果选项为and,在设置完flags之后函数返回;

    (4)设置flags标志位,开始遍历每一个等待线程;

    (5)如果存在合适的线程,不管是等待多个事件还是一个事件,都将它们唤醒,设置重新调度标志;

    (6)如果重新调度标志为1,调用系统调度函数切换到其他线程运行;

    (7)当前线程再次获取到运行的机会,函数返回。


    转眼之间,我们就到了事件的删除过程了。其实事件的删除非常简单,它就是把所有的等待线程唤醒,就这么简单,不知道我说清楚了没?当然了,这中间可能会有高优先级的线程被加入到ready队列里面,所以重新schedule一下也是很有必要的。

RAW_U16 raw_event_delete(RAW_EVENT *event_ptr)
 {
 	LIST *block_list_head;
 	
    RAW_SR_ALLOC();
 	 
 	#if (RAW_EVENT_FUNCTION_CHECK > 0)
 
 	if (event_ptr == 0) {
 		return RAW_NULL_OBJECT;
 	}	
 	
 	#endif
 	
 	block_list_head = &event_ptr->common_block_obj.block_list;
 	
    RAW_CRITICAL_ENTER();
 
 	/*All task blocked on this queue is waken up until list is empty*/
 	while (!is_list_empty(block_list_head)) {
 		delete_pend_obj(list_entry(block_list_head->next, RAW_TASK_OBJ, task_list));	
 	}    
 
 	event_ptr->flags = 0;
 	
 	RAW_CRITICAL_EXIT();
 	
     raw_sched();  
 
 	return RAW_SUCCESS;
 }
 



 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入式-老费

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值