操作系统-Linux课程实验报告.doc

上传人:李医生 文档编号:6080038 上传时间:2020-09-06 格式:DOC 页数:37 大小:1.88MB
返回 下载 相关 举报
操作系统-Linux课程实验报告.doc_第1页
第1页 / 共37页
操作系统-Linux课程实验报告.doc_第2页
第2页 / 共37页
操作系统-Linux课程实验报告.doc_第3页
第3页 / 共37页
操作系统-Linux课程实验报告.doc_第4页
第4页 / 共37页
操作系统-Linux课程实验报告.doc_第5页
第5页 / 共37页
点击查看更多>>
资源描述

《操作系统-Linux课程实验报告.doc》由会员分享,可在线阅读,更多相关《操作系统-Linux课程实验报告.doc(37页珍藏版)》请在三一文库上搜索。

1、实验1.1、1.2 Linux Ubuntu的安装、创建新的虚拟机VMWare实验1.3 Shell编程1.实验目的与内容通过本实验,了解Linux系统的shell机制,掌握简单的shell编程技巧。编制简单的Shell程序,该程序在用户登录时自动执行,显示某些提示信息,如“Welcome to Linux”, 并在命令提示符中包含当前时间、当前目录和当前用户名等基本信息。2.程序源代码清单#include#include int main()printf(Hello Linuxn);int pid;int state;int pfd2;pipe(pfd);if (fork()=0)print

2、f(In the grep progressn);dup2(pfd0,0);close(pfd0);close(pfd1);execlp(grep,grep,sh,0);perror(exelp grep error);esle if(fork()=0) printf(In the ps progressn);dup2(pfd1,1);close(pfd0);close(pfd1);execlp(ps,ps,-ef,0);perror(execlp ps -ef);close(pfd1);close(pfd0);wait(&state);wait(&state);实验2.3 内核模块实验步骤:

3、(1).编写内核模块 文件中主要包含init_clock(),exit_clock(),read_clock()三个函数。其 中init_clock(),exit_clock()负责将模块从系统中加载或卸载,以及增加或删除模块在/proc中的入口。read_clock()负责产生/proc/clock被读时的动作。(2).编译内核模块Makefile文件# Makefile under 2.6.25 ifneq ($(KERNELRELEASE),) #kbuild syntax. dependency relationshsip of files and target modules are

4、 listed here. obj-m := proc_clock.o else PWD := $(shell pwd) KVER ?= $(shell uname -r) KDIR := /lib/modules/$(KVER)/build all: $(MAKE) -C $(KDIR) M=$(PWD) modules clean: rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions *.symvers *.order endif 编译完成之后生成proc_clock.ko模块文件。(3).内核模块源代码clock.c#include #include

5、 #include #include #include #include #define MODULE #define MODULE_VERSION 1.0 #define MODULE_NAME clock struct proc_dir_entry* my_clock; int read_clock(char* page, char* start, off_t off, int count, int* eof, void* data) int len; struct timeval xtime; do_gettimeofday(&xtime); len = sprintf(page, %d

6、 %dn, xtime.tv_sec, xtime.tv_usec); printk(clock: read_func()n); return len; struct proc_dir_entry *clock_proc_file; int init_clock(void) clock_proc_file =create_proc_read_entry(clock,0,NULL,read_clock,NULL); return 0; void exit_clock(void) remove_proc_entry(clock,clock_proc_file); module_init(init_

7、clock) module_exit(exit_clock) MODULE_LICENSE(GPL);(4).编译内核模块# make (5) .加载内核模块 在系统root用户下运行用户态模块命令装载内核模块 # insmod proc_clock.ko(6).测试在终端中输入以下命令: cat /proc/clock (7).卸载内核模块在系统root用户下运行用户态模块命令卸载内核模块#rmmod proc_clock.ko 实验2.4 系统调用实验步骤:(1). 添加新调用的源代码 在./linux-2.6.33.7/arch/x86/kernel/sys_i386_32.c中添加相应

