Linux内核实验报告实验4.docx

上传人:b****2 文档编号:20109180 上传时间:2023-04-25 格式:DOCX 页数:18 大小:19.78KB
下载 相关 举报
Linux内核实验报告实验4.docx_第1页
第1页 / 共18页
Linux内核实验报告实验4.docx_第2页
第2页 / 共18页
Linux内核实验报告实验4.docx_第3页
第3页 / 共18页
Linux内核实验报告实验4.docx_第4页
第4页 / 共18页
Linux内核实验报告实验4.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

Linux内核实验报告实验4.docx

《Linux内核实验报告实验4.docx》由会员分享,可在线阅读,更多相关《Linux内核实验报告实验4.docx(18页珍藏版)》请在冰豆网上搜索。

Linux内核实验报告实验4.docx

Linux内核实验报告实验4

(此文档为word格式,下载后您可任意编辑修改!

Linux内核实验报告

 

实验题目:

动态模块设计实验

 

实验目的:

Linux模块是一些可以独立于内核单独编译的内核函数和数据类型集合,是可增删的

内核部分。

模块在内核启动时装载称为静态装载,在内核已经运行时装载称为动态装载。

模块可以扩充内核所期望的任何功能,但通常用于实现设备驱动程序。

通过本实验,将学习到动态模块的设计过程,以及Proc文件系统的部分知识。

硬件环境:

Pentium(R)Dual-CoreCPUT4400@2.20GHz

软件环境:

Ubuntu12.04

gccversion4.6.3(Ubuntu/Linaro4.6.3-1ubuntu5)

内核版本:

3.0.24

实验步骤:

1、代码分析

模块初始化和模块卸载的函数都类同,同时读取proc文件的函数在本次实验中没有用到,所以着重描述写驱动函数。

实验A:

 

在这个proc函数中只是简单得输出jiffies的数值。

实验B:

遍历父进程和所有进程,依然是在proc_read中,通过以下代码片段完成功能,注意在这里,我们是通过直接向系统分配的那一个page直接写入来得到的,所以每次不同的进程访问该proc文件的时候得到的结果都不一样

遍历父进程:

len+=sprintf(page+len,"遍历父进程\npid\tppid\tcomm\n");

while(task!

=&init_task){

len+=sprintf(page+len,"%d\t%d\t[%s]\n",task->pid,task->parent->pid,task->comm);

task=task->parent;

}

遍历所有进程,通过for_each_process(task)这个宏来遍历所有进程:

len+=sprintf(page+len,"遍历任务队列\ncomm\tpid\n");

for_each_process(task){

len+=sprintf(page+len,"%d\t[%s]\n",task->pid,task->comm);

}

returnlen;

实验C:

在模块开头通过module_param声明了模块参数,在装载模块时通过它来传参

module_param(param,int,0644);

在proc_read函数中通过这个传入的参数来判断应该读取内核的哪些数值,其中标注黄色的一段是从内核实现/proc/loadavg部分中抽取出来的,loops_per_jiffy是每个滴答能执行的循环数,在内核启动的时候计算出来的这个值:

if(param==0){//获取loadavg

len+=sprintf(page+len,"%lu.%02lu%lu.%02lu%lu.%02lu\n"/*%ld/%d%d\n*/,

LOAD_INT(avenrun[0]),LOAD_FRAC(avenrun[0]),

LOAD_INT(avenrun[1]),LOAD_FRAC(avenrun[1]),

LOAD_INT(avenrun[2]),LOAD_FRAC(avenrun[2])

/*,nr_running(),nr_threads,*/

/*task_active_pid_ns(current)->last_pid*/);

}elseif(param==1){

len+=sprintf(page+len,"loops_per_jiffy:

%lu\n",loops_per_jiffy);

len+=sprintf(page+len,"bogomips=lpj/(500000/HZ):

\n%lu.%02lu\n",loops_per_jiffy/(500000/HZ),loops_per_jiffy/(5000/HZ)%100);

}

在这里我们还设计了改写loops_per_jiffy的方法:

staticintproc_write(structfile*file,constchar*buffer,unsignedlongcount,void*data)

{

intlen;

charbuf[16];

if(count>MYDATA_LEN)

len=MYDATA_LEN;

else

len=count;

copy_from_user(buf,buffer,len);

loops_per_jiffy=simple_strtol(buf,NULL,10);

returnlen;

}

2、设计说明

实验A:

对于读取时间,内核提供了do_gettimeofday这个函数,同时在对用户也提供了一个系统调用gettimeofday,这两个获取当前时间的途径都是一样的(在x86上都是访问TSC寄存器——时间戳寄存器来获得时间值),所以一般都要比用jiffies滴答数获得的时间数要准确。

在进行这两种比较时,我们可以有两种策略,直接在proc文件中不停输出两者数值(jiffies和当前时间),或者proc文件只输出文件,在通过用户程序调用系统调用获得时间值再进行比较,在这里使用了第二种。

实验B:

设计说明在代码分析中已经阐明

实验C:

设计说明在代码分析中已经阐明

3、调试记录

实验A:

可以看到在几次循环中,jiffies的值始终没有变,而gettimeofday的值确是一直在变,实际上我的机器的内核HZ设置的是250,也就是0.004秒发生一个滴答,所以滴答数要改变的话,gettimeofday的值至少要变化4000微秒,jiffies的值才能改变,这说明了gettimeofday的精确度逼jiffies的精确度要高(至少是在本次实验环境中)。

实验B:

值得注意的是0号进程swapper进程,查资料发现它就是所谓的idle进程。

实验C:

1.

2.

结论分析与体会:

在本次实验中充分体会了动态模块的灵活性。

可以在装载的时候传入参数,从而改变模块在以后的行为。

proc文件并不是一开始就在哪里,而是动态生成,动态计算的。

虽然对于用户来说proc文件与一般的文件都是有相同的行为,但是其本质确实生成内容而非读取内容的,在这里充分体现出了linux设计的灵活性,以及VFS提供的这种抽象级别的强大之处。

通过对proc的学习,对于以后的调试工作也有一定的帮助。

另一方面,对于模块开发的过程也有了一定的了解,基本上对于一个模块,需要做的事就是:

1.包含必要的头文件

2.使用必要的宏声明模块初始化函数和模块卸载函数

3.实现函数

另一方面,编写模块时Makefile的编写也是值得注意的地方,在这里附上本次实验中用到的一份Makefile

obj-m:

=pm2.o

MOD=pm2

all:

make-C/lib/modules/$(shelluname-r)/buildM=$(shellpwd)modules

clean:

make-C/lib/modules/$(shelluname-r)/buildM=$(shellpwd)clean

rmmod:

sudormmodpm2

install:

sudoinsmodpm2.ko

test:

cat/proc/$(MOD)dir/$(MOD)file

程序完整源代码:

问题A:

#include

#include

#include

#include

#include

#include

#include

#include//do_gettimeofday

/*#include*/

/*#include*/

/*#include*/

/*#include*/

/*#include*/

/*#include*/

#defineMODULE_NAME"Myproc"

#defineMYDATA_LEN16

//放用户空间传入的数据

structmy_proc_data{

charvalue[MYDATA_LEN];

};

structmy_proc_datamydata;

//proc结构变量

staticstructproc_dir_entry*example_dir;

staticstructproc_dir_entry*data_file;

staticintparam;

module_param(param,int,0644);

/***********************v2***********************

//读文件myfile的读驱动函数

staticintproc_read(char*buf,char**start,off_toff,intcount,int*eof,void*data)

{

intlen=0;

structtimevaltv;

unsignedlongj1;

u64j2;

do_gettimeofday(&tv);

j1=jiffies;

j2=get_jiffies_64();

len+=sprintf(buf+len,"%10i.%06i\n",tv.tv_sec,tv.tv_usec);

len+=sprintf(buf+len,"0x%08lx0x%016Lx\n",j1,j2);

*start=buf;

returnlen;

}

*************************************************/

staticintproc_read(char*buf,char**start,off_toff,intcount,int*eof,void*data)

{

intlen=0;

unsignedlongj1;

j1=jiffies;

len+=sprintf(buf+len,"0x%08lx\n",jiffies);

*eof=1;//区别?

不加似乎会在读取结束的时候多发一个不会成功的read请求

printk(KERN_ALERT"len%doff%dcount%d\n",len,off,count);

returnlen;

}

//写文件myfile的写驱动函数

staticintproc_write(structfile*file,constchar*buffer,unsignedlongcount,void*data)

{

intlen;

structmy_proc_data*mydatap=(structmy_proc_data*)data;

if(count>MYDATA_LEN)

len=MYDATA_LEN;

else

len=count;

if(copy_from_user(mydatap->value,buffer,len)){//buffer在usermode

return-EFAULT;//?

Badaddress,whyminus?

}

mydatap->value[len-1]='\0';

returnlen;

}

//装入模块

intinit_module(void)

{

//创建proc/myfile目录

example_dir=(structproc_dir_enry*)proc_mkdir("pm1dir",NULL);

if(example_dir==0){

printk("mkdirfail\n");

return-1;

}

data_file=(structproc_dir_entry*)create_proc_entry("pm1file",0666,example_dir);

if(data_file==0){

remove_proc_entry("pm1file",0);

printk("mkfilefale\n");

return-ENOMEM;

}

strcpy(mydata.value,"Ticks=");

data_file->data=&mydata;

data_file->read_proc=&proc_read;

data_file->write_proc=&proc_write;

//data_file->owner=THIS_MODULE;在我的内核中该结构已经没有owner成员了

return0;

}

//卸载模块

voidcleanup_module(void)

{

remove_proc_entry("pm1file",example_dir);

remove_proc_entry("pm1dir",NULL);

printk("Goodbye.\n");

}

MODULE_LICENSE("GPL");

MODULE_DESCRIPTION("TEST");

MODULE_AUTHOR("xxx");

问题A用户测试程序:

#include

#include

#include

#include

#include

#include

#definepath"/proc/pm1dir/pm1file"

#defineprefix""

#defineprelen6

#defineITERNUM10//默认循环次数

intmain(intargc,char*argv[])

{

intn;

if(argc>1){

n=atoi(argv[1]);

}else{

n=ITERNUM;

}

FILE*fp=0;

charbuf[16];

structtimevaltv;

for(;n>0;--n){

fp=fopen(path,"r");

printf("%s",fgets(buf,16,fp));

fclose(fp);

gettimeofday(&tv,NULL);

printf("%10li.%06li\n***************************\n",tv.tv_sec,tv.tv_usec);

}

}

问题B:

#include

#include

#include

#include

#include

#include

#include

#include//task_struct等

/*#include*/

#defineMODULE_NAME"Myproc"

#defineMYDATA_LEN16

#definePMDIR"pm2dir"

#definePMFILE"pm2file"

//放用户空间传入的数据

structmy_proc_data{

charvalue[MYDATA_LEN];

};

structmy_proc_datamydata;

//proc结构变量

staticstructproc_dir_entry*example_dir;

staticstructproc_dir_entry*data_file;

staticintparam;

module_param(param,int,0644);

//读文件myfile的读驱动函数

staticintproc_read(char*page,char**start,off_toff,intcount,int*eof,void*data)

{

intlen=0;

structtask_struct*task=current;

structmy_proc_data*mydatap=(structmy_proc_data*)data;

len+=sprintf(page+len,"%s%ldHZ=%d\n",mydatap->value,jiffies,HZ);

len+=sprintf(page+len,"遍历父进程\npid\tppid\tcomm\n");

while(task!

=&init_task){

len+=sprintf(page+len,"%d\t%d\t[%s]\n",task->pid,task->parent->pid,task->comm);

task=task->parent;

}

/*tasknowpointstoinit*/

len+=sprintf(page+len,"%d\t%d\t[%s]\n",task->pid,task->parent->pid,task->comm);

/*len+=sprintf(page+len,"init:

%d\t[%s]\n",(&init_task)->pid,(&init_task)->comm);*/

len+=sprintf(page+len,"遍历任务队列\ncomm\tpid\n");

for_each_process(task){

/*thispoinlesslyprintsthenameandpidofeachtask*/

/*printk("%s[%d]",task->comm,task->pid);*/

len+=sprintf(page+len,"%d\t[%s]\n",task->pid,task->comm);

}

returnlen;

}

//写文件myfile的写驱动函数

staticintproc_write(structfile*file,constchar*buffer,unsignedlongcount,void*data)

{

intlen;

structmy_proc_data*mydatap=(structmy_proc_data*)data;

if(count>MYDATA_LEN)

len=MYDATA_LEN;

else

len=count;

if(copy_from_user(mydatap->value,buffer,len)){//buffer在usermode

return-EFAULT;//?

Badaddress,whyminus?

}

mydatap->value[len-1]='\0';

returnlen;

}

//装入模块

intinit_module(void)

{

//创建proc/myfile目录

example_dir=(structproc_dir_enry*)proc_mkdir(PMDIR,NULL);

if(example_dir==0){

printk("mkdirfail\n");

return-1;

}

data_file=(structproc_dir_entry*)create_proc_entry(PMFILE,0666,example_dir);

if(data_file==0){

remove_proc_entry("myfile",0);

printk("mkfilefale\n");

return-ENOMEM;

}

strcpy(mydata.value,"Ticks=");

data_file->data=&mydata;

data_file->read_proc=&proc_read;

data_file->write_proc=&proc_write;

//data_file->owner=THIS_MODULE;在我的内核中该结构已经没有owner成员了

return0;

}

//卸载模块

voidcleanup_module(void)

{

remove_proc_entry(PMFILE,example_dir);

remove_proc_entry(PMDIR,NULL);

printk("Goodbye.\n");

}

MODULE_LICENSE("GPL");

MODULE_DESCRIPTION("TEST");

MODULE_AUTHOR("xxx");

问题C:

#include

#include

#include

#include

#include

#include

#include

#include//task_struct等

#include

#include

#include

#include

#defineLOAD_INT(x)((x)>>FSHIFT)

#defineLOAD_FRAC(x)LOAD_INT(((x)&(FIXED_1-1))

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > IT计算机 > 电脑基础知识

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1