【Linux 驱动】第七章 时间 延迟及延缓操作 (例子详解二)

本文所涉及实验为博文http://blog.csdn.net/tianshuai11/article/details/7465587中示例,请先阅读上述博文,然后消化以下例子

一,模块方法

        jiq.c

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

	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 *ptr)    /* warning: assignment from incompatible pointer type*/
{
	struct clientdata *data = &jiq_data;
	if (! jiq_print (data))
		return;
	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;
    
	prepare_to_wait(&jiq_wait, &wait, TASK_INTERRUPTIBLE);
	schedule_work(&jiq_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, 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)
{
	/* 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");

Makefile

KERNELDIR ?= /lib/modules/$(shell uname -r)/build  
PWD := $(shell pwd)
obj-m := jiq.o 
modules:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
.PHONY: modules modules_install clean
测试:

root@ubuntu:~/桌面/jiq#make

root@ubuntu:~/桌面/jiq# insmod jiq.ko
root@ubuntu:~/桌面/jiq# lsmod  //查看安装成功

root@ubuntu:~/桌面/jiq# cat /proc/jiqwq
    time  delta preempt   pid cpu command
  6292513     0       0   235   2 kworker/2:1
  6292513     0       0   235   2 kworker/2:1
  6292513     0       0   235   2 kworker/2:1
  6292513     0       0   235   2 kworker/2:1
  6292513     0       0   235   2 kworker/2:1
  6292513     0       0   235   2 kworker/2:1
  6292513     0       0   235   2 kworker/2:1
  6292513     0       0   235   2 kworker/2:1
  6292513     0       0   235   2 kworker/2:1
  6292513     0       0   235   2 kworker/2:1
  6292513     0       0   235   2 kworker/2:1

root@ubuntu:~/桌面/jiq# cat /proc/jiqwqdelay
    time  delta preempt   pid cpu command
  6297985     1       0   235   2 kworker/2:1
  6297986     1       0   235   2 kworker/2:1
  6297987     1       0   235   2 kworker/2:1
  6297988     1       0   235   2 kworker/2:1
  6297989     1       0   235   2 kworker/2:1
  6297990     1       0   235   2 kworker/2:1
  6297991     1       0   235   2 kworker/2:1
  6297992     1       0   235   2 kworker/2:1
  6297993     1       0   235   2 kworker/2:1
  6297994     1       0   235   2 kworker/2:1
  6297995     1       0   235   2 kworker/2:1

root@ubuntu:~/桌面/jiq# cat /proc/jiqtimer
    time  delta preempt   pid cpu command
  6304215     0       0  5019   2 cat
  6304465   250     256     0   2 kworker/0:1

root@ubuntu:~/桌面/jiq# cat /proc/jiqtasklet
    time  delta preempt   pid cpu command
  6323656     0     256     3   0 ksoftirqd/0
  6323656     0     256     3   0 ksoftirqd/0
  6323656     0     256     3   0 ksoftirqd/0
  6323656     0     256     3   0 ksoftirqd/0
  6323656     0     256     3   0 ksoftirqd/0
  6323656     0     256     3   0 ksoftirqd/0
  6323656     0     256     3   0 ksoftirqd/0
  6323656     0     256     3   0 ksoftirqd/0
  6323656     0     256     3   0 ksoftirqd/0
  6323656     0     256     3   0 ksoftirqd/0
  6323656     0     256     3   0 ksoftirqd/0







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值