Linux内核定时器是内核用来控制在未来某个时间点(基于jiffies)调度执行某个函数的一种机制,调度函数在运行过一次后就不会再运行了(相当于自动注销),但可以通过在被调度的函数中重新调度自己来周期运行。
(1)jiffies定时器,HZ=100,精度只能达到10ms,已验证
#include <linux/jiffies.h>
#include <linux/timer.h>
static struct timer_list ms_timer;
static void ms_timer_handler(void)
{
printk("DO_DEBUG----------->%s\n",__func__);
ms_timer.expires=jiffies+msecs_to_jiffies(10);
ms_timer.function=&ms_timer_handler;
add_timer(&ms_timer); //循环执行自己
}
static int32_t xxx_init(void)
{
init_timer(&ms_timer); //DO-->初始化定时器
ms_timer.expires=jiffies+msecs_to_jiffies(10); //DO-->定义中断时间:10ms进入中断
ms_timer.function=&ms_timer_handler; //DO-->定义定时器中断处理函数
add_timer(&ms_timer); //DO-->增加注册定时器,使定时器生效
}
移除定时器,用del_timer_sync(&ms_timer)。以上ms_timer_handler的内容,可用
printk("DO_DEBUG----------->%s\n",__func__);
mod_timer(&ms_timer,jiffies+msecs_to_jiffies(10));
代替。碰到睡眠唤醒的处理,睡眠时删掉timer,唤醒时重新初始化timer。
(2)hrtimer高精度定时器,可做到ns级。
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/timer.h>
#include <linux/hrtimer.h>
MODULE_LICENSE("Dual BSD/GPL");
extern int hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode);
extern void hrtimer_init(struct hrtimer *timer, clockid_t clock_id,enum hrtimer_mode mode);
extern int hrtimer_cancel(struct hrtimer *timer);
#define BAT_MS_TO_NS(x) (x * 1000 * 1000)
static struct hrtimer charger_hv_detect_timer;
void __exit kernel_test_exit()
{
hrtimer_cancel(&charger_hv_detect_timer);
printk("module out kernel_test_exit \r\n");
}
enum hrtimer_restart charger_hv_detect_sw_workaround(struct hrtimer *timer)
{
printk("charger_hv_detect_sw_workaround \n");
return HRTIMER_RESTART;
}
int __init kernel_test_init()
{
ktime_t ktime;
ktime = ktime_set(0, BAT_MS_TO_NS(2000));
hrtimer_init(&charger_hv_detect_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
charger_hv_detect_timer.function = charger_hv_detect_sw_workaround;
hrtimer_start(&charger_hv_detect_timer, ktime, HRTIMER_MODE_REL);
printk("module in kernel_test_init \r\n");
return 0;
}
module_init(kernel_test_init);
module_exit(kernel_test_exit);
最终insmod,提示
[ 2058.475797] charger_hv_detect_sw_workaround
[ 2058.475800] charger_hv_detect_sw_workaround
[ 2058.475802] charger_hv_detect_sw_workaround
(3)时间点和时间段
很多时候在内核中,需要用到时间点和时间段的判断来处理事务,举例如下:
A,组合按键进入某个开机模式
BOOL recovery_check_key_trigger(void)
{
ulong begin = get_timer(0); //获得当前时间点
.........................
#ifdef MT65XX_RECOVERY_KEY
while (get_timer(begin) < 50) { //从当前点开始时间差
if (mtk_detect_key(MT65XX_RECOVERY_KEY)) {
printf("%s Detect cal key\n",MODULE_NAME);
printf("%s Enable recovery mode\n",MODULE_NAME);
g_boot_mode = RECOVERY_BOOT;
//video_printf("%s : detect recovery mode !\n",MODULE_NAME);
return TRUE;
}
}
#endif
.......................
return FALSE;
}
B,长按或者短按上报不同功能键值
kpd_keymap_handler中不同次按键中断,通过判断弹起的时间差上报不同键值
if((FACTORY_BOOT == get_boot_mode()) || (RECOVERY_BOOT == get_boot_mode()))
{
if((linux_keycode == KEY_BACK) && (pressed == 1))
{
singleK_click = 1;
singleK_click_ts = jiffies;
break ;
}
if(singleK_click == 1)
{
singleK_click = 0;
int t = jiffies_to_msecs(jiffies - singleK_click_ts) ;
if( t > 1000) //more than 1000ms
{
printk("KEY_MENU single click\n");
input_report_key(kpd_input_dev, KEY_MENU, 1);
input_sync(kpd_input_dev);
input_report_key(kpd_input_dev, KEY_MENU, 0);
input_sync(kpd_input_dev);
}
else
{
printk("KEY_BACK single click\n");
input_report_key(kpd_input_dev, KEY_BACK, 1);
input_sync(kpd_input_dev);
input_report_key(kpd_input_dev, KEY_BACK, 0);
input_sync(kpd_input_dev);
}
break;
}
}
================kthread线程相关的处理=========================
linux内核中创建线程方法:https://www.cnblogs.com/Ph-one/p/6077787.html。
Linux 线程调度与优先级设置:http://blog.youkuaiyun.com/a_ran/article/details/43759729(未验证)。