MTK定时器消息处理机制.doc_第1页
MTK定时器消息处理机制.doc_第2页
MTK定时器消息处理机制.doc_第3页
MTK定时器消息处理机制.doc_第4页
MTK定时器消息处理机制.doc_第5页
已阅读5页,还剩9页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

MTK定时器消息处理机制一、 基本概念及Neclus内核定时器初始化expires:指定定时器到期的时间,这个时间被表示成自系统启动以来的时钟滴答计数(也即时钟节拍数)。当一个定时器的expires值小于或等于jiffies变量时,我们就说这个定时器已经超时或到期了。在初始化一个定时器后,通常把它的expires域设置成当前expires变量的当前值加上某个时间间隔值(以时钟滴答次数计。typedef struct timertable /* store the timer_id. MSB(Most Significant Bit) is align_timer_mask */ U16 timer_idSIMULTANEOUS_TIMER_NUM; /* store the event_id that returns from evshed_set_event() */ eventid event_idSIMULTANEOUS_TIMER_NUM; /* store the timer_expiry_func */ oslTimerFuncPtr callback_funcSIMULTANEOUS_TIMER_NUM; /* point to the next TIMERTABLE data */ struct timertable *next; TIMERTABLE; typedef lcd_dll_node *eventid;struct lcd_dll_node void *data; lcd_dll_node *prev; lcd_dll_node *next;(1)timer_id:定时器id最多同时12个。(2)双向链表元素event_id:用来将多个定时器调度动作连接成一条双向循环队列。 (3)函数指针callback_func:指向一个可执行函数。当定时器到期时,内核就执行function所指定的函数,产生expires 消息。/L4 init the timer/* FUNCTION*L4InitTimer* DESCRIPTION* This function is to init the timer while task create. * PARAMETERS*aIN void* RETURNS*VOID.* GLOBALS AFFECTED* external_global*/void L4InitTimer(void) /*-*/ /* Local Variables */ /*-*/ TIMERTABLE *p; TIMERTABLE *pp; /*-*/ /* Code Body */ /*-*/ /* Try to free TIMERTABLE list exclude g_timer_table */ p = g_timer_table.next; pp = NULL; do if (p != NULL) pp = p-next; OslMfree(p); p = pp; while (p != NULL); /* reset g_timer_talbe */ memset(&g_timer_table, 0, sizeof(TIMERTABLE); g_timer_table_size = SIMULTANEOUS_TIMER_NUM; g_timer_table_used = 0; /* Initiate the clock time callback function. */ get_clocktime_callback_func = NULL; set_clocktime_callback_func = NULL; /* Initate the no alignment stack timer */ stack_init_timer (&base_timer1, MMI_Base_Timer1, MOD_MMI); /* Create a no alignment timer schedule */ event_scheduler1_ptr = new_evshed(&base_timer1, L4StartBaseTimer, L4StopBaseTimer, 0 , kal_evshed_get_mem, kal_evshed_free_mem, 0); /* Initate the alignment stack timer */ stack_init_timer (&base_timer2, MMI_Base_Timer2, MOD_MMI); /* Create an alignment timer schedule */ event_scheduler2_ptr = new_evshed(&base_timer2, L4StartBaseTimer, L4StopBaseTimer, 0, kal_evshed_get_mem, kal_evshed_free_mem, 255);typedef struct stack_timer_struct_t module_type dest_mod_id; kal_timerid kal_timer_id; kal_uint16 timer_indx; stack_timer_status_type timer_status; kal_uint8 invalid_time_out_count; stack_timer_struct;/* Exported Function Prototypes*/* Important:*Current implementation max_delay_ticks only support 0, and non-0.*/extern event_scheduler *new_evshed(void *timer_id, void (*start_timer)(void *, unsigned int), void (*stop_timer)(void *), kal_uint32 fuzz, malloc_fp_t alloc_fn_p, free_fp_t free_fn_p, kal_uint8 max_delay_ticks);实际上,这个初始化函数仅仅将TIMERTABLE链表初始化为空。初始化g_timer_table_size及g_timer_table_used参数。设置定时器调度函数指针。由于定时器通常被连接在一个双向循环队列中等待执行(此时我们说定时器处于pending状态)。因此函数evshed_events_pending就可以用list成员是否为空来判断一个定时器是否处于pending状态。kal_bool evshed_events_pending(event_scheduler *es);二、Linux动态内核定时器机制的原理 Linux是怎样为其内核定时器机制提供动态扩展能力的呢?其关键就在于“定时器向量”的概念。所谓“定时器向量”就是指这样一条双向循环定时器队列(对列中的每一个元素都是一个timer_list结构):对列中的所有定时器都在同一个时刻到期,也即对列中的每一个timer_list结构都具有相同的expires值。显然,可以用一个timer_list结构类型的指针来表示一个定时器向量。显然,定时器expires成员的值与jiffies变量的差值决定了一个定时器将在多长时间后到期。在32位系统中,这个时间差值的最大值应该是0xffffffff。因此如果是基于“定时器向量”基本定义,内核将至少要维护0xffffffff个timer_list结构类型的指针,这显然是不现实的。 另一方面,从内核本身这个角度看,它所关心的定时器显然不是那些已经过期而被执行过的定时器(这些定时器完全可以被丢弃),也不是那些要经过很长时间才会到期的定时器,而是那些当前已经到期或者马上就要到期的定时器(注意!时间间隔是以滴答次数为计数单位的)。 基于上述考虑,并假定一个定时器要经过interval个时钟滴答后才到期(intervalexpiresjiffies),则Linux采用了下列思想来实现其动态内核定时器机制:对于那些0interval255的定时器,Linux严格按照定时器向量的基本语义来组织这些定时器,也即Linux内核最关心那些在接下来的255个时钟节拍内就要到期的定时器,因此将它们按照各自不同的expires值组织成256个定时器向量。而对于那些256interval0xffffffff的定时器,由于他们离到期还有一段时间,因此内核并不关心他们,而是将它们以一种扩展的定时器向量语义(或称为“松散的定时器向量语义”)进行组织。所谓“松散的定时器向量语义”就是指:各定时器的expires值可以互不相同的一个定时器队列。三、MTK Linux动态内核定时器机制的原理MTK内核只需要同时维护12个类型的定时器,而且限定了其interval255,列为最关心处理的定时器,那么我们只需要为每个类型的定时器分配不同的expires值,因为它们按照不同的expires值组织成定时器向量。MTK内核里还分为两种不同类型的定时器,一种允许delay的,一种不允许,其他这些在初始化调度函数指针时就已经指定好了,内核对两者的处理是一样的。一般使用的是允许delay的定时器,防止一些突发性错误。四、MTK具体代码级分析MMITask.c中:void MMI_task(oslEntryType * entry_param)switch (Message.msg_id) case MSG_ID_TIMER_EXPIRY:kal_uint16 msg_len; EvshedMMITimerHandler(get_local_para_ptr(Message.oslDataPtr, &msg_len); break; 在这里或者我们在trace信息的时候经常可能看到一类比较特殊的消息,MSG_ID_TIMER_EXPIRY.(定时器时间到的消息ID)。Expiry是满,终结的意思。那么这个消息应该是我们在设置定时器的时候发给L4层的,然后再转交到MMI或者其他的模块的,被MMITASK所获取读到消息队列里的,然后针对其进行时间上的再分配和调度。在MTK里面,存在两种性质定时时间,一种是很精确的(no alignment timer),一种允许调整校准(delay)(allow alignment timer).而timer发出的消息不类似其他任务或进程发出的消息,并不是信号量,信号量的话一般发出来被其他进程得到(处理完后)可能就消亡了,而timer 的动作则需要重复的产生和调度,对两者的处理不一样。()/* NoteXXX:*In evshed_timer_handler(), system would execute event regisited timeout callback function.*Caller should reset saved event id in regisited timeout callback function,*or cause potential bug to cancel wrong timer event.*/见以下代码:(MMI Timer Event Scheduler)/MMI定时器动作调度函数void EvshedMMITimerHandler(void *dataPtr) /*-*/ /* Local Variables */ /*-*/ stack_timer_struct* stack_timer_ptr; stack_timer_ptr = (stack_timer_struct*)dataPtr; /*-*/ /* Code Body */ /*-*/ if (stack_timer_ptr = &base_timer1) if (stack_is_time_out_valid(&base_timer1) evshed_timer_handler(event_scheduler1_ptr); stack_process_time_out(&base_timer1); else if (stack_timer_ptr = &base_timer2) if (stack_is_time_out_valid(&base_timer2) evshed_timer_handler(event_scheduler2_ptr); stack_process_time_out(&base_timer2); 上面讲的是如何对消息进行处理,那么设置定时器后这消息是如何发出去呢?这个过程还没有讲。见代码:void StartTimer(U16 timerid, U32 delay, FuncPtr funcPtr) StartMyTimer(timerid, delay, (oslTimerFuncPtr)funcPtr);再往下:#defineStartMyTimer(nTimerId,nTimeDuration,TimerExpiryFunction) StartMyTimerInt(nTimerId,nTimeDuration,TimerExpiryFunction,0)再往下:U16 StartMyTimerInt(U16 nTimerId,U32 nTimeDuration,oslTimerFuncPtr TimerExpiry, U8 alignment) if(TimerExistnTimerId) OslStopSoftTimer(nTimerId); OslStartSoftTimer(nTimerId,TimerExpiry, nTimerId, nTimeDuration,alignment); TimerExistnTimerId=1; return TRUE;L4 timer:/将定时器消息由L4发送给MMI#define OslStartSoftTimer(nTimerId,TimerExpiry, nTimerId1, nTimeDuration,alignment) L4StartTimer(nTimerId,TimerExpiry,(void*)nTimerId1,nTimeDuration,alignment)void L4StartTimer(unsigned short nTimerId, oslTimerFuncPtr TimerExpiry, void * funcArg, unsigned long nTimeDurationInTicks, unsigned char alignment) /*-*/ /* Local Variables */ /*-*/ TIMERTABLE *pTable = NULL; U16 i = 0; U32 temp; /*-*/ /* Code Body */ /*-*/ if (TimerExpiry = NULL) /* If TimerExpiry is NULL, we dont start the timer */ MMI_ASSERT(0); return ; MMI_ASSERT(nTimerId= g_timer_table_size) /* * TIMERTABLE list doesnt have enough space, allocate the memory * * If we need to allocate the memeory, it means that MMI may have * such many timers run simultaneously. We wont free the memory * after we allocate more memory in TIMERTABLE list. */ do if (pTable-next = NULL) pTable-next = OslMalloc(sizeof(TIMERTABLE); memset(pTable-next, 0, sizeof(TIMERTABLE); g_timer_table_size += SIMULTANEOUS_TIMER_NUM; pTable = pTable-next; i = 0; break; pTable = pTable- next; while (pTable != NULL); else /* find the empty record in g_timer_table list */ i = 0; do if (pTable-event_id = NULL) /* find the empty space */ break; i+; if (i = SIMULTANEOUS_TIMER_NUM ) pTable = pTable-next; i = 0; while (pTable != NULL); if (pTable = NULL) /* Cant find the empty space in TIMERTABLE list, assert! */ MMI_ASSERT(0); /* if (g_timer_table_used = g_timer_table_size) */ /* * already find the empty record, and then start timer * event_sheduler1 = NO alignment scherulder * event_sheduler2 = alignment scherulder (low power) */ if (alignment = TIMER_IS_NO_ALIGNMENT) /* MSB(Most Significant Bit) is align_timer_mask */ pTable-timer_id = nTimerId | NO_ALIGNMENT_TIMER_MASK; pTable-event_id = evshed_set_event (event_scheduler1_ptr, (kal_timer_func_ptr)L4CallBackTimer, (void *)nTimerId, temp); pTable-callback_func = TimerExpiry; g_timer_table_used +; else if (alignment = TIMER_IS_ALIGNMENT) /* MSB(Most Significant Bit) is align_timer_mask */ pTable-timer_id = nTimerId | ALIGNMENT_TIMER_MASK; pTable-event_id = evshed_set_event (event_scheduler2_ptr, (kal_timer_func_ptr)L4CallBackTimer, (void *)nTimerId,temp ); pTable-callback_func = TimerExpiry; g_timer_table_used +; TimerExpiry 类型为void (*oslTimerFuncPtr)(void*),根据我个人猜测消息应该在回调函数TimerExpiry里(定时时间一到,而且很有可能是中断的方式)发出MSG_ID_TIMER_EXPIRY。Evshed_set_event()这个函数有点类似SetProtocolevent()设置协议动作函数,类似就象设置异步串口时只要相应消息一到就会跳到相应的处理函数里处理。在定时器timer里面,用的是L4CallBackTimer这个函数,在这个函数里面:/ 将使用过的TimerID和EventID给复位(reset).*/void L4CallBackTimer(void *p)U32 nTimerId = (U32)p; TIMERTABLE*pTable = &g_timer_table; U32 i = 0; oslTimerFuncPtr pTimerExpiry = NULL;MMI_ASSERT(nTimerId timer_id & (NO_ALIGNMENT_TIMER_MASK) = (U16)nTimerId) /* find out nTimerId */ if (pTable-callback_func != NULL) pTimerExpiry = pTable-callback_func;MMI_TRACE(MMI_TRACE_G1_FRM, MMI_FRM_INFO_L4DRV_CBTIMER_HDLR, nTimerId, pTimerExpiry); g_timer_table_used -; pTable-event_id = 0; pTable-timer_id = 0; pTable-callback_func = NULL; /* * we process g_timer_table_used, event_id and timer_id first * because the user may call stoptimer() in the timer_expiry_func */ pTimerExpiry(p);/此定时nTimerId已经执行完 break; i+; if (i = SIMULTANEOUS_TIMER_NUM ) pTable = pTable-next; i = 0; while (pTable != NULL); /* cant find nTimerId, do nothing */ mmi_frm_fetch_msg_from_extQ_to_circularQ(); /* * Because we modify MMI process protocol events and key events mechanism, * we dont need to process key events here. */mmi_frm_fetch_msg_from_extQ_to_circularQ();将对所有由MOD_TIMER(receive the message from MMI queue and put in circular queue)发送给MMI的消息放进循环队列,而这个函数在MMI_task()函数while(1)循环一开始就用于获取内部队列消息到循环队列中(fetch the message from external queue and put in the circular queue)。另外我们可以在Stoptimer()里面存在evshed_cancel_event()函数,这是与Starttimer()函数相对应。这样一来对TIMER 消息的处理流程就清楚了许多。当然整个理解过程中可能还有一些缺陷,希望大家指出。/* Important*System will allocate memory for event id, and return to caller.*If caller need to save event id, please be careful to reset when*cancel the event or the event expired.*/extern eventid evshed_set_event(event_scheduler *es, kal_timer_func_ptr event_hf, void *event_hf_param,kal_uint32 elapse_ti

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论