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

/*    * jit.c -- the just-in-time module    *    * Copyright (C) 2001,2003 Alessandro Rubini and Jonathan Corbet    * Copyright (C) 2001,2003 O'Reilly & Associates    *    * The source code in this file can be freely used, adapted,    * and redistributed in source or binary form, so long as an    * acknowledgment appears in derived source files.  The citation    * should list that the code comes from the book "Linux Device    * Drivers" by Alessandro Rubini and Jonathan Corbet, published    * by O'Reilly & Associates.   No warranty is attached;    * we cannot take responsibility for errors or fitness for use.    *    * $Id: jit.c,v 1.16 2004/09/26 07:02:43 gregkh Exp $    */         #include <linux/module.h>   #include <linux/moduleparam.h>   #include <linux/init.h>      #include <linux/time.h>   #include <linux/timer.h>   #include <linux/kernel.h>   #include <linux/proc_fs.h>   #include <linux/types.h>   #include <linux/spinlock.h>   #include <linux/interrupt.h>      #include <linux/param.h>   #include <linux/wait.h>   #include <linux/jiffies.h>   #include <linux/sched.h>      #include <asm/hardirq.h>   /*    * This module is a silly one: it only embeds short code fragments    * that show how time delays can be handled in the kernel.    */      int delay = HZ; /* the default delay, expressed in jiffies */      module_param(delay, int, 0);      MODULE_AUTHOR("Alessandro Rubini");   MODULE_LICENSE("Dual BSD/GPL");      /* use these as data pointers, to implement four files in one function */   enum jit_files {       JIT_BUSY,       JIT_SCHED,       JIT_QUEUE,       JIT_SCHEDTO   };      /*    * This function prints one line of data, after sleeping one second.    * It can sleep in different ways, according to the data pointer    */   int jit_fn(char *buf, char **start, off_t offset,             int len, int *eof, void *data)   {       unsigned long j0, j1; /* jiffies */       wait_queue_head_t wait;          init_waitqueue_head (&wait);       j0 = jiffies;       j1 = j0 + delay;          switch((long)data) {           case JIT_BUSY:               while (time_before(jiffies, j1))                   cpu_relax();               break;           case JIT_SCHED:               while (time_before(jiffies, j1)) {                   schedule();               }               break;           case JIT_QUEUE:               wait_event_interruptible_timeout(wait, 0, delay);                break;           case JIT_SCHEDTO:               set_current_state(TASK_INTERRUPTIBLE);               schedule_timeout (delay);               break;       }       j1 = jiffies; /* actual value after we delayed */          len = sprintf(buf, "%9li %9li\n", j0, j1);       *start = buf;       return len;   }      /*    * This file, on the other hand, returns the current time forever    */   int jit_currentime(char *buf, char **start, off_t offset,                      int len, int *eof, void *data)   {       struct timeval tv1;       struct timespec tv2;       unsigned long j1;       u64 j2;          /* get them four */       j1 = jiffies;       j2 = get_jiffies_64();       do_gettimeofday(&tv1);       tv2 = current_kernel_time();          /* print */       len=0;       len += sprintf(buf,"0x%08lx 0x%016Lx %10i.%06i\n"                  "%40i.%09i\n",                  j1, j2,                  (int) tv1.tv_sec, (int) tv1.tv_usec,                  (int) tv2.tv_sec, (int) tv2.tv_nsec);       *start = buf;       return len;   }      /*    * The timer example follows    */      int tdelay = 10;   module_param(tdelay, int, 0);      /* This data structure used as "data" for the timer and tasklet functions */   struct jit_data {       struct timer_list timer;       struct tasklet_struct tlet;       int hi; /* tasklet or tasklet_hi */       wait_queue_head_t wait;       unsigned long prevjiffies;       unsigned char *buf;       int loops;   };   #define JIT_ASYNC_LOOPS 5      void jit_timer_fn(unsigned long arg)   {       struct jit_data *data = (struct jit_data *)arg;       unsigned long j = jiffies;       data->buf += sprintf(data->buf, "%9li  %3li     %i    %6i   %i   %s\n",                    j, j - data->prevjiffies, in_interrupt() ? 1 : 0,                    current->pid, smp_processor_id(), current->comm);          if (--data->loops) {           data->timer.expires += tdelay;           data->prevjiffies = j;           add_timer(&data->timer);       } else {           wake_up_interruptible(&data->wait);       }   }      /* the /proc function: allocate everything to allow concurrency */   int jit_timer(char *buf, char **start, off_t offset,             int len, int *eof, void *unused_data)   {       struct jit_data *data;       char *buf2 = buf;       unsigned long j = jiffies;          data = kmalloc(sizeof(*data), GFP_KERNEL);       if (!data)           return -ENOMEM;          init_timer(&data->timer);       init_waitqueue_head (&data->wait);          /* write the first lines in the buffer */       buf2 += sprintf(buf2, "   time   delta  inirq    pid   cpu command\n");       buf2 += sprintf(buf2, "%9li  %3li     %i    %6i   %i   %s\n",               j, 0L, in_interrupt() ? 1 : 0,               current->pid, smp_processor_id(), current->comm);          /* fill the data for our timer function */       data->prevjiffies = j;       data->buf = buf2;       data->loops = JIT_ASYNC_LOOPS;              /* register the timer */       data->timer.data = (unsigned long)data;       data->timer.function = jit_timer_fn;       data->timer.expires = j + tdelay; /* parameter */       add_timer(&data->timer);          /* wait for the buffer to fill */       wait_event_interruptible(data->wait, !data->loops);       if (signal_pending(current))           return -ERESTARTSYS;       buf2 = data->buf;       kfree(data);       *eof = 1;       return buf2 - buf;   }      void jit_tasklet_fn(unsigned long arg)   {       struct jit_data *data = (struct jit_data *)arg;       unsigned long j = jiffies;       data->buf += sprintf(data->buf, "%9li  %3li     %i    %6i   %i   %s\n",                    j, j - data->prevjiffies, in_interrupt() ? 1 : 0,                    current->pid, smp_processor_id(), current->comm);          if (--data->loops) {           data->prevjiffies = j;           if (data->hi)               tasklet_hi_schedule(&data->tlet);           else               tasklet_schedule(&data->tlet);       } else {           wake_up_interruptible(&data->wait);       }   }      /* the /proc function: allocate everything to allow concurrency */   int jit_tasklet(char *buf, char **start, off_t offset,             int len, int *eof, void *arg)   {       struct jit_data *data;       char *buf2 = buf;       unsigned long j = jiffies;       long hi = (long)arg;          data = kmalloc(sizeof(*data), GFP_KERNEL);       if (!data)           return -ENOMEM;          init_waitqueue_head (&data->wait);          /* write the first lines in the buffer */       buf2 += sprintf(buf2, "   time   delta  inirq    pid   cpu command\n");       buf2 += sprintf(buf2, "%9li  %3li     %i    %6i   %i   %s\n",               j, 0L, in_interrupt() ? 1 : 0,               current->pid, smp_processor_id(), current->comm);          /* fill the data for our tasklet function */       data->prevjiffies = j;       data->buf = buf2;       data->loops = JIT_ASYNC_LOOPS;              /* register the tasklet */       tasklet_init(&data->tlet, jit_tasklet_fn, (unsigned long)data);       data->hi = hi;       if (hi)           tasklet_hi_schedule(&data->tlet);       else           tasklet_schedule(&data->tlet);          /* wait for the buffer to fill */       wait_event_interruptible(data->wait, !data->loops);          if (signal_pending(current))           return -ERESTARTSYS;       buf2 = data->buf;       kfree(data);       *eof = 1;       return buf2 - buf;   }            int __init jit_init(void)   {       create_proc_read_entry("currentime", 0, NULL, jit_currentime, NULL);       create_proc_read_entry("jitbusy", 0, NULL, jit_fn, (void *)JIT_BUSY);       create_proc_read_entry("jitsched",0, NULL, jit_fn, (void *)JIT_SCHED);       create_proc_read_entry("jitqueue",0, NULL, jit_fn, (void *)JIT_QUEUE);       create_proc_read_entry("jitschedto", 0, NULL, jit_fn, (void *)JIT_SCHEDTO);          create_proc_read_entry("jitimer", 0, NULL, jit_timer, NULL);       create_proc_read_entry("jitasklet", 0, NULL, jit_tasklet, NULL);       create_proc_read_entry("jitasklethi", 0, NULL, jit_tasklet, (void *)1);          return 0; /* success */   }      void __exit jit_cleanup(void)   {       remove_proc_entry("currentime", NULL);       remove_proc_entry("jitbusy", NULL);       remove_proc_entry("jitsched", NULL);       remove_proc_entry("jitqueue", NULL);       remove_proc_entry("jitschedto", NULL);          remove_proc_entry("jitimer", NULL);       remove_proc_entry("jitasklet", NULL);       remove_proc_entry("jitasklethi", NULL);   }      module_init(jit_init);   module_exit(jit_cleanup);  

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/ppjdz.html