九鼎创展论坛中文版English
登录 | 立即注册 设为首页收藏本站 切换到宽版
查看: 4329|回复: 0
打印 上一主题 下一主题

x4412&ibox项目实战45-Linux内核定时器编程实验

[复制链接]
跳转到指定楼层
楼主
发表于 2014-10-14 17:07:55 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
内核定时器是管理内核时间的基础。内核经常要推迟执行一些代码,如底半部机制就是为了将工作推后执行。时钟中断由系统的定时硬件以周期性的时间间隔产生,这个间隔由内核根据HZ来确定。每当时钟中断发生时,全局变量jiffies(unsigned long)就加1,因此jiffies记录了自linux启动后时钟中断发生的次数。内核定时器用于控制定时器处理函数在未来的某个特定时间执行。内核定时器注册的处理函数只执行一次,它在超时后就自行销毁,动态定时器不断地创建和销毁,而且它的运行次数也不受限制。
定时器的使用只须执行一些初始化工作,设置一个超时时间,指定超时发生后执行的函数,然后激活定时器就可以了。我们从一个简单的秒定时器驱动实例开始。
编写一个简单的秒定时器驱动,应用从驱动中读取定时器值并打印出来。
在kernel/drivers/char/x4412目录下新建x4412-second.c文件,编辑内容如下:
  1. #include <linux/kernel.h>
  2. #include <linux/module.h>
  3. #include <linux/init.h>
  4. #include <linux/fs.h>
  5. #include <linux/cdev.h>
  6. #include <linux/uaccess.h>
  7. #include <linux/timer.h>
  8. #include <asm/atomic.h>
  9. #include <linux/slab.h>
  10. #include <linux/device.h>

  11. static int x4412_second_major;
  12. static struct class *cdev_class;
  13. struct x4412_second_dev{
  14.          struct cdev cdevp;
  15.          atomic_t counter;
  16.          struct timer_list s_timer;
  17. };
  18. struct x4412_second_dev *second_devp;
  19. static void second_timer_handle(unsigned long arg)
  20. {
  21.          mod_timer(&second_devp->s_timer,jiffies+HZ);
  22.          atomic_inc(&second_devp->counter);
  23. }
  24. static int x4412_second_open(struct inode *inode,struct file *filp)
  25. {
  26.     init_timer(&second_devp->s_timer);  
  27.     second_devp->s_timer.function=&second_timer_handle;
  28.     second_devp->s_timer.expires=jiffies+HZ;
  29.     add_timer(&second_devp->s_timer);
  30.     atomic_set(&second_devp->counter,0);
  31.     return 0;
  32. }
  33. int x4412_second_release(struct inode *inode,struct file *filp)
  34. {  
  35.     del_timer(&second_devp->s_timer);
  36.     return 0;
  37. }
  38. static ssize_t x4412_second_read(struct file *filp,char __user *buf,size_t count,loff_t *ppos)
  39. {
  40.      int counter;
  41.     counter=atomic_read(&second_devp->counter);
  42.     if(copy_to_user(buf,&counter,0x4))
  43.                      return -EFAULT;
  44.     else
  45.                   return sizeof(unsigned int);
  46. }
  47. static const struct file_operations second_fops={
  48.     .owner=THIS_MODULE,
  49.     .open=x4412_second_open,
  50.     .release=x4412_second_release,
  51.     .read=x4412_second_read,
  52. };
  53. static void second_setup_cdev(struct x4412_second_dev *second_devp,int index)
  54. {
  55.     int err,devno=MKDEV(x4412_second_major,index);
  56.     cdev_init(&second_devp->cdevp,&second_fops);
  57.     second_devp->cdevp.owner=THIS_MODULE;
  58.     second_devp->cdevp.ops=&second_fops;
  59.     err=cdev_add(&second_devp->cdevp,devno,1);
  60.     if(err)
  61.                      printk("add the second cdev failly");
  62. }
  63. static void x4412_clear_cdev(void)
  64. {
  65.          cdev_del(&second_devp->cdevp);
  66.          unregister_chrdev_region(MKDEV(x4412_second_major, 0), 1);
  67. }
  68. int __init x4412_second_init(void)
  69. {
  70.     int ret;
  71.     dev_t devno;
  72.         ret=alloc_chrdev_region(&devno,0,1,"x4412-second");
  73.         x4412_second_major=MAJOR(devno);
  74.     if(ret<0)
  75.                       return ret;
  76.     second_devp=kmalloc(sizeof(struct x4412_second_dev),GFP_KERNEL);
  77.     if(!second_devp)
  78.     {
  79.                    ret=-ENOMEM;
  80.                    goto fail_malloc;
  81.     }
  82.          memset(second_devp,0,sizeof(struct x4412_second_dev));
  83.          second_setup_cdev(second_devp,0);
  84.          cdev_class = class_create(THIS_MODULE,"x4412-second");
  85.          if(IS_ERR(cdev_class))
  86.          {
  87.                    x4412_clear_cdev();
  88.                    return PTR_ERR(cdev_class);
  89.          }
  90.          device_create(cdev_class,NULL,MKDEV(x4412_second_major,0),NULL,"x4412-second");
  91.     return 0;
  92. fail_malloc:
  93.          unregister_chrdev_region(devno,1);
  94.          return -1;
  95. }
  96. void x4412_second_exit(void)
  97. {
  98. device_destroy(cdev_class,MKDEV(x4412_second_major,0));
  99.          class_destroy(cdev_class);
  100.     cdev_del(&second_devp->cdevp);
  101.     kfree(second_devp);
  102.     unregister_chrdev_region(MKDEV(x4412_second_major,0),1);
  103. }
  104. MODULE_AUTHOR("www.9tripod.com");
  105. MODULE_LICENSE("Dual BSD/GPL");
  106. module_init(x4412_second_init);
  107. module_exit(x4412_second_exit);
