本文所涉及实验为博文http://blog.youkuaiyun.com/tianshuai11/article/details/7465587中示例,请先阅读上述博文,然后消化以下例子
一,模块方法
jit.c
#include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> #include <linux/time.h> #include <linux/timer.h> #include <linux/kernel.h> #include <linux/proc_fs.h> #include <linux/types.h> #include <linux/spinlock.h> #include <linux/interrupt.h> #include <asm/hardirq.h> #include <linux/sched.h> //schedule() /* * This module is a silly one: it only embeds short code fragments * that show how time delays can be handled in the kernel. */ int delay = HZ; /* s3c24x0 HZ= 200*/ module_param(delay, int, 0); /* use these as data pointers, to implement four files in one function */ enum jit_files { JIT_BUSY, JIT_SCHED, JIT_QUEUE, JIT_SCHEDTO }; /* 当驱动程序需要延迟比较长的时间,则要用一个长时钟滴答,而忙等待则是其中最不常用到的一种,此方法就是在等待期间锁定处理器,在没有完成延迟之前,处理器始终处于等待中,此方法一般很少使用,因为会大大的降低系统性能,如果不是抢占式内核中应用时,则更加可怕,因为调度器不会抢占在处理器中的进程,则在此延迟期间,处理器就如死掉一般。如果在时间未来临前,中止了中断,则系统就死了。下面是这个方法的程序片段: */ int jit_fn(char *buf, char **start, off_t offset,int len, int *eof, void *data) { unsigned long j0, j1; /* jiffies */ wait_queue_head_t wait; init_waitqueue_head (&wait); j0 = jiffies; j1 = j0 + delay; /*下面代码主要是执行延迟时间,然后通过 jiffies显示出来*/ 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; /* actual value after we delayed */ len = sprintf(buf, "%9li %9li\n", j0, j1); *start = buf; return len; } /* * This file, on the other hand, returns the current time forever */ 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; /* get them four */ j1 = jiffies; j2 = get_jiffies_64(); do_gettimeofday(&tv1);//此函数用秒或者毫秒来填充一个struct timeval的指针变量 tv2 = current_kernel_time();//内核辅助函数,用以访问struct timeval的两个成员 /* print */ 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; /*if you want currentime to output only onec ,disable this line!*/ return len; } /* * The timer example follows */ int tdelay = 10; module_param(tdelay, int, 0); /* This data structure used as "data" for the timer and tasklet functions */ struct jit_data { struct timer_list timer; struct tasklet_struct tlet; int hi; /* tasklet or tasklet_hi */ wait_queue_head_t wait; unsigned long prevjiffies; unsigned char *buf; int loops; }; #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->prevjiffies = j; mod_timer(&data->timer, data->timer.expires+tdelay); } else { wake_up_interruptible(&data->wait); } } /* the /proc function: allocate everything to allow concurrency */ 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); /* write the first lines in the buffer */ 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); /* fill the data for our timer function */ data->prevjiffies = j; data->buf = buf2; data->loops = JIT_ASYNC_LOOPS; /* register the timer */ data->timer.data = (unsigned long)data; data->timer.function = jit_timer_fn; data->timer.expires = j + tdelay; /* parameter */ add_timer(&data->timer); /* wait for the buffer to fill */ 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); } } /* the /proc function: allocate everything to allow concurrency */ 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); /* write the first lines in the buffer */ 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); /* fill the data for our tasklet function */ data->prevjiffies = j; data->buf = buf2; data->loops = JIT_ASYNC_LOOPS; /* register the tasklet */ 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 for the buffer to fill */ 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("currentime", 0, NULL, jit_currentime, NULL); create_proc_read_entry("jitbusy", 0, NULL, jit_fn, (void *)JIT_BUSY); //根据最后不同的data 调用 jit_fn 不同代码段 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("jitimer", 0, NULL, jit_timer, NULL); create_proc_read_entry("jitasklet", 0, NULL, jit_tasklet, NULL); create_proc_read_entry("jitasklethi", 0, NULL, jit_tasklet, (void *)1); return 0; /* success */ } void __exit jit_cleanup(void)//卸载模块时删除建立的文件 { remove_proc_entry("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("jitimer", NULL); remove_proc_entry("jitasklet", NULL); remove_proc_entry("jitasklethi", NULL); } module_init(jit_init); //insmod jit.ko module_exit(jit_cleanup); //rmmod jit.ko MODULE_AUTHOR("Alessandro Rubini ( modified by tekkaman )"); MODULE_LICENSE("Dual BSD/GPL");Makefile
KERNELDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) obj-m := jit.o modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules clean: rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions .PHONY: modules modules_install cleanroot@ubuntu:~/桌面/jit# make
root@ubuntu:~/桌面/jit# insmod jit.ko
root@ubuntu:~/桌面/jit# lsmod //查询安装完毕
其中文件currentime,jitbusy,jitsched,jitqueue,jitschedto,jitimer,jitasklet,jitasklethi都是模块jit创建
root@ubuntu:~/桌面/jit#head -6 /proc/currentime //查询currentime 文件的前六行(currentime 为jit程序创建)
/*返回的值为:当前的 jiffies 和 jiffies_64 值, 以 16 进制数的形式.
如同 do_gettimeofday 返回的相同的当前时间.
由 current_kernel_time 返回的 timespec.*/
0x004e4a3e 0x00000001004e4a3e 1334565617.514572
1334565617.511113437
0x004e4a3e 0x00000001004e4a3e 1334565617.514575
1334565617.511113437
0x004e4a3e 0x00000001004e4a3e 1334565617.514576
1334565617.511113437
root@ubuntu:~/桌面/jit# dd bs=20 count=5 < /proc/jitbusy //dd 命令参见【补充1】
5183602 5183852
5183852 5184102
5184102 5184352
5184352 5184602
5184602 5184852
记录了5+0 的读入
记录了5+0 的写出
100字节(100 B)已复制,4.99935 秒,0.0 kB/秒
root@ubuntu:~/桌面/jit# dd bs=20 count=5 < /proc/jitsched
5198924 5199174
5199174 5199424
5199424 5199674
5199674 5199924
5199924 5200174
记录了5+0 的读入
记录了5+0 的写出
100字节(100 B)已复制,4.99645 秒,0.0 kB/秒
root@ubuntu:~/桌面/jit# dd bs=20 count=5 < /proc/jitqueue
5205914 5206164
5206164 5206414
5206414 5206664
5206664 5206914
5206914 5207164
记录了5+0 的读入
记录了5+0 的写出
100字节(100 B)已复制,4.99969 秒,0.0 kB/秒
root@ubuntu:~/桌面/jit# dd bs=20 count=5 < /proc/jitschedto
5212110 5212360
5212360 5212610
5212610 5212860
5212860 5213110
5213110 5213360
记录了5+0 的读入
记录了5+0 的写出
100字节(100 B)已复制,4.99915 秒,0.0 kB/秒
root@ubuntu:~/桌面/jit# cat /proc/jitimer //inirp有没有被中断
time delta inirq pid cpu command
5226700 0 0 4625 3 cat
5226710 10 1 0 3 kworker/0:1
5226720 10 1 0 3 kworker/0:1
5226730 10 1 0 3 kworker/0:1
5226740 10 1 0 3 kworker/0:1
5226750 10 1 0 3 kworker/0:1
root@ubuntu:~/桌面/jit# cat /proc/jitasklet
time delta inirq pid cpu command
5236006 0 0 4626 2 cat
5236006 0 1 13 2 ksoftirqd/2
5236006 0 1 13 2 ksoftirqd/2
5236006 0 1 13 2 ksoftirqd/2
5236006 0 1 13 2 ksoftirqd/2
5236006 0 1 13 2 ksoftirqd/2
root@ubuntu:~/桌面/jit# cat /proc/jitasklethi
time delta inirq pid cpu command
5241403 0 0 4627 2 cat
5241403 0 1 13 2 ksoftirqd/2
5241403 0 1 13 2 ksoftirqd/2
5241403 0 1 13 2 ksoftirqd/2
5241403 0 1 13 2 ksoftirqd/2
5241403 0 1 13 2 ksoftirqd/2
【补充1】dd 是 Linux/UNIX 下的一个非常有用的命令,作用是用指定大小的块拷贝一个文件,并在拷贝的同时进行指定的转换。 dd 的主要选项: