【Linux设备驱动程序(第三版)】----tasklet

 【Linux设备驱动程序(第三版)】----tasklet

jit.c

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/proc_fs.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <asm/hardirq.h>
#include <linux/sched.h>//jiffies
#include <linux/kernel.h>
#include <linux/types.h>//u64
#include <linux/fs.h>//file_operations, file
#include <linux/completion.h>
#include <asm/uaccess.h>//copy_to_user & copy_from_user

int delay = HZ;

enum jit_files {
	JIT_BUSY,
	JIT_SCHED,
	JIT_QUEUE,
	JIT_SCHEDTO
};

int tdelay = 10;

struct jit_data {
	struct timer_list timer;
	struct tasklet_struct tlet;
	int hi;
	wait_queue_head_t wait;
	unsigned long prevjiffies;
	unsigned char *buf;
	int loops;
};

int jit_fn(char *buf, char **start, off_t offset, int len, int *eof, void *data)
{
	unsigned long j0, j1;
	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;
	len = sprintf(buf, "%9li %9li\n", j0, j1);
	*start = buf;
	return len;
}

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;

	j1 = jiffies;
	j2 = get_jiffies_64();
	do_gettimeofday(&tv1);
	tv2 = current_kernel_time();
	
	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;
}

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

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

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

	data->prevjiffies = j;
	data->buf = buf2;
	data->loops = JIT_ASYNC_LOOPS;

	data->timer.data = (unsigned long)data;
	data->timer.function = jit_timer_fn;
	data->timer.expires = j + tdelay;
	add_timer(&data->timer);

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

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

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

	data->prevjiffies = j;
	data->buf = buf2;
	data->loops = JIT_ASYNC_LOOPS;

	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_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("jit_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("jittimer", 0, NULL, jit_timer, NULL);
	create_proc_read_entry("jittasklet", 0, NULL, jit_tasklet, NULL);
	create_proc_read_entry("jittasklethi", 0, NULL, jit_tasklet, (void *)1);
	return 0;
}

void __exit jit_exit(void)
{
	remove_proc_entry("jit_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("jittimer", NULL);
	remove_proc_entry("jittasklet", NULL);
	remove_proc_entry("jittasklethi", NULL);
}

MODULE_LICENSE("Dual BSD/GPL");
module_init(jit_init);
module_exit(jit_exit);


Makefile

obj-m:= jit.o
modules-objs:= jit.o

KDIR:= /usr/src/linux-headers-2.6.31-14-generic/
PWD:= $(shell pwd)

default:
	make -C $(KDIR) M=$(PWD) modules
clean:
	rm -rf *.ko *.mod.c *.mod.o *.o *.markers *.symvers *.order


装载

insmod jit.ko


测试

cat /proc/jittasklet
cat /proc/jittasklethi


卸载

rmmod jit



 

你可能感兴趣的:(【Linux设备驱动程序(第三版)】----tasklet)