操作系统Linux课程实验报告文档格式.docx
《操作系统Linux课程实验报告文档格式.docx》由会员分享,可在线阅读,更多相关《操作系统Linux课程实验报告文档格式.docx(14页珍藏版)》请在冰豆网上搜索。
wait(&
state);
}
实验内核模块
实验步骤:
(1).编写内核模块
文件中主要包含init_clock(),exit_clock(),read_clock()三个函数。
其中init_clock(),exit_clock()负责将模块从系统中加载或卸载,以及增加或删除模块在/proc中的入口。
read_clock()负责产生/proc/clock被读时的动作。
(2).编译内核模块Makefile文件
#Makefileunder
ifneq($(KERNELRELEASE),)
#kbuildsyntax.dependencyrelationshsipoffilesandtargetmodulesarelistedhere.
obj-m:
=
else
PWD:
=$(shellpwd)
KVER?
=$(shelluname-r)
KDIR:
=/lib/modules/$(KVER)/build
all:
$(MAKE)-C$(KDIR)M=$(PWD)modules
clean:
rm-rf.*.cmd*.o*.*.ko.tmp_versions*.symvers*.order
endif
编译完成之后生成模块文件。
(3).内核模块源代码
#include<
linux/>
asm/>
#defineMODULE
#defineMODULE_VERSION"
"
#defineMODULE_NAME"
clock"
structproc_dir_entry*my_clock;
intread_clock(char*page,char**start,off_toff,intcount,int*eof,
void*data){
intlen;
structtimevalxtime;
do_gettimeofday(&
xtime);
len=sprintf(page,"
%d%d\n"
,;
printk("
clock:
read_func()\n"
returnlen;
}
structproc_dir_entry*clock_proc_file;
intinit_clock(void)
{
clock_proc_file=create_proc_read_entry("
0,NULL,read_clock,NULL);
return0;
voidexit_clock(void)
remove_proc_entry("
clock_proc_file);
module_init(init_clock)
module_exit(exit_clock)
MODULE_LICENSE("
GPL"
(4).编译内核模块
#make
(5).加载内核模块
在系统root用户下运行用户态模块命令装载内核模块
#insmod
(6).测试
在终端中输入以下命令:
#cat/proc/clock
(7).卸载内核模块
在系统root用户下运行用户态模块命令卸载内核模块
#rmmod
实验系统调用
(1).添加新调用的源代码
在./中添加相应的调用代码
asmlinkageintsys_xwlcall(structtimeval*tv)
structtimevalktv;
ktv);
copy_to_user(tv,&
ktv,sizeof(ktv));
printk(KERN_ALERT"
PID%ldcalledsys_xwlcall()./n"
(long)current->
pid);
(2).连接系统调用
a、修改./,
在系统调用列表后面相应位置添加一行,这样在用户空间做系统调用时就不需要知道系统调用号了,如果在用户空间指明了调用号,就可以省略这一步,实际上我就没写:
#define__NR_xwlcall338
新增加的调用号位338
b、修改./
在ENTRY(sys_call_table)清单最后添加一行,这步至关重要,338就是这里来的:
.longsys_xwlcall
(3).重建新的Linux内核
先安装好编译内核必要的软件包:
#sudoapt-getinstallbuild-essentialkernel-packagelibncurses5-dev
复制当前内核的配置文件
#cp/boot/config-`uname-r`./.config
保存配置文件
#sudomakemenuconfig
使用debian的的内核编译方法,要简单很多
#sudomake-kpkg-initrd--initrd--append-to-version=xwlcall
kernel_imagekernel-headers
运行以下deb包,安装内核镜像和模块:
运行以下deb包,安装内核头文件:
运行以下命令,使内核启动时能调用模块,比如硬件驱动:
#sudoupdate-initramfs-c-k此次编译的内核采用ubuntu默认配置文件,通用性非常好,可以拷贝到大部分x86机器上安装。
安装后系统自动会修改grub启动选单。
4.重建引导信息
a、安装deb包就自动重建引导信息了,无须另行处理。
b、如果仍然不放心,可以运行
#update-grub
5.重新引导从新的内核进入
6.修改系统调用表
7.测试
实验Shell编程实验(进程管理实验)
1、实验目的
通过编写shell程序,了解子进程的创建和父进程与子进程间的协同,获得多进程程序的编程经验。
2、实验内容1
设计一个简单的shell解释程序,能实现基本的bsh功能。
3、实验原理
将每一条命令分子段压入argv栈。
然后再子进程中调用execvp()来实现该命令的功能。
4、代码(源代码清单)
#defineBUFFERSIZE256
n"
buf);
计思路
通过fork()创建子进程,用execvp()更改子进程代码,用wait()等待子进程结束。
这三个系统调用可以很好地创建多进程。
另一方面,编写的Shell要实现管道功能,需要用pipe()创建管道使子进程进行通信。
2.源代码清单
#defineBUFFERSIZE256
exit
(1);
n=0;
argv2[n++]=cmd2;
while(argv2[n++]=strtok(NULL,"
\t\n"
));
pipe(fd);
if(fork()==0){
dup2(fd[0],0);
验步骤
(1)、安装GDB
(2)、编写观测程序
(3)、按照指令手册进行观察操作
2.观测程序源代码
charstr[50]="
HelloLinux."
;
intmain()
intnum=10;
while(num--){
printf("
%s\n"
str);
验结果及分析
(1).Gdb程序观察一个程序文件的内容和结构
结果截图:
(2).GDB观察程序内存映象的内容和结构
(3).在Linux下,用free和vmstat命令观察内存使用情况
(4).在Linux下,查看/proc与内存管理相关的文件,并解释显示结果
实验观察实验(进程通信)
在Linux下,用ipcs()命令观察进程通信情况,了解Linux基本通信机制
实验结果(截图):
实验IO系统编程实验
编写一个daemon进程,该进程定时执行ps命令,然后将该命令的输出写至文件F1尾部。
通过此实验,掌握LinuxI/O系统相关内容。
2、实验内容
3、实验原理
在这个程序中,首先fork一个子程序,然后,关闭父进程,这样,新生成的子进程被交给init进程接管,并在后台执行。
新生成的子进程里,使用system系统调用,将ps的输出重定向,输入到里面。
4、实验步骤
编写
代码如下:
intmain(intargc,char*argv[])
inti,p;
p=fork();
if(p>
0){
exit(0);
elseif(p==0){
for(i=0;
i<
100;
i++){
sleep(100);
system("
ps>
"
else{
perror("
Createnewprocess!
return1;
编译程序
#gcc-odaemon
执行程序
#./daemon
实验代码分析(文件系统管理实验)
1.实验目的
了解与文件管理有关的Linux内核模块的代码结构。
2.实验结果(源代码分析)
A.创建文件模块分析
5780/*creatsystemcall*/
5781Creat()
5782{
5783resister*ip;
5784externuchar;
5785
5786ip=namei(&
uchar,1);
5787if(ip==NULL){
5788if
5789return;
5790ip=maknode[1]&
07777&
(~ISVTX));
5791if(ip==NULL)
5792return;
5793open1(ip,FWRITE,2);
5794}else
5795open1(ip,FWRITE,1);
5796}
第5786:
“namei”(7518)将一路径名变换成一个“inode”指针。
“uchar”是一个过程的
名字,它从用户程序数据区一个字符一个字符地取得文件路径名。
5787:
一个空“inode”指针表示出了一个错,或者并没有具有给定路径名的文件存在。
5788:
对于出错的各种条件,请见UMP的CREAT(II)。
5790:
“maknode”(7455)调用“ialloc”创建一内存“inode”,然后对其赋初值,并使
其进入适当的目录。
注意,显式地清除了“粘住”位(ISVTX)。
B.删除文件rm模块分析
3510unlink()
3511{
3512resister*ip,*pp;
3513externuchar;
3514
3515pp=namei(&
uchar,2);
3516if(pp==NULL)
3517return;
3518prele(pp);
3519ip=iset(pp->
dev,
3520if(ip==NULL)
3521panic(*unlink–iset*);
3522if((ip->
i_mode%IFMT)==IFDIR&
&
!
suser())
3523gotoout;
3524[1]=-DIRSIZ+2;
3525=&
3526=DIRSIZE+2;
3527=0;
3528writei(pp);
3529ip->
i_nlink--;
3530ip->
i_flag=!
IUPD;
3531
3532out:
3533iput(pp);
3534iput(ip);
3535}
新文件作为永久文件自动进入文件目录。
关闭文件不会自动地造成文件被删除。
当内存“inode”项中的“i_nlink”字段值为0并且相应文件未被打开时,将删除该文件。
在创建文件时,该字段由“maknode”赋初值为1。
系统调用“link”(5941)可将其值加1,系统调用“unlink”(3529)则可将其值减1。
创建临时“工作文件”的程序应当在其终止前执行“unlink”系统调用将这些文件删除。
注意,“unlink”系统调用本身并没有删除文件。
当引用计数(i_count)被减为0时(7350、7362),才删除该文件。
为了减少在程序或系统崩溃时遗留下来的临时文件所带来的问题,程序员应当遵守下列约定:
(1)在打开临时文件后立即对其执行“unlink”操作。
(2)应在“tmp”目录下创建临时文件。
在文件名中包括进程标识数就可构成一惟一文件名
C.读写模块分析
5711Read()
5712{
5713rdwr(FREAD);
5714}
5720Write()
5721{
5722rdwr(FWRITE);
5723}
5731rdwr(mode)
5732{
5733resister*fp,m;
5734
5735m=mode;
5736fp=setf[R0]);
5737if(fp==NILL)
5738return;
5739if((fp->
f_flag&
m==0){
5740=EBADF;
5741return;
5742}
5743=[0];
5744=[1];
5745=0;
5746if(fp->
FPIPE){
5747if(m==FREAD)
5748readp(fp);
5749writep(fp);
5750}else{
5751[1]=fp->
f_offset[1];
5752[0]=fp->
f_offset[0];
5753if(m==FREAD)
5754readi(fp->
f_inode);
5755writei(fp->
5756dpadd(fp->
f_offset,[1]–;
5757}
5758[R0]=[1]–;
5759}
“read”系统调用的基本工作过程为:
……read(f,b,n);
/*用户程序*/
{发生陷入}
2693trap{#3系统调用}
5711read();
5713rdwr(FREAD);
用户进程执行系统调用激活运行在核心态的“trap”。
“trap”识别#3系统调用,然后通过“trapl”调用例程“read”,它又调用“rdwr”。
“rdwr”包含了很多“read”和“write”操作共用的代码。
它调用“getf”(6619)将用户进程提供的文件标识变换成“file”数组中一项的地址。
注意,该系统调用的第1个参数是以不同于另外2个参数的方式传送的。
将“”设置为0,这表示此操作的目的地址在用户地址空间中。
在以一个inode指针参数调用“readi”后,将要求传送的字符数减去剩余未传输字符数(在_count中),加至文件位移量中。
6221readi
6239lbn=lshift,-9);
6248on=[i]&
0777;
6241n=min(512–on,;
6250dn=ip->
i_dev;
6258bp=bread(dn,bn);
6260iomove(bp,on,n,B_READ);
6261brelse(bp);
“readi”将文件位移量分解成两部分:
一个逻辑块号“lbn”,以及一个块内索引“on”。
将要传输的字符数是下而两个值中的较小者:
“_count”和块内尚余字符数(在这种情况下以后还必须读其他块,此处没有进一步对此说明),还应考虑尚余留在文件中的字符数(对这种情况也未进一步说明)。
“dn”是存储在“inode”中的设备编号,“bn”是在该设备(磁盘)上的实际块号,这是由“bmap”(6415)用“lbn”计算得到的。
对“bread”的调用找到所要求的磁盘块,若需要,则将其从磁盘复制到内存中。
“iomove”(6364)将适当数量的字符传送至目的区,然后执行计数操作。
“read”和“write”执行的操作有很多相似之处,两者共享很多代码。
系统调用“read”(5711)和“write”(5720),然后立即调用“rdwr”,它执行下列操作:
5736:
将用户程序文件标识变换成指向相应文件表项的指针。
5739:
检查所要求的操作(读或写)是否与文件打开时的读/写方式符合。
5743:
用各参数在“u”中设置几个标准单元。
5746:
从此开始对“管道”文件进行特殊处理。
5755:
按读、写要求分别调用“readi”或“writei”。
5756:
更新文件位移量,使其增加实际传送的字符数,同时也将实际传送的字符数返回。