您的位置:首页 > 运维架构 > Linux

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

2014-04-03 15:16 701 查看
共享隊列

点击(此处)折叠或打开

/*

* 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/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 */

/*

* The delay for the delayed workqueue timer file.

*/

static long delay = 1;

module_param(delay, long, 0);

/*

* This module is a silly one: it only embeds short code fragments

* that show how enqueued tasks `feel' the environment

*/

#define LIMIT (512) /* 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;

static struct delayed_work jiq_work_delay;

/*

* Keep track of info we need between task queue runs.

*/

static struct clientdata {

int len;

char *buf;

unsigned long jiffies;

unsigned 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;

//error , full

if (len > LIMIT)

{

wake_up_interruptible(&jiq_wait);

return 0;

}

//the first time to show
the message

if (len == 0)

len = sprintf(buf,"
time delta preempt pid cpu commandn");

else

len =0; //init
again

/* intr_count is only exported since 1.3.5, but
1.99.4 is needed anyways */

len += sprintf(buf, "%9li
%4li %3i %5i %3i %sn",

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(struct work_struct *ptr) /* warning: assignment
from incompatible pointer type*/

{

struct clientdata *data = &jiq_data;

if (! jiq_print (data))

return;

//to schedule again, so
jiq_work <===> jiq_print_wq() will
be call again

if (data->delay)

schedule_delayed_work( &jiq_work_delay, data->delay);

else

schedule_work(&jiq_work);

}

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;

//add jiq_wait into the waitquene

prepare_to_wait(&jiq_wait, &wait, TASK_INTERRUPTIBLE);

//use this method, jiq_work <===> jiq_print_wq() will
be call(here is very important)

schedule_work(&jiq_work);

//here sleep and wait

schedule();

//cleanup the waitquene

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, 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))

return;

//to schedule it again

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);

//here interruptible_sleep_on is not a
good method

//try to use 手動休眠

interruptible_sleep_on(&jiq_wait); /* sleep
utill 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)

{

struct clientdata *data = ptr;

//jiq_print((void *)ptr); /* print
a line */

//wake_up_interruptible(&jiq_wait); /* awake
the process */

if (! jiq_print (data))

{

wake_up_interruptible(&jiq_wait); /* awake
the process */

return;

}

//update the timer

mod_timer(&jiq_timer, jiq_timer.expires+HZ);

}

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)

{

/* this line is in jiq_init() */

INIT_WORK(&jiq_work, jiq_print_wq);

INIT_DELAYED_WORK(&jiq_work_delay, 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("jiqtimer", 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("jiqtimer", NULL);

remove_proc_entry("jiqtasklet", NULL);

}

module_init(jiq_init);

module_exit(jiq_cleanup);

MODULE_LICENSE("Dual BSD/GPL");
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: