linux定时器使用

摘要:
作者:范英飞在内核中对计时器的定义:structtimer_List{/**在正常运行期间发生更改的所有字段分组到*samecache行*/structlist_header;//计时器的链接列表未签名长过期;//计时器时间(以节拍为单位),表示为计时器触发的过期时间structvec_base*base;v

作者: 樊颖飞

定时器在内核的定义:

struct timer_list {
  /*
   * All fields that change during normal runtime grouped to the
   * same cacheline
   */
  struct list_head entry; //定时器的链表
  unsigned long expires;//以节拍为单位的定时时间,表示为定时器触发的到期时间
  struct tvec_base *base;

  void (*function)(unsigned long); //该指针指向定时器处理函数,函数参数为长整形
  unsigned long data; //处理函数的参数值

  int slack;

#ifdef CONFIG_TIMER_STATS
  void *start_site;
  char start_comm[16];
  int start_pid;
#endif
#ifdef CONFIG_LOCKDEP
  struct lockdep_map lockdep_map;
#endif
};

使用定时器的步骤:
1) 定义定时器:

struct timer_list my_timer

2)初始化定时器:

初始化定时器的到期节拍数

my_timer.expires = jiffies +delay ;该设置让定时器的触发时间设置为 激活定时器后的delay个节拍点

my_timer.function = 处理函数的名称 该设置设置定时器触发时处理的函数

my_timer.data 初始化处理函数的参数值,若处理函数没有参数则可简单设置为0或任意其他数值

3)激活定时器:即内核会开始定时,直到my_timer.expires

使用函数add_timer 即 add_timer(&my_timer);

内核原型为:

void add_timer(struct timer_list *timer)
{
  BUG_ON(timer_pending(timer));
  mod_timer(timer, timer->expires); //该函数设置定时器timer的定时时间为timer->expires;
}

4)删除定时器:如果需要在定时器到期之前停止定时器,则可以使用该函数,若是定时器已经过期则不需调用该函数,因为它们会自动删除

del_timer(&my_timer);

定时器的简单实例:该例子的功能是首先初始化一个定时器,当定时器时间到后触发定时器出俩函数的执行,该函数又重新设置了该定时器的时间,即该定时器又在下一次定时时间的到来继续处理函数,一直循环,知道最后在该模块卸载时进行删除定时器,结束该定时器

代码中 HZ为内核每一秒的节拍数,是通过宏进行定义的,通过该程序的打印结果可以得到,本人电脑的节拍数测试结果为250

#include< linux/module.h >
#include< linux/init.h >
#include< linux/sched.h >
#include < linux/timer.h >

#include < linux/kernel.h >

struct timer_list stimer; //定义定时器
static void time_handler(unsigned long data){ //定时器处理函数
  mod_timer(&stimer, jiffies + HZ);
  printk(“current jiffies is %ld\n”, jiffies);
}
static int __init timer_init(void){ //定时器初始化过程
  printk(“My module worked!\n”);
  init_timer(&stimer);
  stimer.data = 0;
  stimer.expires = jiffies + HZ; //设置到期时间
  stimer.function = time_handler;
  add_timer(&stimer);
  return 0;
}
static void __exit timer_exit(void){
  printk(“Unloading my module.\n”);
  del_timer(&stimer);//删除定时器
  return;
}
module_init(timer_init);//加载模块
module_exit(timer_exit);//卸载模块

MODULE_AUTHOR(“fyf”);

MODULE_LICENSE(“GPL”);

加载/ 卸载该程序后通过命令dmesg可以看到

[ 6225.522208] My module worked!
[ 6226.520014] current jiffies is 1481630
[ 6227.520014] current jiffies is 1481880
[ 6228.520013] current jiffies is 1482130
[ 6229.520011] current jiffies is 1482380
[ 6229.770335] Unloading my module.
即每2次的jiffies之差为250

定时器的应用:以下是一个简单的延迟当前进程执行的程序,延迟是通过定时器来实现的;

#include< linux/module.h >
#include< linux/init.h >
#include< linux/sched.h >
#include < linux/timer.h >
#include < linux/kernel.h >
struct timer_list stimer; //定义定时器
int timeout = 10 * HZ;
static void time_handler(unsigned long data){ //定时器处理函数,执行该函数获取挂起进程的pid,唤醒该进程
  struct task_struct *p = (struct task_struct *)data;//参数为挂起进程pid
  wake_up_process(p);//唤醒进程
  printk(“current jiffies is %ld\n”, jiffies); //打印当前jiffies
}
static int __init timer_init(void){ //定时器初始化过程
  printk(“My module worked!\n”);
  init_timer(&stimer);
  stimer.data = (unsigned long)current; //将当前进程的pid作为参数传递
  stimer.expires = jiffies + timeout; //设置到期时间
  stimer.function = time_handler;
  add_timer(&stimer);
  printk(“current jiffies is %ld\n”, jiffies);
  set_current_state(TASK_INTERRUPTIBLE);
  schedule(); //挂起该进程
  del_timer(&stimer); //删除定时器
  return 0;
}
static void __exit timer_exit(void){
  printk(“Unloading my module.\n”);
  return;
}
module_init(timer_init);//加载模块
module_exit(timer_exit);//卸载模块
MODULE_AUTHOR(“fyf”);
MODULE_LICENSE(“GPL”);

运行结果:

[ 9850.099121] My module worked!
[ 9850.099127] current jiffies is 2387524
[ 9860.128017] current jiffies is 2390032
[ 9869.135805] Unloading my module.

打印结果与定时时间2500有一点差距,是因为打印时第一次的jiffies实在add_timer之后打印的,故不是定时器激发时的jiffies,第二次同理,所以结果不是确定的,但都于2500相差不多

免责声明:文章转载自《linux定时器使用》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Vue的介绍&amp;amp;原理iOS状态栏详解(隐藏)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

[201020] Manjaro(KDE桌面环境)小白向完全安装教程(附Linux简要介绍)

本文并非网上常见的安装试错文,这一点还请读者大可放心。 本文力求做到手把手教学,尽量为系统安装过程中每个步骤给出截图并做出必要的说明。不过即便如此也难免有疏漏之处,到时还请读者自行咨询搜索引擎。在Linux的使用过程中一定会遇到各种各样的问题,搜索引擎永远是你最好的伴侣。 基础知识 不需这些知识,想要直接按步骤安装系统的读者可以直接跳过本节。 开始教程前首...

linux 3.10 的中断收包笔记

来看下NAPI和非NAPI的区别: (1) 支持NAPI的网卡驱动必须提供轮询方法poll()。 (2) 非NAPI的内核接口为netif_rx(),NAPI的内核接口为napi_schedule(),或者类似的__napi_schedule之类的,总之都是在硬中断中调用对应的函数。 (3) 非NAPI使用共享的CPU队列softnet_data->...

gpio IOCTL控制

之前工作的时候,linux下用过GPIO的,无非就是配置输出输入模式,set/get value ,或者是gpio中断之类的,用户态配置GPIO主要是两种方式:用户态使用mmap直接将GPIO 地址映射过来,操作地址, 或者 IOCTL发命令给内核,内核来控制,最近半年都在写单片机的代码。时间久了有点忘了,最近使用都是偷懒直接使用了/sys下的设备,通过s...

linux定时任务执行没结果,手动执行有结果问题总结

今天写了个脚本手动执行有结果,但是放到系统定时任务跑却没结果,之前也遇到这种问题解决了没记录后面又懵逼了一次~~~ 如下图: 手动执行有结果 放到定时任务中每五分钟执行一次 解决方法: 脚本中加载系统环境变量 source /etc/profile 如果不加入脚本定时任务可以这样写效果一样 */5 * * * * ./etc/profile;sh /f...

linux时间同步ntp服务的安装与配置

当我们需要管理多台服务器的时间时,一台一台的修改未免太麻烦了,NTP服务就很好的为我们解决了这个问题! 1.首先安装NTP [root@localhost /]# yum install ntp -y 2.修改NTP配置文件,添加NTP服务器的网络位置    /etc/ntp.conf   # For more information about thi...

linux clamav杀毒软件的安装

一、概述   Linux比其它操作系统更稳定更安全。理论上Linux是有可能被病毒侵害的。但实际上 Linux机器几乎不可能遭受病毒的攻击。所以我这里的问题是为什么要为Linux准备防病毒软件,为了更好理解,我准备了以下理由,Linux平台安装杀毒软件的原因:1、从Linux平台扫描Windows驱动。2、通过网络扫描Windows工作站。3、在Linux...