复制代码
       编辑kernel/drivers/char/x4412/Kconfig文件,添加如下语句:
  1. config X4412_SECOND_DRIVER
  2.          tristate "x4412 second timer driver"
  3.          default m
  4.          help
  5.          compile for x4412 second timer driver,y for kernel,m for module.
复制代码
       编辑kernel/drivers/char/x4412/Makefile文件,添加如下语句:
  1. obj-$(CONFIG_X4412_SECOND_DRIVER) += x4412-second.o
复制代码
       编译内核,在kernel/drivers/char/x4412目录下将会生成目标文件x4412-second.ko
       ubuntu用户目录或samba目录下新建应用程序x4412-second-app.c文件,编辑内容如下:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <fcntl.h>

  4. main()
  5. {
  6.          int fd;
  7.          int counter = 0;
  8.          int old_counter = 0;
  9.          /*打开/dev/second 设备文件*/
  10.          fd = open("/dev/x4412-second", O_RDONLY);
  11.          if (fd != - 1)
  12.          {
  13.                    while (1)
  14.                    {
  15.                             read(fd,&counter, sizeof(unsigned int));//读目前经历的秒数
  16.                             if(counter!=old_counter)
  17.                             {
  18.                                      printf("seconds after open /dev/x4412-second :%d\n",counter);
  19.                                      old_counter = counter;
  20.                             }
  21.                    }
  22.          }
  23.          else
  24.          {
  25.                    printf("Device open failure\n");
  26.          }
  27. }
复制代码
    执行如下指令编译应用程序:
  1. arm-none-linux-gnueabi-gcc x4412-second-app.c -o x4412-second-app
复制代码
       加载驱动模块后,运行应用程序,观察测试效果:
  1. [root@x4412 mnt]# insmod x4412-second.ko
  2. [root@x4412 mnt]# ./x4412-second-app
  3. [   77.851276] CPU2: Booted secondary processor
  4. [   77.855022] Switched to NOHz mode on CPU #2
  5. seconds after open /dev/x4412-second :1
  6. seconds after open /dev/x4412-second :2
  7. seconds after open /dev/x4412-second :3
  8. seconds after open /dev/x4412-second :4
  9. seconds after open /dev/x4412-second :5
  10. seconds after open /dev/x4412-second :6

  11. [root@x4412 mnt]#
复制代码
       通过实例,回过头来分析定时器的使用方法。
       第一步:定义一个定时器:
  1. struct timer_list s_timer;
复制代码
       第二步:在open函数中初始化定时器,并指定定时器服务函数,设置定时器到期时间,然后将定时器添加到内核定时器链表。
  1. static int x4412_second_open(struct inode *inode,struct file *filp)
  2. {
  3.      ……
  4.     init_timer(&second_devp->s_timer);//打开驱动时初始化定时器
  5.     second_devp->s_timer.function=&second_timer_handle;//指定定时器服务函数
  6.     second_devp->s_timer.expires=jiffies+HZ;//设定定时器到期时间为1秒
  7.     add_timer(&second_devp->s_timer);//将定时器添加到内核定时器链表
  8.      ……
  9. }
复制代码
       第三步:编写定时器服务函数:
  1. static void second_timer_handle(unsigned long arg)
  2. {
  3.          mod_timer(&second_devp->s_timer,jiffies+HZ);//修改定时器的expire并再次启动
  4.          ……
  5. }
复制代码
       第四步:在release函数中删除定时器:
  1. int x4412_second_release(struct inode *inode,struct file *filp)
  2. {
  3.     del_timer(&second_devp->s_timer);//关闭驱动时删除定时器
  4.     ……
  5. }
复制代码
       在本示例中还定义了一个原子变量,用于记录定时器一共经历了多少秒。在open函数中,初始化原子变量为0,然后每发生一次定时器中断,原子变量加1。在read函数中,通过atomic_read函数读出原子变量值,并通过copy_to_user函数上报给应用。在open函数中定义的定时器到期时间为jiffies+HZ,这里HZ表示1秒,jiffies记录了系统启动后所经历的时间,jiffies+HZ表示从当前时间开始,再过1秒触发定时器中断,即定时器时间为1秒。由于定时器的工作是不连续的,因此在中断服务函数中通过mod_timer函数重新修改定时器到期时间,并再次启动。修改后的到期时间仍然为jiffies+HZ,这时的jiffies和之前的jiffies值已经不同了,它记录的是当前时间,不断的会增加。正是利用了jiffies的特性,巧妙的实现了间隔一秒循环定时的功能。
编译好的映像:
x4412-second.ko (4.33 KB, 下载次数: 5)
x4412-second-app (6.06 KB, 下载次数: 4)
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳市九鼎创展科技官方论坛 ( 粤ICP备11028681号-2  

GMT+8, 2024-6-23 10:42 , Processed in 0.020685 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表