**linux timer

说明:

/******************
 * linux内核的时间管理
 ******************/

(1)内核中的时间概念
  时间管理在linux内核中占有非常重要的作用。相对于事件驱动而言,内核中有大量函数是基于时间驱动的。
  有些函数是周期执行的,比如每10毫秒刷新一次屏幕;有些函数是推后一定时间执行的,比如内核在500毫秒后执行某项任务。
  要区分:
    *绝对时间和相对时间
    *周期性产生的事件和推迟执行的事件
  周期性事件是由系统系统定时器驱动的
(2)HZ值
  内核必须在硬件定时器的帮助下才能计算和管理时间。定时器产生中断的频率称为节拍率(tick rate)。
  在内核中指定了一个变量HZ,内核初始化的时候会根据这个值确定定时器的节拍率。
  HZ定义在<asm/param.h>,在i386平台上,目前采用的HZ值是1000。
  也就是时钟中断每秒发生1000次,周期为1毫秒。即:#define HZ 1000
  注意!HZ不是个固定不变的值,它是可以更改的,可以在内核源代码配置的时候输入。
  不同的体系结构其HZ值是不一样的,比如arm就采用100。
  如果在驱动中要使用系统的中断频率,直接使用HZ,而不要用100或1000。
a.理想的HZ值
  i386的HZ值一直采用100,直到2.5版后才改为1000。提高节拍率意味着时钟中断产生的更加频繁,中断处理程序也会更频繁地执行。
  带来的好处有:
    *内核定时器能够以更高的频率和更高的准确度运行
    *依赖定时器执行的系统调用,比如poll()和select(),运行的精度更高
    *提高进程抢占的准确度(缩短了调度延时,如果进程还剩2ms时间片,在10ms的调度周期下,进程会多运行8ms。由于耽误了抢占,对于一些对时间要求严格的任务会产生影响)
  坏处有:
    *节拍率越高,系统负担越重。中断处理程序将占用更多的处理器时间。
(3)jiffies
  全局变量jiffies用于记录系统启动以来产生的节拍的总数。
  启动时,jiffies初始化为0,此后每次时钟中断处理程序都会增加该变量的值。这样,系统启动后的运行时间就是jiffies/HZ秒。
  jiffies定义于<linux/jiffies.h>中:extern unsigned long volatile jiffies;
  jiffies变量总是为unsigned long型。因此在32位体系结构上是32位,而在64位体系上是64位。
  对于32位的jiffies,如果HZ为1000,49.7天后会溢出。虽然溢出的情况不常见,但程序在检测超时时仍然可能因为回绕而导致错误。
  linux提供了4个宏来比较节拍计数,它们能正确地处理节拍计数回绕。
    #include <linux/jiffies.h>
    #define time_after(unknown, known)       // unknow >  known
    #define time_before(unknown, known)      // unknow <  known
    #define time_after_eq(unknown, known)    // unknow >= known
    #define time_before_eq(unknown, known)   // unknow <= known
  unknown通常是指jiffies,known是需要对比的值(常常是一个jiffies加减后计算出的相对>值)。例如:
    unsigned long timeout = jiffies + HZ/2; /* 0.5秒后超时 */
    ...
    if(time_before(jiffies, timeout)){
            /* 没有超时,很好 */
    }else{
            /* 超时了,发生错误 */

    }
  time_before可以理解为如果在超时(timeout)之前(before)完成。
  *系统中还声明了一个64位的值jiffies_64,在64位系统中jiffies_64和jiffies是一个值。可以通过get_jiffies_64()获得这个值。
  *使用  u64 j2;        j2 = get_jiffies_64();
(4)获得当前时间
  驱动程序中一般不需要知道墙钟时间(也就是年月日的时间)。但驱动可能需要处理绝对时间。
  为此,内核提供了两个结构体,都定义在<linux/time.h>:
  a.较老,但很流行。采用秒和毫秒值,保存了1970年1月1日0点以来的秒数。
    struct timeval {
      time_t tv_sec; /* seconds */
      suseconds_t tv_usec; /* microseconds */
    };
  b.较新,采用秒和纳秒值保存时间。
    struct timespec {
      time_t  tv_sec; /* seconds */
      long tv_nsec; /* nanoseconds */
    };
  c.函数do_gettimeofday():该函数用通常的秒或微秒来填充一个指向struct timeval的指针变量,原型如下:
    #include <linux/time.h>
    void do_gettimeofday(struct timeval *tv);
  d.函数current_kernel_time():该函数可用于获得timespec,原型如下:
    #include <linux/time.h>
    struct timespec current_kernel_time(void);

 

/********************
 *确定时间的延迟执行
 *******************/

设备驱动程序经常需要将某些特定代码延迟一段时间后执行,通常是为了让硬件能完成某些任务。
长于定时器周期(也称为时钟嘀嗒)的延迟可以通过使用系统时钟完成,而非常短的延时则通过软件循环的方式完成。
(1)短延时
  对于那些最多几十个毫秒的延迟,无法借助系统定时器。系统通过软件循环提供了下面的延迟函数:
    #include <linux/delay.h>          /* 实际在<asm/delay.h> */
    void ndelay(unsigned long nsecs);  /*延迟纳秒 */
    void udelay(unsigned long usecs);  /*延迟微秒 */
    void mdelay(unsigned long msecs);  /*延迟毫秒 */
  这三个延迟函数均是忙等待函数,在延迟过程中无法运行其他任务。实际上,当前所有平台都无法达到纳秒精度。
