立即注册
查看: 587|回复: 4

[资料] MTK内核定时器消息处理机制介绍

已绑定手机
发表于 2022-3-4 15:42:24 | 显示全部楼层 |阅读模式 来自 广东省深圳市
基本概念及Neclus内核定时器初始化
expires:指定定时器到期的时间,这个时间被表示成自系统启动以来的时钟滴答计数(也即时钟节拍数)。当一个定时器的expires值小于或等于jiffies变量时,我们就说这个定时器已经超时或到期了。在初始化一个定时器后,通常把它的expires域设置成当前expires变量的当前值加上某个时间间隔值(以时钟滴答次数计。
typedef struct timertable
{        /* store the timer_id. MSB(Most Significant Bit) is align_timer_mask */
        U16     timer_id[SIMULTANEOUS_TIMER_NUM];
        /* store the event_id that returns from evshed_set_event() */
        eventid   event_id[SIMULTANEOUS_TIMER_NUM];
        /* store the timer_expiry_func */
        oslTimerFuncPtr    callback_func[SIMULTANEOUS_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

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;
......
实际上,这个初始化函数仅仅将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个时钟滴答后才到期(interval=expires-jiffies),则Linux采用了下列思想来实现其动态内核定时器机制:对于那些0≤interval≤255的定时器,Linux严格按照定时器向量的基本语义来组织这些定时器,也即Linux内核最关心那些在接下来的255个时钟节拍内就要到期的定时器,因此将它们按照各自不同的expires值组织成256个定时器向量。而对于那些256≤interval≤0xffffffff的定时器,由于他们离到期还有一段时间,因此内核并不关心他们,而是将它们以一种扩展的定时器向量语义(或称为“松散的定时器向量语义”)进行组织。所谓“松散的定时器向量语义”就是指:各定时器的expires值可以互不相同的一个定时器队列。

更多详细内容请下载附件查看
游客,如果您要查看本帖隐藏内容请回复
已绑定手机
发表于 2022-3-4 16:20:23 | 显示全部楼层 来自 广东省深圳市
9999999999999999999999999
已绑定手机
发表于 2022-3-4 16:49:17 | 显示全部楼层 来自 上海市
了解一下
已绑定手机
发表于 2022-3-4 17:15:10 | 显示全部楼层 来自 北京市
顶顶顶顶顶顶顶顶顶顶顶顶顶顶
已绑定手机
发表于 2022-3-16 10:15:16 | 显示全部楼层 来自 广东省惠州市
66666666666666
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

合作/建议

TEL: 19168984579

工作时间:
周一到周五 9:00-11:30 13:30-19:30
  • 扫一扫关注公众号
  • 扫一扫打开小程序
Copyright © 2013-2024 一牛网 版权所有 All Rights Reserved. 帮助中心|隐私声明|联系我们|手机版|粤ICP备13053961号|营业执照|EDI证
在本版发帖搜索
扫一扫添加微信客服
QQ客服返回顶部
快速回复 返回顶部 返回列表