jiq.c

来源:互联网 发布:91申请网站域名 编辑:程序博客网 时间:2024/05/05 00:55
/* * jiq.c -- the just-in-queue module * * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet * Copyright (C) 2001 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: jiq.c,v 1.7 2004/09/26 07:02:43 gregkh Exp $ */ //#include <linux/config.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/fs.h>     /* everything... */#include <linux/proc_fs.h>#include <linux/errno.h>  /* error codes */#include <linux/workqueue.h>#include <linux/preempt.h>#include <linux/interrupt.h> /* tasklets */MODULE_LICENSE("Dual BSD/GPL");/* * The delay for the delayed workqueue timer file. */static long delay = 1;module_param(delay, long, 0);static struct delayed_work_struct_ldd3_t {    struct delayed_work delayed_work;     void *privatedata;} delayed_work_struct_ldd3;/* * This module is a silly one: it only embeds short code fragments * that show how enqueued tasks `feel' the environment */#define LIMIT(PAGE_SIZE-128)/* don't print any more after this size *//* * Print information about the current environment. This is called from * within the task queues. If the limit is reched, awake the reading * process. */static DECLARE_WAIT_QUEUE_HEAD (jiq_wait);static struct work_struct jiq_work;/* * Keep track of info we need between task queue runs. */static struct clientdata {int len;char *buf;unsigned long jiffies;long delay;} jiq_data;//#define SCHEDULER_QUEUE ((task_queue *) 1)static void jiq_print_tasklet(unsigned long);static DECLARE_TASKLET(jiq_tasklet, jiq_print_tasklet, (unsigned long)&jiq_data);/* * Do the printing; return non-zero if the task should be rescheduled. */static int jiq_print(void *ptr){struct clientdata *data = ptr;int len = data->len;char *buf = data->buf;unsigned long j = jiffies;if (len > LIMIT) { wake_up_interruptible(&jiq_wait);return 0;}if (len == 0)len = sprintf(buf,"    time  delta preempt   pid cpu command\n");elselen =0;  /* intr_count is only exported since 1.3.5, but 1.99.4 is needed anyways */len += sprintf(buf+len, "%9li  %4li     %3i %5i %3i %s\n",j, j - data->jiffies,preempt_count(), current->pid, smp_processor_id(),current->comm);data->len += len;data->buf += len;data->jiffies = j;return 1;}/* * Call jiq_print from a work queue *///static void jiq_print_wq(void *ptr)static void jiq_print_wq(struct work_struct *ptr){#if 0struct clientdata *data = (struct clientdata *) ptr;    if (! jiq_print (ptr))return;    if (data->delay)schedule_delayed_work(&jiq_work, data->delay);elseschedule_work(&jiq_work);#endifstruct delayed_work *p_delayed_work = to_delayed_work(ptr);struct delayed_work_struct_ldd3_t *p_delayed_work_struct_ldd3 =container_of(p_delayed_work,  struct delayed_work_struct_ldd3_t, delayed_work);struct clientdata *data = (struct clientdata *) (p_delayed_work_struct_ldd3->privatedata);if (! jiq_print (data))          return;if (data->delay)     schedule_delayed_work(p_delayed_work,  data->delay);    else schedule_work(ptr);}static int jiq_read_wq(char *buf, char **start, off_t offset,                   int len, int *eof, void *data){DEFINE_WAIT(wait);jiq_data.len = 0;                /* nothing printed, yet */jiq_data.buf = buf;              /* print in this place */jiq_data.jiffies = jiffies;      /* initial time */jiq_data.delay = 0;    prepare_to_wait(&jiq_wait, &wait, TASK_INTERRUPTIBLE);//schedule_work(&jiq_work);schedule_work(&(delayed_work_struct_ldd3.delayed_work.work));schedule();finish_wait(&jiq_wait, &wait);*eof = 1;return jiq_data.len;}static int jiq_read_wq_delayed(char *buf, char **start, off_t offset,                   int len, int *eof, void *data){DEFINE_WAIT(wait);jiq_data.len = 0;                /* nothing printed, yet */jiq_data.buf = buf;              /* print in this place */jiq_data.jiffies = jiffies;      /* initial time */jiq_data.delay = delay;    prepare_to_wait(&jiq_wait, &wait, TASK_INTERRUPTIBLE);//schedule_delayed_work(&jiq_work, delay);schedule_delayed_work(&(delayed_work_struct_ldd3.delayed_work), delay);schedule();finish_wait(&jiq_wait, &wait);*eof = 1;return jiq_data.len;}/* * Call jiq_print from a tasklet */static void jiq_print_tasklet(unsigned long ptr){if (jiq_print ((void *) ptr))tasklet_schedule (&jiq_tasklet);}static int jiq_read_tasklet(char *buf, char **start, off_t offset, int len,                int *eof, void *data){jiq_data.len = 0;                /* nothing printed, yet */jiq_data.buf = buf;              /* print in this place */jiq_data.jiffies = jiffies;      /* initial time */tasklet_schedule(&jiq_tasklet);interruptible_sleep_on(&jiq_wait);    /* sleep till completion */*eof = 1;return jiq_data.len;}/* * This one, instead, tests out the timers. */static struct timer_list jiq_timer;static void jiq_timedout(unsigned long ptr){jiq_print((void *)ptr);            /* print a line */wake_up_interruptible(&jiq_wait);  /* awake the process */}static int jiq_read_run_timer(char *buf, char **start, off_t offset,                   int len, int *eof, void *data){jiq_data.len = 0;           /* prepare the argument for jiq_print() */jiq_data.buf = buf;jiq_data.jiffies = jiffies;init_timer(&jiq_timer);              /* init the timer structure */jiq_timer.function = jiq_timedout;jiq_timer.data = (unsigned long)&jiq_data;jiq_timer.expires = jiffies + HZ; /* one second */jiq_print(&jiq_data);   /* print and go to sleep */add_timer(&jiq_timer);interruptible_sleep_on(&jiq_wait);  /* RACE */del_timer_sync(&jiq_timer);  /* in case a signal woke us up */    *eof = 1;return jiq_data.len;}/* * the init/clean material */static int jiq_init(void){delayed_work_struct_ldd3.privatedata = (void*)&jiq_data;/* this line is in jiq_init() *///INIT_WORK(&jiq_work, jiq_print_wq, &jiq_data);INIT_DELAYED_WORK(&(delayed_work_struct_ldd3.delayed_work), jiq_print_wq);create_proc_read_entry("jiqwq", 0, NULL, jiq_read_wq, NULL);create_proc_read_entry("jiqwqdelay", 0, NULL, jiq_read_wq_delayed, NULL);create_proc_read_entry("jitimer", 0, NULL, jiq_read_run_timer, NULL);create_proc_read_entry("jiqtasklet", 0, NULL, jiq_read_tasklet, NULL);return 0; /* succeed */}static void jiq_cleanup(void){remove_proc_entry("jiqwq", NULL);remove_proc_entry("jiqwqdelay", NULL);remove_proc_entry("jitimer", NULL);remove_proc_entry("jiqtasklet", NULL);}module_init(jiq_init);module_exit(jiq_cleanup);


原创粉丝点击