(2)长延时
  a.在延迟到期前让出处理器
    while(time_before(jiffies, j1))
      schedule();
    在等待期间可以让出处理器,但系统无法进入空闲模式(因为这个进程始终在进行调度),不利于省电。
  b.超时函数
    #include <linux/sched.h>
    signed long schedule_timeout(signed long timeout);
    使用方式:
      set_current_state(TASK_INTERRUPTIBLE);
      schedule_timeout(2*HZ);  /* 睡2秒 */
    进程经过2秒后会被唤醒。如果不希望被用户空间打断,可以将进程状态设置为TASK_UNINTERRUPTIBLE。
(3)等待队列
  使用等待队列也可以实现长延迟。在延迟期间,当前进程在等待队列中睡眠。进程在睡眠时,需要根据所等待的事件链接到某一个等待队列。
  a.声明等待队列
    等待队列实际上就是一个进程链表,链表中包含了等待某个特定事件的所有进程。
    #include <linux/wait.h>
    struct __wait_queue_head {
      spinlock_t lock;
      struct list_head task_list;
    };
    typedef struct __wait_queue_head wait_queue_head_t;
    想把进程加入等待队列,驱动首先要在模块中声明一个等待队列头,并将它初始化。
  b.静态初始化
    DECLARE_WAIT_QUEUE_HEAD(name);
  c.动态初始化
    wait_queue_head_t my_queue;
    init_waitqueue_head(&my_queue);
  d.等待函数
    进程通过调用下面函数可以在某个等待队列中休眠固定的时间:
    #include <linux/wait.h>
    long wait_event_timeout(wait_queue_head_t q,condition, long timeout);
    long wait_event_interruptible_timeout(wait_queue_head_t q, condition, long timeout);
    调用这两个函数后,进程会在给定的等待队列q上休眠,但会在超时(timeout)到期时返回。
    如果超时到期,则返回0,如果进程被其他事件唤醒,则返回剩余的时间数。
    如果没有等待条件,则将condition设为0
  e.使用方式:
    wait_queue_head_t wait;
    init_waitqueue_head(&wait);
    wait_event_interruptible_timeout(wait, 0, 2*HZ);  /*当前进程在等待队列wait中睡2秒 */

(4)内核定时器
  还有一种将任务延迟执行的方法是采用内核定时器。
  与前面几种延迟方法不同,内核定时器并不会阻塞当前进程,启动一个内核定时器只是声明了要在未来的某个时刻执行一项任务,当前进程仍然继续执行。
  不要用定时器完成硬实时任务!
  定时器由结构timer_list表示,定义在<linux/timer.h>
    struct timer_list{
      struct list_head entry; /* 定时器链表 */
      unsigned long expires; /* 以jiffies为单位的定时值 */
      spinlock_t lock;
      void(*function)(unsigned long); /* 定时器处理函数 */
      unsigned long data;  /* 传给定时器处理函数的参数 */
    };
  内核在<linux/timer.h>中提供了一系列管理定时器的接口。
  a.创建定时器
    struct timer_list my_timer;
  b.初始化定时器
    init_timer(&my_timer);  /* 填充数据结构 */
    my_timer.expires = jiffies + delay;
    my_timer.data = 0;
    my_timer.function = my_function; /*定时器到期时调用的函数*/
  c.定时器的执行函数
    超时处理函数的原型如下:
    void my_timer_function(unsigned long data);
    可以利用data参数用一个处理函数处理多个定时器。可以将data设为0。
  d.激活定时器
    add_timer(&my_timer);
    定时器一旦激活就开始运行。
  e.更改已激活的定时器的超时时间
    mod_timer(&my_timer, jiffies+ney_delay);
    可以用于那些已经初始化但还没激活的定时器,如果调用时定时器未被激活则返回0,否则返回1。
    一旦mod_timer返回,定时器将被激活。
  f.删除定时器
    del_timer(&my_timer);
    被激活或未被激活的定时器都可以使用,如果调用时定时器未被激活则返回0,否则返回1。
    不需要为已经超时的定时器调用,它们被自动删除
  g.同步删除
    del_time_sync(&my_timer);
    在smp系统中,确保返回时,所有的定时器处理函数都退出。不能在中断上下文使用!

 

/********************
 *不确定时间的延迟执行
 *******************/

(1)什么是不确定时间的延迟
  前面介绍的是确定时间的延迟执行,但在写驱动的过程中经常遇到这种情况:
  用户空间程序调用read函数从设备读数据,但设备中当前没有产生数据。
  此时,驱动的read函数默认的操作是进入休眠,一直等待到设备中有了数据为止。
  这种等待就是不定时的延迟,通常采用休眠机制来实现。
