Linux设备驱动程序学习(10)-时间、延迟及延缓操作(Jiq.c)

来源:互联网 发布:淘宝自动评价 编辑:程序博客网 时间:2024/05/18 20:06
共享隊列

点击(此处)折叠或打开

  1. /*
  2.  * jiq.-- the just-in-queue module
  3.  *
  4.  * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
  5.  * Copyright (C) 2001 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: jiq.c,v 1.7 2004/09/26 07:02:43 gregkh Exp $
  16.  */
  17.  
  18. #include <linux/module.h>
  19. #include <linux/moduleparam.h>
  20. #include <linux/init.h>

  21. #include <linux/sched.h>
  22. #include <linux/kernel.h>
  23. #include <linux/fs.h> /* everything... */
  24. #include <linux/proc_fs.h>
  25. #include <linux/errno.h> /* error codes */
  26. #include <linux/workqueue.h>
  27. #include <linux/preempt.h>
  28. #include <linux/interrupt.h> /* tasklets */



  29. /*
  30.  * The delay for the delayed workqueue timer file.
  31.  */
  32. static long delay = 1;
  33. module_param(delay, long, 0);


  34. /*
  35.  * This module is a silly one: it only embeds short code fragments
  36.  * that show how enqueued tasks `feel' the environment
  37.  */

  38. #define LIMIT    (512)    /* don't print any more after this size */

  39. /*
  40.  * Print information about the current environment. This is called from
  41.  * within the task queues. If the limit is reched, awake the reading
  42.  * process.
  43.  */
  44. static DECLARE_WAIT_QUEUE_HEAD (jiq_wait);


  45. static struct work_struct jiq_work;
  46. static struct delayed_work jiq_work_delay;


  47. /*
  48.  * Keep track of info we need between task queue runs.
  49.  */
  50. static struct clientdata {
  51.     int len;
  52.     char *buf;
  53.     unsigned long jiffies;
  54.     unsigned long delay;
  55. } jiq_data;

  56. #define SCHEDULER_QUEUE ((task_queue *) 1)



  57. static void jiq_print_tasklet(unsigned long);
  58. static DECLARE_TASKLET(jiq_tasklet, jiq_print_tasklet, (unsigned long)&jiq_data);


  59. /*
  60.  * Do the printing; return non-zero if the task should be rescheduled.
  61.  */
  62. static int jiq_print(void *ptr)
  63. {
  64.     struct clientdata *data = ptr;
  65.     int len = data->len;
  66.     char *buf = data->buf;
  67.     unsigned long j = jiffies;

  68.     //error , full
  69.     if (len > LIMIT) 
  70.     { 
  71.         wake_up_interruptible(&jiq_wait);
  72.         return 0;
  73.     }

  74.     //the first time to show the message
  75.     if (len == 0)
  76.         len = sprintf(buf," time delta preempt pid cpu commandn");
  77.     else
  78.         len =0;    //init again

  79.       /* intr_count is only exported since 1.3.5, but 1.99.is needed anyways */
  80.     len += sprintf(buf, "%9li %4li %3i %5i %3i %sn",
  81.             j, j - data->jiffies,
  82.             preempt_count(), current->pid, smp_processor_id(),
  83.             current->comm);

  84.     data->len += len;
  85.     data->buf += len;
  86.     data->jiffies = j;
  87.     return 1;
  88. }


  89. /*
  90.  * Call jiq_print from a work queue
  91.  */
  92. static void jiq_print_wq(struct work_struct *ptr) /* warning: assignment from incompatible pointer type*/
  93. {
  94.     struct clientdata *data = &jiq_data;

  95.     if (! jiq_print (data))
  96.         return;

  97.     //to schedule again, so jiq_work <===> jiq_print_wq() will be call again
  98.     if (data->delay)
  99.         schedule_delayed_work( &jiq_work_delay, data->delay);
  100.     else
  101.         schedule_work(&jiq_work);
  102. }



  103. static int jiq_read_wq(char *buf, char **start, off_t offset,
  104.                    int len, int *eof, void *data)
  105. {
  106.     DEFINE_WAIT(wait);
  107.     
  108.     jiq_data.len = 0; /* nothing printed, yet */
  109.     jiq_data.buf = buf; /* print in this place */
  110.     jiq_data.jiffies = jiffies; /* initial time */
  111.     jiq_data.delay = 0;

  112.     //add jiq_wait into the waitquene
  113.     prepare_to_wait(&jiq_wait, &wait, TASK_INTERRUPTIBLE);
  114.     //use this method, jiq_work <===> jiq_print_wq() will be call(here is very important)
  115.     schedule_work(&jiq_work);
  116.     //here sleep and wait
  117.     schedule();
  118.     //cleanup the waitquene
  119.     finish_wait(&jiq_wait, &wait);

  120.     *eof = 1;
  121.     return jiq_data.len;
  122. }


  123. static int jiq_read_wq_delayed(char *buf, char **start, off_t offset,
  124.                    int len, int *eof, void *data)
  125. {
  126.     DEFINE_WAIT(wait);
  127.     
  128.     jiq_data.len = 0; /* nothing printed, yet */
  129.     jiq_data.buf = buf; /* print in this place */
  130.     jiq_data.jiffies = jiffies; /* initial time */
  131.     jiq_data.delay = delay;
  132.     
  133.     prepare_to_wait(&jiq_wait, &wait, TASK_INTERRUPTIBLE);
  134.     schedule_delayed_work(&jiq_work_delay, delay);
  135.     schedule();
  136.     finish_wait(&jiq_wait, &wait);

  137.     *eof = 1;
  138.     return jiq_data.len;
  139. }




  140. /*
  141.  * Call jiq_print from a tasklet
  142.  */
  143. static void jiq_print_tasklet(unsigned long ptr)
  144. {
  145.     if (!jiq_print ((void *) ptr))
  146.         return;

  147.     //to schedule it again
  148.     tasklet_schedule (&jiq_tasklet);
  149. }



  150. static int jiq_read_tasklet(char *buf, char **start, off_t offset, int len,
  151.                 int *eof, void *data)
  152. {
  153.     jiq_data.len = 0; /* nothing printed, yet */
  154.     jiq_data.buf = buf; /* print in this place */
  155.     jiq_data.jiffies = jiffies; /* initial time */

  156.     tasklet_schedule(&jiq_tasklet);
  157.     //here interruptible_sleep_on is not a good method
  158.     //try to use 手動休眠
  159.     interruptible_sleep_on(&jiq_wait); /* sleep utill completion */

  160.     *eof = 1;
  161.     return jiq_data.len;
  162. }




  163. /*
  164.  * This one, instead, tests out the timers.
  165.  */

  166. static struct timer_list jiq_timer;

  167. static void jiq_timedout(unsigned long ptr)
  168. {
  169.     struct clientdata *data = ptr;
  170.     //jiq_print((void *)ptr); /* print a line */
  171.     //wake_up_interruptible(&jiq_wait); /* awake the process */

  172.     if (! jiq_print (data))
  173.     {
  174.         wake_up_interruptible(&jiq_wait); /* awake the process */
  175.         return;
  176.     }
  177.     //update the timer
  178.     mod_timer(&jiq_timer, jiq_timer.expires+HZ);
  179. }


  180. static int jiq_read_run_timer(char *buf, char **start, off_t offset,
  181.                    int len, int *eof, void *data)
  182. {

  183.     jiq_data.len = 0; /* prepare the argument for jiq_print() */
  184.     jiq_data.buf = buf;
  185.     jiq_data.jiffies = jiffies;

  186.     init_timer(&jiq_timer); /* init the timer structure */
  187.     jiq_timer.function = jiq_timedout;
  188.     jiq_timer.data = (unsigned long)&jiq_data;
  189.     jiq_timer.expires = jiffies + HZ; /* one second */

  190.     jiq_print(&jiq_data); /* print and go to sleep */
  191.     add_timer(&jiq_timer);
  192.     interruptible_sleep_on(&jiq_wait); /* RACE */
  193.     del_timer_sync(&jiq_timer); /* in case a signal woke us up */
  194.     
  195.     *eof = 1;
  196.     return jiq_data.len;
  197. }



  198. /*
  199.  * the init/clean material
  200.  */

  201. static int jiq_init(void)
  202. {

  203.     /* this line is in jiq_init() */
  204.     INIT_WORK(&jiq_work, jiq_print_wq);
  205.     INIT_DELAYED_WORK(&jiq_work_delay, jiq_print_wq);
  206.     create_proc_read_entry("jiqwq", 0, NULL, jiq_read_wq, NULL);
  207.     create_proc_read_entry("jiqwqdelay", 0, NULL, jiq_read_wq_delayed, NULL);
  208.     create_proc_read_entry("jiqtimer", 0, NULL, jiq_read_run_timer, NULL);
  209.     create_proc_read_entry("jiqtasklet", 0, NULL, jiq_read_tasklet, NULL);

  210.     return 0; /* succeed */
  211. }

  212. static void jiq_cleanup(void)
  213. {
  214.     remove_proc_entry("jiqwq", NULL);
  215.     remove_proc_entry("jiqwqdelay", NULL);
  216.     remove_proc_entry("jiqtimer", NULL);
  217.     remove_proc_entry("jiqtasklet", NULL);
  218. }


  219. module_init(jiq_init);
  220. module_exit(jiq_cleanup);

  221. MODULE_LICENSE("Dual BSD/GPL");
0 0