8、的调用代码asmlinkage int sys_xwlcall(struct timeval *tv) struct timeval ktv; do_gettimeofday(&ktv); copy_to_user(tv,&ktv,sizeof(ktv); printk(KERN_ALERTPID %ld called sys_xwlcall()./n,(long)current-pid); return 0; (2). 连接系统调用 a、修改./linux-2.6.33.7/arch/x86/include/asm/unistd_32.h,在系统调用列表后面相应位置添加一行,这样在用户空间做

9、系统调用时就不需要知道系统调用号了,如果在用户空间指明了调用号,就可以省略这一步,实际上我就没写:#define _NR_xwlcall338 新增加的调用号位338 b、修改./linux-2.6.33.7/arch/x86/kernel/syscall_table_32.S 在ENTRY(sys_call_table)清单最后添加一行,这步至关重要,338就是这里来的: .long sys_xwlcall (3). 重建新的Linux内核先安装好编译内核必要的软件包:# sudo apt-get install build-essential kernel-package libncurs

10、es5-dev 复制当前内核的配置文件 # cp /boot/config-uname -r ./.config 保存配置文件# sudo make menuconfig 使用debian的的内核编译方法,要简单很多# sudo make-kpkg-initrd-initrd-append-to-version=xwlcallkernel_image kernel-headers 运行以下deb包,安装内核镜像和模块:linux-image-2.6.33.7xwlcall_2.6.33.7xwlcall-10.00.Custom_i386.deb运行以下deb包,安装内核头文件:linux-h

11、eaders-2.6.33.7xwlcall_2.6.33.7xwlcall-10.00.Custom_i386.deb 运行以下命令,使内核启动时能调用模块,比如硬件驱动:# sudo update-initramfs -c -k 2.6.33.7xwlcall此次编译的内核采用ubuntu默认配置文件,通用性非常好,可以拷贝到大部分x86机器上安装。安装后系统自动会修改grub启动选单。4. 重建引导信息 a、安装deb包就自动重建引导信息了,无须另行处理。 b、如果仍然不放心,可以运行# update-grub5. 重新引导从新的内核进入6. 修改系统调用表 7. 测试实验3.3 She

12、ll编程实验(进程管理实验)1、实验目的通过编写shell程序,了解子进程的创建和父进程与子进程间的协同,获得多进程程序的编程经验。2、实验内容1设计一个简单的shell解释程序,能实现基本的bsh功能。3、实验原理 将每一条命令分子段压入argv栈。然后再子进程中调用execvp()来实现该命令的功能。4、代码(源代码清单)#include #include #include #define BUFFERSIZE 256 /最简单的shell,只是简单的执行命令调用,没有任何的其他功能 int main() char bufBUFFERSIZE,*cmd,*argv100; char inc

13、har; int n,sv,buflength; int result; buflength = 0; for(;) printf(= ); /处理过长的命令; inchar = getchar();/读取命令 while (inchar != n & buflength BUFFERSIZE) printf(Command too long,please enter again!n); buflength = 0; continue; else bufbuflength = 0; /解析命令行,分成一个个的标记 /char *strtok(char *s,char *delim) /分解字符

14、串为一组字符串。s为要分解的字符串,delim为分隔符字符串。 cmd=strtok(buf, tn); if(cmd) if(strcmp(cmd,exit)=0) exit(0); n=0; argvn+=cmd; while(argvn+=strtok(NULL, tn); if(fork()=0) execvp(cmd,argv); fprintf(stderr,sxh:%s:command not found.n,buf);/如果子进程顺利执行,这段话是不会执行的 exit(1); wait(&sv); buflength = 0; 实验内容2编写一个带有重定向和管道功能的Shell

15、1.设计思路通过fork()创建子进程,用execvp()更改子进程代码,用wait()等待子进程结束。这三个系统调用可以很好地创建多进程。另一方面,编写的Shell要实现管道功能,需要用pipe()创建管道使子进程进行通信。2.源代码清单#include #include #include #include #define BUFFERSIZE256 /具有输入输出重定向的功能 和管道功能 int main() char buf256,*buf2,*cmd,*cmd2,*argv64,*argv264,*infile,*outfile; char inchar; int n,sv,bufle

16、ngth,fd2; for(;) buflength = 0; printf(= ); inchar = getchar(); while (inchar != n & buflength BUFFERSIZE) fprintf(stderr,Command too long,please enter again!n); buflength = 0; continue; else bufbuflength = 0; /检查是否具有管道操作符 /strstr()在字符串中查找指定字符串的第一次出现,buf2指向管道符号前端的命令 buf2=strstr(buf,|); if(buf2) *buf

17、2+=0; else /否则查看是否具有重定向的操作符 infile=strstr(buf,); if(infile) *infile=0; infile=strtok(infile+1, tn); if(outfile) *outfile=0; outfile=strtok(outfile+1, tn); /解析命令行,分成一个个的标记 cmd=strtok(buf, tn); /执行管道命令 if(buf2) if(strcmp(cmd,exit)=0) exit(0); if(!cmd) fprintf(stderr,Command token error.n); exit(1); n=

18、0; /管道后端的命令 argvn+=cmd; while(argvn+=strtok(NULL, tn); /管道前端的命令 cmd2=strtok(buf2, tn); if(!cmd2) fprintf(stderr,Command token error.n); exit(1); n=0; argv2n+=cmd2; while(argv2n+=strtok(NULL, tn); pipe(fd); if(fork()=0) dup2(fd0,0); /dup2 复制文件句柄,将fd0复制到描述符0。close(fd0); close(fd1); execvp(cmd2,argv2);

19、 fprintf(stderr,* bad commandn); exit(1); else if(fork()=0) dup2(fd1,1); close(fd0);close(fd1); execvp(cmd,argv); fprintf(stderr,* bad commandn); exit(1); close(fd0); close(fd1); wait(&sv); wait(&sv); buflength = 0; /如果没有管道命令,如果有重定向就执行重定向操作,如果没有重定向就当作普通shell命令执行 else if(cmd) if(strcmp(cmd,exit)=0) e

20、xit(0); n=0; argvn+=cmd; while(argvn+=strtok(NULL, tn); if(fork()=0) int fd0=-1,fd1=-1; if(infile) fd0=open(infile,O_RDONLY); if(outfile) fd1=open(outfile,O_CREAT|O_WRONLY,0666); if(fd0!=-1) dup2(fd0,0);/dup2 复制文件句柄,将fd0复制到描述符0。 if(fd1!=-1) dup2(fd1,1);/dup2 复制文件句柄,将fd1复制到描述符1。 close(fd0); close(fd1

21、); execvp(cmd,argv); fprintf(stderr,* Bad commandn); exit(1); wait(&sv); buflength = 0; /for 实验4.1 观察实验(存储管理实验)1.实验步骤 (1)、安装GDB (2)、编写观测程序(3)、按照指令手册进行观察操作2.观测程序源代码#include #include char str50 = Hello Linux.; int main() int num = 10; while(num-) printf(%sn,str); /gcc -g -o testing testing.c3.实验结果及分析(

22、1).Gdb程序观察一个程序文件的内容和结构结果截图:(2).GDB观察程序内存映象的内容和结构(3).在Linux下,用free 和vmstat命令观察内存使用情况(4).在Linux下,查看/proc与内存管理相关的文件,并解释显示结果实验5.1 观察实验(进程通信)在Linux下,用ipcs()命令观察进程通信情况,了解Linux基本通信机制实验结果(截图):实验6.3 IO系统编程实验1、实验目的编写一个daemon进程,该进程定时执行 ps命令,然后将该命令的输出写至文件F1尾部。通过此实验,掌握Linux I/O系统相关内容。2、实验内容编写一个daemon进程,该进程定时执行 p

23、s命令,然后将该命令的输出写至文件F1尾部。3、实验原理在这个程序中,首先fork一个子程序,然后,关闭父进程,这样,新生成的子进程被交给init进程接管,并在后台执行。新生成的子进程里,使用system系统调用,将ps的输出重定向,输入到f1.txt里面。4、实验步骤编写daemon.c代码如下:#include #include int main(int argc,char* argv) int i,p; p = fork(); if(p 0) exit(0); else if(p = 0) for(i = 0; i f1.txt); else perror(Create new proc

24、ess!); return 1; 编译程序# gcc -o daemon daemon.c执行程序 # ./daemon实验7.1 代码分析(文件系统管理实验)1.实验目的了解与文件管理有关的Linux内核模块的代码结构。2.实验结果(源代码分析)A. 创建文件模块分析 5780 /*creat system call */ 5781 Creat() 5782 5783 resister *ip; 5784 extern uchar; 5785 5786 ip = namei(&uchar,1); 5787 if(ip = NULL) 5788 if(u.u_error) 5789 retur

25、n; 5790 ip = maknode(u.u_arg1&07777&(ISVTX); 5791 if (ip = NULL) 5792 return; 5793 open1(ip,FWRITE,2); 5794 else 5795 open1(ip,FWRITE,1); 5796 第 5786:“namei”( 7 5 1 8 )将一路径名变换成一个“inode”指针。“uchar”是一个过程的名字,它从用户程序数据区一个字符一个字符地取得文件路径名。 5787:一个空“inode”指针表示出了一个错,或者并没有具有给定路径名的文件存在。 5788:对于出错的各种条件,请见 UMP 的 C

26、REAT(II)。 5790:“maknode”( 7455)调用“ialloc”创建一内存“ inode”,然后对其赋初值,并使其进入适当的目录。注意,显式地清除了“粘住”位( ISVTX)。 B. 删除文件 rm 模块分析 3510 unlink() 3511 3512 resister *ip,*pp;3513 extern uchar; 3514 3515 pp = namei(&uchar,2); 3516 if (pp =NULL) 3517 return; 3518 prele(pp); 3519 ip = iset(pp -dev,u.u_dent.u_ino); 3520 i

27、f (ip = NULL) 3521 panic (*unlink iset *); 3522 if (ip -i_mode%IFMT) = IFDIR & !suser() 3523 goto out; 3524 u.u_offset1 = - DIRSIZ+2; 3525 u.ubase = &u.u_dent; 3526 u.ucount = DIRSIZE +2; 3527 u.u_dent.u_ino = 0; 3528 writei(pp); 3529 ip -i_nlink-; 3530 ip-i_flag =! IUPD; 3531 3532 out: 3533 iput(pp

28、); 3534 iput(ip); 3535 新文件作为永久文件自动进入文件目录。关闭文件不会自动地造成文件被删除。当内存“ inode”项中的“ i _ nlink”字段值为 0 并且相应文件未被打开时,将删除该文件。在创建文件时,该字段由“ maknode”赋初值为 1。系统调用“ link”( 5941 )可将其值加1,系统调用“unlink”( 3529 )则可将其值减 1。创建临时“工作文件”的程序应当在其终止前执行“ unlink”系统调用将这些文件删除。 注意,“unlink”系统调用本身并没有删除文件。当引用计数( i _ count )被减为 0 时(7350、7362),才

29、删除该文件。 为了减少在程序或系统崩溃时遗留下来的临时文件所带来的问题,程序员应当遵守下列约定: (1) 在打开临时文件后立即对其执行“ unlink”操作。 (2) 应在“tmp”目录下创建临时文件。在文件名中包括进程标识数就可构成一惟一文件名 C. 读写模块分析 5711 Read( ) 5712 5713 rdwr(FREAD); 5714 5720 Write( )5721 5722 rdwr(FWRITE); 5723 5731 rdwr(mode) 5732 5733 resister *fp,m; 5734 5735 m = mode; 5736 fp = setf(u.u_ar

30、gR0); 5737 if (fp =NILL) 5738 return; 5739 if (fp -f_flag&m =0) 5740 u.u_error = EBADF; 5741 return; 5742 5743 u.u_base = u.u_arg0; 5744 u.u_count = u.u_arg1; 5745 u.u_segflg = 0; 5746 if(fp -f_flag&FPIPE) 5747 if(m = FREAD) 5748 readp(fp);else 5749 writep(fp); 5750 else 5751 u.u_offset1 = fp -f_off

31、set1; 5752 u.u_offset0 = fp -f_offset0; 5753 if (m = FREAD) 5754 readi(fp -f_inode);else 5755 writei(fp -f_inode); 5756 dpadd(fp -f_offset,u.u_arg1 u.u_count; 5757 5758 u.u_ar0R0 = u.u_arg1 u.u_count; 5759 “read”系统调用的基本工作过程为: read ( f , b , n ) ;*用户程序* 发生陷入 2693 trap3 系统调用 5711 read() ; 5713 rdwr(FR

32、EAD); 用户进程执行系统调用激活运行在核心态的“ trap”。“trap”识别系统调用,然后通过“trap l”调用例程“read”,它又调用“rdwr”。 “rdwr”包含了很多“read”和“write”操作共用的代码。它调用“ getf”( 6 6 1 9 )将用户进程提供的文件标识变换成“file”数组中一项的地址。 注意,该系统调用的第 1 个参数是以不同于另外 2 个参数的方式传送的。 将“u.u_segflg”设置为0,这表示此操作的目的地址在用户地址空间中。在以一个 inode指针参数调用“ read i”后,将要求传送的字符数减去剩余未传输字符数(在 u.u _ coun

33、t 中),加至文件位移量中。 6221 readi 6239 lbn = lshift (u.u_offset,-9); 6248 on = u.u_offseti & 0777; 6241 n = min (512 on,u.u_count); 6250 dn = ip-i_dev; 6258 bp = bread (dn,bn); 6260 iomove (bp,on,n,B_READ); 6261 brelse (bp); “read i”将文件位移量分解成两部分:一个逻辑块号“lbn”,以及一个块内索引“on”。将要传输的字符数是下而两个值中的较小者:“u.u _ count”和块内尚

34、余字符数(在这种情况下以后还必须读其他块,此处没有进一步对此说明),还应考虑尚余留在文件中的字符数(对这种情况也未进一步说明)。 “dn”是存储在“ inode”中的设备编号,“bn”是在该设备(磁盘)上的实际块号,这是由“bmap”(6415)用“lbn”计算得到的。 对“ bread ”的调用找到所要求的磁盘块,若需要,则将其从磁盘复制到内存中。“iomove”(6364)将适当数量的字符传送至目的区,然后执行计数操作。 “read”和“ write”执行的操作有很多相似之处,两者共享很多代码。 系统调用“ read”(5711)和“write”( 5720),然后立即调用“rdwr”,它执行下列操作: 5736:将用户程序文件标识变换成指向相应文件表项的指针。 5739:检查所要求的操作(读或写)是否与文件打开时的读/写方式符合。 5743:用各参数在“u”中设置几个标准单元。 5746:从此开始对“管道”文件进行特殊处理。 5755:按读、写要求分别调用“ read i”或“write i”。 5756:更新文件位移量,使其增加实际传送的字符数,同时也将实际传送的字符数返回。

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

当前位置:首页 > 科普知识


经营许可证编号:宁ICP备18001539号-1