(2)休眠
  休眠是基于等待队列实现的,前面我们已经介绍过wait_event系列函数,但现在我们将不会有确定的休眠时间。
  当进程被置入休眠时,会被标记为特殊状态并从调度器的运行队列中移走。
  直到某些事件发生后,如设备接收到数据,则将进程重新设为运行态并进入运行队列进行调度。
  休眠函数的头文件是<linux/wait.h>,具体的实现函数在kernel/wait.c中。
  a.休眠的规则
    *永远不要在原子上下文中休眠
    *当被唤醒时,我们无法知道睡眠了多少时间,也不知道醒来后是否获得了我们需要的资源
    *除非知道有其他进程会在其他地方唤醒我们,否则进程不能休眠
  b.等待队列的初始化
    见前文
  c.休眠函数
    linux最简单的睡眠方式为wait_event宏。该宏在实现休眠的同时,检查进程等待的条件。
    1. void wait_event(wait_queue_head_t q, int condition);
    2. int wait_event_interruptible(wait_queue_head_t q, int condition);
      q: 是等待队列头,注意是采用值传递。
      condition: 任意一个布尔表达式,在条件为真之前,进程会保持休眠。
    注意!进程需要通过唤醒函数才可能被唤醒,此时需要检测条件。
    如果条件满足,则被唤醒的进程真正醒来;如果条件不满足,则进程继续睡眠。
  d.唤醒函数
    当我们的进程睡眠后,需要由其他的某个执行线程(可能是另一个进程或中断处理例程)唤醒。
    唤醒函数:
      #include <linux/wait.h>
      1. void wake_up(wait_queue_head_t *queue);
      2. void wake_up_interruptible(wait_queue_head_t *queue);
      wake_up会唤醒等待在给定queue上的所有进程。而wake_up_interruptible唤醒那些执行可中断休眠的进程。
    实践中,约定做法是在使用wait_event时使用wake_up,而使用wait_event_interruptible>时使用wake_up_interruptible。

 

参考文件:

  http://wenku.baidu.com/view/cc8c677b1711cc7931b71699.html
  http://blog.chinaunix.net/uid-23037472-id-2565394.html
  http://blog.csdn.net/heanyu/article/details/6552578
  

 

程序一:获取现在系统内核中的HZ值。

创建文件夹/nfsroot/kern/2012-05-11/01/。

创建文件/nfsroot/kern/2012-05-11/01/test.c,内容如下:

View Code
复制代码
 1 #include <linux/module.h>
 2 #include <linux/init.h>
 3 #include <linux/param.h>
 4 
 5 MODULE_LICENSE("GPL");
 6 
 7 static int __init test_init(void)
 8 {
 9     printk("HZ = %d\n", HZ);
10     return 0;
11 }
12 
13 static void __exit test_exit(void)
14 {
15 }
16 
17 module_init(test_init);
18 module_exit(test_exit);
复制代码

创建文件/nfsroot/kern/2012-05-11/01/Makefile,内容如下:

View Code
复制代码
 1 obj-m    := test.o
 2 
 3 KERN    := /timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410
 4 
 5 all:
 6     make -C $(KERN) M=`pwd` modules
 7 
 8 clean:
 9     make -C $(KERN) M=`pwd` modules clean
10     rm -f modules.order
复制代码

在主机端编译模块,过程如下:

View Code

在开发板端载入模块、查看输出、卸载模块,过程如下:

View Code

 

 

程序二:使用jiffies,获得系统启动时间。

创建文件夹/nfsroot/kern/2012-05-11/02/。

创建文件/nfsroot/kern/2012-05-11/02/test.c,内容如下:

View Code
复制代码
 1 #include <linux/module.h>
 2 #include <linux/init.h>
 3 #include <linux/param.h>
 4 #include <linux/jiffies.h>
 5 
 6 MODULE_LICENSE("GPL");
 7 
 8 static int __init test_init(void)
 9 {
10     unsigned long now;
11     int h, m, s;
12 
13     printk("jiffies = %lu\n", jiffies);
14 
15     now = jiffies / HZ;
16     h = now / (60 * 60);
17     m = (now % (60 * 60)) / 60;
18     s = now % 60; 
19 
20     printk("system up %d:%d:%d\n", h, m, s);
21 
22     return 0;
23 }
24 
25 static void __exit test_exit(void)
26 {
27 }
28 
29 module_init(test_init);
30 module_exit(test_exit);
复制代码

创建文件/nfsroot/kern/2012-05-11/02/Makefile,内容如下:

View Code
复制代码
 1 obj-m    := test.o
 2 
 3 KERN    := /timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410
 4 
 5 all:
 6     make -C $(KERN) M=`pwd` modules
 7 
 8 clean:
 9     make -C $(KERN) M=`pwd` modules clean
10     rm -f modules.order
复制代码

在主机端编译模块,过程如下:

View Code
复制代码
 1 [root@localhost 02]# pwd
 2 /nfsroot/kern/2012-05-11/02
 3 [root@localhost 02]# ls
 4 Makefile  test.c
 5 [root@localhost 02]# make
 6 make -C /timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410 M=`pwd` modules
 7 make[1]: Entering directory `/timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410'
 8   CC [M]  /nfsroot/kern/2012-05-11/02/test.o
 9   Building modules, stage 2.
10   MODPOST 1 modules
11   CC      /nfsroot/kern/2012-05-11/02/test.mod.o
12   LD [M]  /nfsroot/kern/2012-05-11/02/test.ko
13 make[1]: Leaving directory `/timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410'
14 [root@localhost 02]# ls
15 Makefile       Module.symvers  test.ko     test.mod.o
16 modules.order  test.c          test.mod.c  test.o
17 [root@localhost 02]# modinfo test.ko 
18 filename:       test.ko
19 license:        GPL
20 depends:        
21 vermagic:       2.6.28.6 mod_unload ARMv6 
22 [root@localhost 02]#
复制代码

在开发板端载入模块、查看输出、卸载模块,过程如下:

