Linux设备驱动之时间,延迟及延缓操作(实践)


一 jit.函数源码

  1. /*  
  2.  * jit.c -- the just-in-time module  
  3.  *  
  4.  * Copyright (C) 2001,2003 Alessandro Rubini and Jonathan Corbet  
  5.  * Copyright (C) 2001,2003 O'Reilly & Associates  
  6.  *  
  7.  * The source code in this file can be freely used, adapted,  
  8.  * and redistributed in source or binary form, so long as an  
  9.  * acknowledgment appears in derived source files.  The citation  
  10.  * should list that the code comes from the book "Linux Device  
  11.  * Drivers" by Alessandro Rubini and Jonathan Corbet, published  
  12.  * by O'Reilly & Associates.   No warranty is attached;  
  13.  * we cannot take responsibility for errors or fitness for use.  
  14.  *  
  15.  * $Id: jit.c,v 1.16 2004/09/26 07:02:43 gregkh Exp $  
  16.  */  
  17.   
  18.   
  19. #include <linux/module.h>  
  20. #include <linux/moduleparam.h>  
  21. #include <linux/init.h>  
  22.   
  23. #include <linux/time.h>  
  24. #include <linux/timer.h>  
  25. #include <linux/kernel.h>  
  26. #include <linux/proc_fs.h>  
  27. #include <linux/types.h>  
  28. #include <linux/spinlock.h>  
  29. #include <linux/interrupt.h>  
  30.   
  31. #include <linux/param.h>  
  32. #include <linux/wait.h>  
  33. #include <linux/jiffies.h>  
  34. #include <linux/sched.h>  
  35.   
  36. #include <asm/hardirq.h>  
  37. /*  
  38.  * This module is a silly one: it only embeds short code fragments  
  39.  * that show how time delays can be handled in the kernel.  
  40.  */  
  41.   
  42. int delay = HZ; /* the default delay, expressed in jiffies */  
  43.   
  44. module_param(delay, int, 0);  
  45.   
  46. MODULE_AUTHOR("Alessandro Rubini");  
  47. MODULE_LICENSE("Dual BSD/GPL");  
  48.   
  49. /* use these as data pointers, to implement four files in one function */  
  50. enum jit_files {  
  51.     JIT_BUSY,  
  52.     JIT_SCHED,  
  53.     JIT_QUEUE,  
  54.     JIT_SCHEDTO  
  55. };  
  56.   
  57. /*  
  58.  * This function prints one line of data, after sleeping one second.  
  59.  * It can sleep in different ways, according to the data pointer  
  60.  */  
  61. int jit_fn(char *buf, char **start, off_t offset,  
  62.           int len, int *eof, void *data)  
  63. {  
  64.     unsigned long j0, j1; /* jiffies */  
  65.     wait_queue_head_t wait;  
  66.   
  67.     init_waitqueue_head (&wait);  
  68.     j0 = jiffies;  
  69.     j1 = j0 + delay;  
  70.   
  71.     switch((long)data) {  
  72.         case JIT_BUSY:  
  73.             while (time_before(jiffies, j1))  
  74.                 cpu_relax();  
  75.             break;  
  76.         case JIT_SCHED:  
  77.             while (time_before(jiffies, j1)) {  
  78.                 schedule();  
  79.             }  
  80.             break;  
  81.         case JIT_QUEUE:  
  82.             wait_event_interruptible_timeout(wait, 0, delay);   
  83.             break;  
  84.         case JIT_SCHEDTO:  
  85.             set_current_state(TASK_INTERRUPTIBLE);  
  86.             schedule_timeout (delay);  
  87.             break;  
  88.     }  
  89.     j1 = jiffies; /* actual value after we delayed */  
  90.   
  91.     len = sprintf(buf, "%9li %9li\n", j0, j1);  
  92.     *start = buf;  
  93.     return len;  
  94. }  
  95.   
  96. /*  
  97.  * This file, on the other hand, returns the current time forever  
  98.  */  
  99. int jit_currentime(char *buf, char **start, off_t offset,  
  100.                    int len, int *eof, void *data)  
  101. {  
  102.     struct timeval tv1;  
  103.     struct timespec tv2;  
  104.     unsigned long j1;  
  105.     u64 j2;  
  106.   
  107.     /* get them four */  
  108.     j1 = jiffies;  
  109.     j2 = get_jiffies_64();  
  110.     do_gettimeofday(&tv1);  
  111.     tv2 = current_kernel_time();  
  112.   
  113.     /* print */  
  114.     len=0;  
  115.     len += sprintf(buf,"0x%08lx 0x%016Lx %10i.%06i\n"  
  116.                "%40i.%09i\n",  
  117.                j1, j2,  
  118.                (int) tv1.tv_sec, (int) tv1.tv_usec,  
  119.                (int) tv2.tv_sec, (int) tv2.tv_nsec);  
  120.     *start = buf;  
  121.     return len;  
  122. }  
  123.   
  124. /*  
  125.  * The timer example follows  
  126.  */  
  127.   
  128. int tdelay = 10;  
  129. module_param(tdelay, int, 0);  
  130.   
  131. /* This data structure used as "data" for the timer and tasklet functions */  
  132. struct jit_data {  
  133.     struct timer_list timer;  
  134.     struct tasklet_struct tlet;  
  135.     int hi; /* tasklet or tasklet_hi */  
  136.     wait_queue_head_t wait;  
  137.     unsigned long prevjiffies;  
  138.     unsigned char *buf;  
  139.     int loops;  
  140. };  
  141. #define JIT_ASYNC_LOOPS 5  
  142.   
  143. void jit_timer_fn(unsigned long arg)  
  144. {  
  145.     struct jit_data *data = (struct jit_data *)arg;  
  146.     unsigned long j = jiffies;  
  147.     data->buf += sprintf(data->buf, "%9li  %3li     %i    %6i   %i   %s\n",  
  148.                  j, j - data->prevjiffies, in_interrupt() ? 1 : 0,  
  149.                  current->pid, smp_processor_id(), current->comm);  
  150.   
  151.     if (--data->loops) {  
  152.         data->timer.expires += tdelay;  
  153.         data->prevjiffies = j;  
  154.         add_timer(&data->timer);  
  155.     } else {  
  156.         wake_up_interruptible(&data->wait);  
  157.     }  
  158. }  
  159.   
  160. /* the /proc function: allocate everything to allow concurrency */  
  161. int jit_timer(char *buf, char **start, off_t offset,  
  162.           int len, int *eof, void *unused_data)  
  163. {  
  164.     struct jit_data *data;  
  165.     char *buf2 = buf;  
  166.     unsigned long j = jiffies;  
  167.   
  168.     data = kmalloc(sizeof(*data), GFP_KERNEL);  
  169.     if (!data)  
  170.         return -ENOMEM;  
  171.   
  172.     init_timer(&data->timer);  
  173.     init_waitqueue_head (&data->wait);  
  174.   
  175.     /* write the first lines in the buffer */  
  176.     buf2 += sprintf(buf2, "   time   delta  inirq    pid   cpu command\n");  
  177.     buf2 += sprintf(buf2, "%9li  %3li     %i    %6i   %i   %s\n",  
  178.             j, 0L, in_interrupt() ? 1 : 0,  
  179.             current->pid, smp_processor_id(), current->comm);  
  180.   
  181.     /* fill the data for our timer function */  
  182.     data->prevjiffies = j;  
  183.     data->buf = buf2;  
  184.     data->loops = JIT_ASYNC_LOOPS;  
  185.       
  186.     /* register the timer */  
  187.     data->timer.data = (unsigned long)data;  
  188.     data->timer.function = jit_timer_fn;  
  189.     data->timer.expires = j + tdelay; /* parameter */  
  190.     add_timer(&data->timer);  
  191.   
  192.     /* wait for the buffer to fill */  
  193.     wait_event_interruptible(data->wait, !data->loops);  
  194.     if (signal_pending(current))  
  195.         return -ERESTARTSYS;  
  196.     buf2 = data->buf;  
  197.     kfree(data);  
  198.     *eof = 1;  
  199.     return buf2 - buf;  
  200. }  
  201.   
  202. void jit_tasklet_fn(unsigned long arg)  
  203. {  
  204.     struct jit_data *data = (struct jit_data *)arg;  
  205.     unsigned long j = jiffies;  
  206.     data->buf += sprintf(data->buf, "%9li  %3li     %i    %6i   %i   %s\n",  
  207.                  j, j - data->prevjiffies, in_interrupt() ? 1 : 0,  
  208.                  current->pid, smp_processor_id(), current->comm);  
  209.   
  210.     if (--data->loops) {  
  211.         data->prevjiffies = j;  
  212.         if (data->hi)  
  213.             tasklet_hi_schedule(&data->tlet);  
  214.         else  
  215.             tasklet_schedule(&data->tlet);  
  216.     } else {  
  217.         wake_up_interruptible(&data->wait);  
  218.     }  
  219. }  
  220.   
  221. /* the /proc function: allocate everything to allow concurrency */  
  222. int jit_tasklet(char *buf, char **start, off_t offset,  
  223.           int len, int *eof, void *arg)  
  224. {  
  225.     struct jit_data *data;  
  226.     char *buf2 = buf;  
  227.     unsigned long j = jiffies;  
  228.     long hi = (long)arg;  
  229.   
  230.     data = kmalloc(sizeof(*data), GFP_KERNEL);  
  231.     if (!data)  
  232.         return -ENOMEM;  
  233.   
  234.     init_waitqueue_head (&data->wait);  
  235.   
  236.     /* write the first lines in the buffer */  
  237.     buf2 += sprintf(buf2, "   time   delta  inirq    pid   cpu command\n");  
  238.     buf2 += sprintf(buf2, "%9li  %3li     %i    %6i   %i   %s\n",  
  239.             j, 0L, in_interrupt() ? 1 : 0,  
  240.             current->pid, smp_processor_id(), current->comm);  
  241.   
  242.     /* fill the data for our tasklet function */  
  243.     data->prevjiffies = j;  
  244.     data->buf = buf2;  
  245.     data->loops = JIT_ASYNC_LOOPS;  
  246.       
  247.     /* register the tasklet */  
  248.     tasklet_init(&data->tlet, jit_tasklet_fn, (unsigned long)data);  
  249.     data->hi = hi;  
  250.     if (hi)  
  251.         tasklet_hi_schedule(&data->tlet);  
  252.     else  
  253.         tasklet_schedule(&data->tlet);  
  254.   
  255.     /* wait for the buffer to fill */  
  256.     wait_event_interruptible(data->wait, !data->loops);  
  257.   
  258.     if (signal_pending(current))  
  259.         return -ERESTARTSYS;  
  260.     buf2 = data->buf;  
  261.     kfree(data);  
  262.     *eof = 1;  
  263.     return buf2 - buf;  
  264. }  
  265.   
  266.   
  267.   
  268. int __init jit_init(void)  
  269. {  
  270.     create_proc_read_entry("currentime", 0, NULL, jit_currentime, NULL);  
  271.     create_proc_read_entry("jitbusy", 0, NULL, jit_fn, (void *)JIT_BUSY);  
  272.     create_proc_read_entry("jitsched",0, NULL, jit_fn, (void *)JIT_SCHED);  
  273.     create_proc_read_entry("jitqueue",0, NULL, jit_fn, (void *)JIT_QUEUE);  
  274.     create_proc_read_entry("jitschedto", 0, NULL, jit_fn, (void *)JIT_SCHEDTO);  
  275.   
  276.     create_proc_read_entry("jitimer", 0, NULL, jit_timer, NULL);  
  277.     create_proc_read_entry("jitasklet", 0, NULL, jit_tasklet, NULL);  
  278.     create_proc_read_entry("jitasklethi", 0, NULL, jit_tasklet, (void *)1);  
  279.   
  280.     return 0; /* success */  
  281. }  
  282.   
  283. void __exit jit_cleanup(void)  
  284. {  
  285.     remove_proc_entry("currentime", NULL);  
  286.     remove_proc_entry("jitbusy", NULL);  
  287.     remove_proc_entry("jitsched", NULL);  
  288.     remove_proc_entry("jitqueue", NULL);  
  289.     remove_proc_entry("jitschedto", NULL);  
  290.   
  291.     remove_proc_entry("jitimer", NULL);  
  292.     remove_proc_entry("jitasklet", NULL);  
  293.     remove_proc_entry("jitasklethi", NULL);  
  294. }  
  295.   
  296. module_init(jit_init);  
  297. module_exit(jit_cleanup);  
  • 1
  • 2
  • 下一页

相关内容