在新版的linux中,workqueue的api做了一定的修改。
下面是个简单的例子,是基于ldd3的 jiq.c代码。
其中网上另一个人给的一个用法是,将jiq_print_wq的输入参数作为一个全局的变量,而不是通过container_of来算出来的。
我觉得这样写代码比较清楚点。
//#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);
/*
* 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 */
#define LIMIT (PAGE_SIZE-3072) /* 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);
/*
* Keep track of info we need between task queue runs.
*/
static struct clientdata {
//static struct work_struct jiq_work;
struct delayed_work jiq_work;
int len;
char *buf;
unsigned long jiffies;
long delay;
} jiq_data;
#define SCHEDULER_QUEUE ((task_queue *) 1)
/*
* 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");
else
len =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(struct work_struct *work)
{
// struct clientdata *data = (struct clientdata *) ptr;
struct clientdata *data = container_of(work, struct clientdata, jiq_work.work) ;
if (! jiq_print (data))
return;
if (data->delay)
schedule_delayed_work(&data->jiq_work, data->delay);
else
schedule_work(&data->jiq_work.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;
prepare_to_wait(&jiq_wait, &wait, TASK_INTERRUPTIBLE);
schedule_work(&jiq_data.jiq_work.work);
schedule();
finish_wait(&jiq_wait, &wait);
*eof = 1;
return jiq_data.len;
}
/*
* the init/clean material
*/
static int workqueue_init(void)
{
/* this line is in jiq_init() */
INIT_DELAYED_WORK(&jiq_data.jiq_work, jiq_print_wq );
create_proc_read_entry("workqueue", 0, NULL, jiq_read_wq, NULL);
return 0; /* succeed */
}
static void workqueue_cleanup(void)
{
remove_proc_entry("workqueue", NULL);
}
module_init(workqueue_init);
module_exit(workqueue_cleanup);