View Code
复制代码
 1 [root@timkyle 02]# pwd
 2 /kern/2012-05-11/02
 3 [root@timkyle 02]# ls
 4 Makefile        modules.order   test.ko         test.mod.o
 5 Module.symvers  test.c          test.mod.c      test.o
 6 [root@timkyle 02]# modinfo test.ko 
 7 filename:       test.ko
 8 license:        GPL
 9 vermagic:       2.6.28.6 mod_unload ARMv6 
10 [root@timkyle 02]# lsmod 
11 [root@timkyle 02]# insmod test.ko ; uptime 
12 jiffies = 4294913459
13 system up 5965:9:27
14  21:44:00 up 0 min, load average: 0.11, 0.02, 0.00
15 [root@timkyle 02]# rmmod test
16 [root@timkyle 02]# lsmod 
17 [root@timkyle 02]# uptime 
18  21:49:35 up 6 min, load average: 0.00, 0.00, 0.00
19 [root@timkyle 02]# insmod test.ko ; uptime 
20 jiffies = 14491
21 system up 0:1:12
22  21:49:42 up 6 min, load average: 0.00, 0.00, 0.00
23 [root@timkyle 02]# rmmod test
24 [root@timkyle 02]# lsmod 
25 [root@timkyle 02]# 
复制代码

由测试结果可知,系统启动时jiffies并不是初始化为0值!而且经过5分钟后,时间相对准确,但是误差是5分钟!原因如下:

View Code
1 /*
2  * Have the 32 bit jiffies value wrap 5 minutes after boot
3  * so jiffies wrap bugs show up earlier.
4  */
5 #define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ))

 


程序三:利用jiffies及相关宏,实现定时5秒。

创建文件夹/nfsroot/kern/2012-05-11/03/。

创建文件/nfsroot/kern/2012-05-11/03/test.c,内容如下:

View Code
复制代码
 1 #include <linux/module.h>
 2 #include <linux/init.h>
 3 #include <linux/param.h>
 4 #include <linux/jiffies.h>
 5 
 6 MODULE_LICENSE("GPL");
 7 
 8 static void show_uptime(void)
 9 {
10     unsigned long now;
11     int h, m, s;
12 
13     now = jiffies / HZ;
14     h = now / (60 * 60);
15     m = (now % (60 * 60)) / 60 + 5;
16     s = now % 60; 
17     printk("system up %d:%d:%d\n", h, m, s);
18 }
19 
20 static int __init test_init(void)
21 {
22     unsigned long pos;
23 
24     pos = jiffies + 5 * HZ;
25 
26     if (time_before(jiffies, pos))
27     {
28         printk("Please wait ...\n");
29     }
30 
31     show_uptime();
32 
33     while (!time_after(jiffies, pos))
34         ;    // nothing, just loop!
35 
36     show_uptime();
37 
38     return 0;
39 }
40 
41 static void __exit test_exit(void)
42 {
43 }
44 
45 module_init(test_init);
46 module_exit(test_exit);
复制代码

创建文件/nfsroot/kern/2012-05-11/03/Makefile,内容如下:

View Code
复制代码
 1 obj-m    := test.o
 2 
 3 KERN    := /timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410
 4 
 5 all:
 6     make -C $(KERN) M=`pwd` modules
 7 
 8 clean:
 9     make -C $(KERN) M=`pwd` modules clean
10     rm -f modules.order
复制代码

在主机端编译模块,过程如下:

View Code
复制代码
 1 [root@localhost 03]# pwd
 2 /nfsroot/kern/2012-05-11/03
 3 [root@localhost 03]# ls
 4 Makefile  test.c
 5 [root@localhost 03]# make
 6 make -C /timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410 M=`pwd` modules
 7 make[1]: Entering directory `/timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410'
 8   CC [M]  /nfsroot/kern/2012-05-11/03/test.o
 9   Building modules, stage 2.
10   MODPOST 1 modules
11   CC      /nfsroot/kern/2012-05-11/03/test.mod.o
12   LD [M]  /nfsroot/kern/2012-05-11/03/test.ko
13 make[1]: Leaving directory `/timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410'
14 [root@localhost 03]# ls
15 Makefile       Module.symvers  test.ko     test.mod.o
16 modules.order  test.c          test.mod.c  test.o
17 [root@localhost 03]# modinfo test.ko 
18 filename:       test.ko
19 license:        GPL
20 depends:        
21 vermagic:       2.6.28.6 mod_unload ARMv6 
22 [root@localhost 03]#
复制代码

在开发板端载入模块、查看输出、卸载模块,过程如下:

View Code
复制代码
 1 [root@timkyle 03]# pwd
 2 /kern/2012-05-11/03
 3 [root@timkyle 03]# ls
 4 Makefile        modules.order   test.ko         test.mod.o
 5 Module.symvers  test.c          test.mod.c      test.o
 6 [root@timkyle 03]# modinfo test.ko 
 7 filename:       test.ko
 8 license:        GPL
 9 vermagic:       2.6.28.6 mod_unload ARMv6 
10 [root@timkyle 03]# lsmod 
11 [root@timkyle 03]# insmod test.ko ; uptime 
12 Please wait ...
13 system up 0:27:27
14 system up 0:27:32
15  22:11:02 up 27 min, load average: 0.29, 0.11, 0.02
16 [root@timkyle 03]# rmmod test
17 [root@timkyle 03]# lsmod 
18 [root@timkyle 03]#
复制代码

 

 

程序四:获取系统当前的绝对时间(自1970年经过的秒数)。

创建文件夹/nfsroot/kern/2012-05-11/04/。

创建文件/nfsroot/kern/2012-05-11/04/test.c,内容如下:

View Code
复制代码
 1 #include <linux/module.h>
 2 #include <linux/init.h>
 3 #include <linux/param.h>
 4 #include <linux/jiffies.h>
 5 #include <linux/time.h>
 6 
 7 MODULE_LICENSE("GPL");
 8 
 9 static struct timeval tv;
10 static struct timespec ts;
11 
12 /*
13 static void show_uptime(void)
14 {
15     unsigned long now;
16     int h, m, s;
17 
18     now = jiffies / HZ;
19     h = now / (60 * 60);
20     m = (now % (60 * 60)) / 60 + 5;
21     s = now % 60; 
22     printk("system up %d:%d:%d\n", h, m, s);
23 }
24 */
25 
26 static int __init test_init(void)
27 {
28     do_gettimeofday(&tv);
29     printk("timeval.tv_sec = %ld; timeval.tv_usec = %ld\n", tv.tv_sec, tv.tv_usec);
30 
31     ts = current_kernel_time();
32     printk("timespec.tv_set = %ld; timespec.tv_nsec = %ld\n", ts.tv_sec, ts.tv_nsec);
33 
34     return 0;
35 }
36 
37 static void __exit test_exit(void)
38 {
39 }
40 
41 module_init(test_init);
42 module_exit(test_exit);
复制代码

创建文件/nfsroot/kern/2012-05-11/04/Makefile,内容如下:

View Code
复制代码
 1 obj-m    := test.o
 2 
 3 KERN    := /timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410
 4 
 5 all:
 6     make -C $(KERN) M=`pwd` modules
 7 
 8 clean:
 9     make -C $(KERN) M=`pwd` modules clean
10     rm -f modules.order
复制代码

在主机端编译模块,过程如下:

View Code
复制代码
 1 [root@localhost 04]# pwd
 2 /nfsroot/kern/2012-05-11/04
 3 [root@localhost 04]# ls
 4 Makefile  test.c
 5 [root@localhost 04]# make
 6 make -C /timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410 M=`pwd` modules
 7 make[1]: Entering directory `/timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410'
 8   CC [M]  /nfsroot/kern/2012-05-11/04/test.o
 9   Building modules, stage 2.
10   MODPOST 1 modules
11   CC      /nfsroot/kern/2012-05-11/04/test.mod.o
12   LD [M]  /nfsroot/kern/2012-05-11/04/test.ko
13 make[1]: Leaving directory `/timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410'
14 [root@localhost 04]# ls
15 Makefile       Module.symvers  test.ko     test.mod.o
16 modules.order  test.c          test.mod.c  test.o
17 [root@localhost 04]# modinfo test.ko 
18 filename:       test.ko
19 license:        GPL
20 depends:        
21 vermagic:       2.6.28.6 mod_unload ARMv6 
22 [root@localhost 04]# 
复制代码

在开发板端载入模块、查看输出、卸载模块,过程如下:

View Code
复制代码
 1 [root@timkyle 04]# pwd
 2 /kern/2012-05-11/04
 3 [root@timkyle 04]# ls
 4 Makefile        modules.order   test.ko         test.mod.o
 5 Module.symvers  test.c          test.mod.c      test.o
 6 [root@timkyle 04]# modinfo test.ko 
 7 filename:       test.ko
 8 license:        GPL
 9 vermagic:       2.6.28.6 mod_unload ARMv6 
10 [root@timkyle 04]# lsmod 
11 [root@timkyle 04]# insmod test.ko 
12 timeval.tv_sec = 1370558041; timeval.tv_usec = 904708
13 timespec.tv_set = 1370558041; timespec.tv_nsec = 903603000
14 [root@timkyle 04]# rmmod test
15 [root@timkyle 04]# lsmod 
16 [root@timkyle 04]#
复制代码


程序五:短延时及长延时。

创建文件夹/nfsroot/kern/2012-05-11/05/。

创建文件/nfsroot/kern/2012-05-11/05/test.c,内容如下:

View Code
复制代码
 1 #include <linux/module.h>
 2 #include <linux/init.h>
 3 #include <linux/delay.h>
 4 #include <linux/jiffies.h>
 5 #include <linux/param.h>
 6 #include <linux/sched.h>
 7 
 8 MODULE_LICENSE("GPL");
 9 
10 static unsigned long dly = 100;
11 
12 static int __init test_init(void)
13 {
14     unsigned long end;
15 
16     printk("start delay %ld nsecs\n", dly);
17     ndelay(dly);
18     printk("end delay %ld nsecs\n", dly);
19     
20     printk("start delay %ld usecs\n", dly);
21     udelay(dly);
22     printk("end delay %ld usecs\n", dly);
23     
24     printk("start delay %ld msecs\n", dly);
25     mdelay(dly);
26     printk("end delay %ld msecs\n", dly);
27 
28     printk("start delay 5 secs\n");
29     end = jiffies + 5 * HZ;
30     while (time_before(jiffies, end))
31         schedule();
32     printk("end delay 5 secs\n");
33     
34     printk("start delay 10 secs\n");
35     set_current_state(TASK_INTERRUPTIBLE);
36     schedule_timeout(10 * HZ);
37     printk("end delay 10 secs\n");
38 
39     return 0;
40 }
41 
42 static void __exit test_exit(void)
43 {
44 }
45 
46 module_init(test_init);
47 module_exit(test_exit);
复制代码

创建文件/nfsroot/kern/2012-05-11/05/Makefile,内容如下:

View Code
复制代码
 1 obj-m    := test.o
 2 
 3 KERN    := /timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410
 4 
 5 all:
 6     make -C $(KERN) M=`pwd` modules
 7 
 8 clean:
 9     make -C $(KERN) M=`pwd` modules clean
10     rm -f modules.order
复制代码

在主机端编译模块,过程如下:

View Code
复制代码
 1 [root@localhost 05]# pwd
 2 /nfsroot/kern/2012-05-11/05
 3 [root@localhost 05]# ls
 4 Makefile  test.c
 5 [root@localhost 05]# make
 6 make -C /timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410 M=`pwd` modules
 7 make[1]: Entering directory `/timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410'
 8   CC [M]  /nfsroot/kern/2012-05-11/05/test.o
 9   Building modules, stage 2.
10   MODPOST 1 modules
11   CC      /nfsroot/kern/2012-05-11/05/test.mod.o
12   LD [M]  /nfsroot/kern/2012-05-11/05/test.ko
13 make[1]: Leaving directory `/timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410'
14 [root@localhost 05]# ls
15 Makefile       Module.symvers  test.ko     test.mod.o
16 modules.order  test.c          test.mod.c  test.o
17 [root@localhost 05]# modinfo test.ko 
18 filename:       test.ko
19 license:        GPL
20 depends:        
21 vermagic:       2.6.28.6 mod_unload ARMv6 
22 [root@localhost 05]# 
复制代码

在开发板端载入模块、查看输出、卸载模块,过程如下:

View Code
复制代码
 1 [root@timkyle 05]# ls
 2 Makefile        modules.order   test.ko         test.mod.o
 3 Module.symvers  test.c          test.mod.c      test.o
 4 [root@timkyle 05]# modinfo test.ko 
 5 filename:       test.ko
 6 license:        GPL
 7 vermagic:       2.6.28.6 mod_unload ARMv6 
 8 [root@timkyle 05]# insmod test.ko 
 9 start delay 100 nsecs
10 end delay 100 nsecs
11 start delay 100 usecs
12 end delay 100 usecs
13 start delay 100 msecs
14 end delay 100 msecs
15 start delay 5 secs
16 end delay 5 secs
17 start delay 10 secs
18 end delay 10 secs
19 [root@timkyle 05]# lsmod 
20 test 1440 0 - Live 0xbf054000
21 [root@timkyle 05]# rmmod test
22 [root@timkyle 05]# lsmod 
23 [root@timkyle 05]# 
复制代码

 

程序六:使用等待队列延时。

创建文件夹/nfsroot/kern/2012-05-11/06/。

创建文件/nfsroot/kern/2012-05-11/06/test.c,内容如下:

View Code
复制代码
 1 #include <linux/module.h>
 2 #include <linux/init.h>
 3 #include <linux/wait.h>
 4 #include <linux/param.h>
 5 #include <linux/sched.h>
 6 
 7 MODULE_LICENSE("GPL");
 8 
 9 static wait_queue_head_t wait;
10 
11 static int __init test_init(void)
12 {
13     init_waitqueue_head(&wait);
14 
15     printk("start to wait 10 secs\n");
16     wait_event_interruptible_timeout(wait, 0, 10 * HZ);
17     printk("end to wait 10 secs\n");
18 
19     return 0;
20 }
21 
22 static void __exit test_exit(void)
23 {
24 }
25 
26 module_init(test_init);
27 module_exit(test_exit);
复制代码

创建文件/nfsroot/kern/2012-05-11/06/Makefile,内容如下:

View Code
复制代码
 1 obj-m    := test.o
 2 
 3 KERN    := /timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410
 4 
 5 all:
 6     make -C $(KERN) M=`pwd` modules
 7 
 8 clean:
 9     make -C $(KERN) M=`pwd` modules clean
10     rm -f modules.order
复制代码

在主机端编译模块,过程如下:

View Code
复制代码
 1 [root@localhost 06]# pwd
 2 /nfsroot/kern/2012-05-11/06
 3 [root@localhost 06]# ls
 4 Makefile  test.c
 5 [root@localhost 06]# make
 6 make -C /timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410 M=`pwd` modules
 7 make[1]: Entering directory `/timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410'
 8   CC [M]  /nfsroot/kern/2012-05-11/06/test.o
 9   Building modules, stage 2.
10   MODPOST 1 modules
11   CC      /nfsroot/kern/2012-05-11/06/test.mod.o
12   LD [M]  /nfsroot/kern/2012-05-11/06/test.ko
13 make[1]: Leaving directory `/timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410'
14 [root@localhost 06]# ls
15 Makefile       Module.symvers  test.ko     test.mod.o
16 modules.order  test.c          test.mod.c  test.o
17 [root@localhost 06]# modinfo test.ko 
18 filename:       test.ko
19 license:        GPL
20 depends:        
21 vermagic:       2.6.28.6 mod_unload ARMv6 
22 [root@localhost 06]#
复制代码

在开发板端载入模块、查看输出、卸载模块,过程如下:

View Code
复制代码
 1 [root@timkyle 06]# pwd
 2 /kern/2012-05-11/06
 3 [root@timkyle 06]# ls
 4 Makefile        modules.order   test.ko         test.mod.o
 5 Module.symvers  test.c          test.mod.c      test.o
 6 [root@timkyle 06]# modinfo test.ko 
 7 filename:       test.ko
 8 license:        GPL
 9 vermagic:       2.6.28.6 mod_unload ARMv6 
10 [root@timkyle 06]# lsmod 
11 [root@timkyle 06]# insmod test.ko 
12 start to wait 10 secs
13 end to wait 10 secs
14 [root@timkyle 06]# lsmod 
15 test 1400 0 - Live 0xbf060000
16 [root@timkyle 06]# rmmod test
17 [root@timkyle 06]# lsmod 
18 [root@timkyle 06]#
复制代码

 

程序七:使用内核定时器延时,并执行相应任务。

创建文件夹/nfsroot/kern/2012-05-11/07/。

创建文件/nfsroot/kern/2012-05-11/07/test.c,内容如下:

View Code
复制代码
 1 #include <linux/module.h>
 2 #include <linux/init.h>
 3 #include <linux/timer.h>
 4 #include <linux/jiffies.h>
 5 #include <linux/param.h>
 6 
 7 MODULE_LICENSE("GPL");
 8 
 9 static struct timer_list mytimer;
10 static unsigned long count = 1; 
11 
12 static void my_func(unsigned long data)
13 {
14     printk("\nafter 10 secs, data = %ld\n", data);
15 
16     printk("set timer of 10 secs again.\n");
17     mytimer.data = count++;
18     mod_timer(&mytimer, jiffies + 10 * HZ);
19     printk("after mod_timer()\n");
20 }
21 
22 static int __init test_init(void)
23 {
24     init_timer(&mytimer);
25     mytimer.expires = jiffies + 10 * HZ;
26     mytimer.data = count++;
27     mytimer.function = my_func;
28 
29     printk("set timer of 10 secs.\n");
30     add_timer(&mytimer);
31     printk("after add_timer()\n");
32 
33     return 0;
34 }
35 
36 static void __exit test_exit(void)
37 {
38     printk("del the timer\n");
39     del_timer(&mytimer);
40     printk("after del_timer()\n");
41 }
42 
43 module_init(test_init);
44 module_exit(test_exit);
复制代码

创建文件/nfsroot/kern/2012-05-11/07/Makefile,内容如下:

View Code
复制代码
 1 obj-m    := test.o
 2 
 3 KERN    := /timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410
 4 
 5 all:
 6     make -C $(KERN) M=`pwd` modules
 7 
 8 clean:
 9     make -C $(KERN) M=`pwd` modules clean
10     rm -f modules.order
复制代码

在主机端编译模块,过程如下:

View Code
复制代码
 1 [root@localhost 07]# pwd
 2 /nfsroot/kern/2012-05-11/07
 3 [root@localhost 07]# ls
 4 Makefile  test.c
 5 [root@localhost 07]# make
 6 make -C /timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410 M=`pwd` modules
 7 make[1]: Entering directory `/timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410'
 8   CC [M]  /nfsroot/kern/2012-05-11/07/test.o
 9   Building modules, stage 2.
10   MODPOST 1 modules
11   CC      /nfsroot/kern/2012-05-11/07/test.mod.o
12   LD [M]  /nfsroot/kern/2012-05-11/07/test.ko
13 make[1]: Leaving directory `/timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410'
14 [root@localhost 07]# ls
15 Makefile       Module.symvers  test.ko     test.mod.o
16 modules.order  test.c          test.mod.c  test.o
17 [root@localhost 07]# modinfo test.ko 
18 filename:       test.ko
19 license:        GPL
20 depends:        
21 vermagic:       2.6.28.6 mod_unload ARMv6 
22 [root@localhost 07]#
复制代码

在开发板端载入模块、查看输出、卸载模块,过程如下:

View Code
复制代码
 1 [root@timkyle 05]# pwd
 2 /kern/2012-05-11/05
 3 [root@timkyle 05]# ls
 4 [root@timkyle 07]# pwd
 5 /kern/2012-05-11/07
 6 [root@timkyle 07]# ls
 7 Makefile        modules.order   test.ko         test.mod.o
 8 Module.symvers  test.c          test.mod.c      test.o
 9 [root@timkyle 07]# modinfo test.ko 
10 filename:       test.ko
11 license:        GPL
12 vermagic:       2.6.28.6 mod_unload ARMv6 
13 [root@timkyle 07]# lsmod 
14 [root@timkyle 07]# insmod test.ko 
15 set timer of 10 secs.
16 after add_timer()
17 [root@timkyle 07]# lsmod 
18 test 1720 0 - Live 0xbf078000
19 [root@timkyle 07]# 
20 after 10 secs, data = 1
21 set timer of 10 secs again.
22 after mod_timer()
23 
24 after 10 secs, data = 2
25 set timer of 10 secs again.
26 after mod_timer()
27 
28 after 10 secs, data = 3
29 set timer of 10 secs again.
30 after mod_timer()
31 
32 after 10 secs, data = 4
33 set timer of 10 secs again.
34 after mod_timer()
35 
36 [root@timkyle 07]# rmmod test
37 del the timer
38 after del_timer()
39 [root@timkyle 07]# lsmod 
40 [root@timkyle 07]# 
复制代码

 

程序八:使用等待队列实现休眠(不确定延时)。

创建文件夹/nfsroot/kern/2012-05-11/08/。

创建文件/nfsroot/kern/2012-05-11/08/test.c,内容如下:

View Code
复制代码
 1 #include <linux/module.h>
 2 #include <linux/init.h>
 3 #include <linux/timer.h>
 4 #include <linux/jiffies.h>
 5 #include <linux/param.h>
 6 #include <linux/wait.h>
 7 #include <linux/sched.h>
 8 
 9 MODULE_LICENSE("GPL");
10 
11 #define INT 1
12 
13 static struct timer_list mytimer;
14 static wait_queue_head_t mywait;
15 static unsigned long count = 1;
16 
17 static void my_func(unsigned long data)
18 {
19     printk("\nafter 10 secs, data = %ld, count = %ld\n", data, count);
20 
21 #if INT
22     printk("start wake_up_interruptible()\n");
23     wake_up_interruptible(&mywait);
24     printk("after wake_up_interruptible()\n");
25 #else
26     printk("start wake_up()\n");
27     wake_up(&mywait);
28     printk("after wake_up()\n");
29 #endif
30 
31     printk("set timer of 10 secs again.\n");
32     mytimer.data = count++;
33     mod_timer(&mytimer, jiffies + 10 * HZ);
34     printk("after mod_timer()\n");
35 }
36 
37 static int __init test_init(void)
38 {
39     init_timer(&mytimer);
40     mytimer.expires = jiffies + 10 * HZ;
41     mytimer.data = count++;
42     mytimer.function = my_func;
43 
44     init_waitqueue_head(&mywait);
45 
46     printk("set timer of 10 secs.\n");
47     add_timer(&mytimer);
48     printk("after add_timer()\n");
49 
50 #if INT
51     printk("start wait_event_interruptible()\n");
52     wait_event_interruptible(mywait, count == 4);
53     printk("after wait_event_interruptible()\n");
54 #else
55     printk("start wait_event()\n");
56     wait_event(mywait, count == 4);
57     printk("after wait_event()\n");
58 #endif
59 
60     printk("\ndel the timer\n");
61     del_timer(&mytimer);
62     printk("after del_timer()\n");
63 
64     return 0;
65 }
66 
67 static void __exit test_exit(void)
68 {
69 }
70 
71 module_init(test_init);
72 module_exit(test_exit);
复制代码

创建文件/nfsroot/kern/2012-05-11/08/Makefile,内容如下:

View Code
复制代码
 1 obj-m    := test.o
 2 
 3 KERN    := /timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410
 4 
 5 all:
 6     make -C $(KERN) M=`pwd` modules
 7 
 8 clean:
 9     make -C $(KERN) M=`pwd` modules clean
10     rm -f modules.order
复制代码

在主机端编译模块,过程如下:

View Code
复制代码
 1 [root@localhost 08]# pwd
 2 /nfsroot/kern/2012-05-11/08
 3 [root@localhost 08]# ls
 4 Makefile  test.c
 5 [root@localhost 08]# make
 6 make -C /timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410 M=`pwd` modules
 7 make[1]: Entering directory `/timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410'
 8   CC [M]  /nfsroot/kern/2012-05-11/08/test.o
 9   Building modules, stage 2.
10   MODPOST 1 modules
11   CC      /nfsroot/kern/2012-05-11/08/test.mod.o
12   LD [M]  /nfsroot/kern/2012-05-11/08/test.ko
13 make[1]: Leaving directory `/timkyle-dev/my/arm/newnfs/home/linux-2.6.28_smdk6410'
14 [root@localhost 08]# ls
15 Makefile       Module.symvers  test.ko     test.mod.o
16 modules.order  test.c          test.mod.c  test.o
17 [root@localhost 08]# modinfo test.ko 
18 filename:       test.ko
19 license:        GPL
20 depends:        
21 vermagic:       2.6.28.6 mod_unload ARMv6 
22 [root@localhost 08]#
复制代码

在开发板端载入模块、查看输出、卸载模块,过程如下:

View Code
复制代码
 1 [root@timkyle 08]# pwd
 2 /kern/2012-05-11/08
 3 [root@timkyle 08]# ls
 4 Makefile        modules.order   test.ko         test.mod.o
 5 Module.symvers  test.c          test.mod.c      test.o
 6 [root@timkyle 08]# modinfo test.ko 
 7 filename:       test.ko
 8 license:        GPL
 9 vermagic:       2.6.28.6 mod_unload ARMv6 
10 [root@timkyle 08]# lsmod 
11 [root@timkyle 08]# insmod test.ko 
12 set timer of 10 secs.
13 after add_timer()
14 start wait_event_interruptible()
15 
16 after 10 secs, data = 1, count = 2
17 start wake_up_interruptible()
18 after wake_up_interruptible()
19 set timer of 10 secs again.
20 after mod_timer()
21 
22 after 10 secs, data = 2, count = 3
23 start wake_up_interruptible()
24 after wake_up_interruptible()
25 set timer of 10 secs again.
26 after mod_timer()
27 after wait_event_interruptible()
28 
29 del the timer
30 after del_timer()
31 [root@timkyle 08]# lsmod 
32 test 2128 0 - Live 0xbf090000
33 [root@timkyle 08]# rmmod test
34 [root@timkyle 08]# lsmod 
35 [root@timkyle 08]#
复制代码

由程序及测试结果可知,被唤醒的等待队列在检查条件是否满足时,有一定的延时效应。

<本文来至于:http://www.cnblogs.com/timkyle/archive/2012/05/12/2496752.html>


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值