Linux实验指导书.doc_第1页
Linux实验指导书.doc_第2页
Linux实验指导书.doc_第3页
Linux实验指导书.doc_第4页
Linux实验指导书.doc_第5页
免费预览已结束,剩余60页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Linux实验指导书Linux实验指导书西安理工大学计算机科学与工程学院2011年6月前言近几年,随着Linux的迅速崛起,受到企业和个人的普遍欢迎和广泛关注。这主要得益于Linux的开源精神,作为免费使用和自由传播的类UNIX操作系统,它实现了UNIX的全部功能和特性,并且其性能优越、功能强大、安全稳定、移植性良好。在高校中,也掀起了Linux的学习热潮,各种形式的兴趣小组如雨后春笋般出现,对Linux表现出强烈地求知热情。但是,面对庞大而复杂的Linux操作系统,初学者往往有畏惧心理,不知从何处学起,理论知识和实践操作不能恰当地联系起来,造成对Linux系统的原理也是一知半解。针对这些问题,特编写Linux实验指导书,希望对初学者更好地理解Linux操作系统的原理有所帮助,在理论知识和实践操作之间架起一座桥梁。本文主要围绕Shell脚本、进程管理、内核模块、系统调用、内存管理和字符设备驱动程序这几个部分设计实验程序,包括十章内容,每一章节都有两个左右的程序,并详细记录了实验过程和注意事项。所有程序均在Ubuntu 10.04版本的2.6.34内核下运行通过。由于本人学习Linux时间不长,水平有限,所以,书中难免有不足之处,希望大家不吝赐教。目录1 初步使用Linux41.1 实验目的41.2 准备知识41.2.1 C语言使用简介41.2.2 文本编辑器vi使用说明41.2.3 GNU C编辑器61.3 实验基本原理及方法62 Shell程序设计92.1 实验目的92.2 实验内容92.3 实验原理及方法92.3.1 认识Shell92.3.2 Shell脚本的编写与执行92.3.3 Shell系统变量102.3.4 条件测试102.3.5 流程控制语句102.4 实验参考程序123 Makefile文件的编写153.1 实验目的153.2 实验内容153.3 实验原理及方法153.3.1 make简介153.3.2 Makefile的基本规则153.3.3 Makefile文件的一些特性163.4 实验参考程序164 内核模块编程194.1 实验目的194.2 实验内容194.3 实验原理及方法194.3.1 Linux内核结构194.3.2 Linux 2.6内核模块的Makefile文件194.3.3 内核模块的主要组成204.3.4 内核函数printk204.4 实验参考程序215 系统调用245.1 实验目的245.2 实验内容245.3 实验原理及方法245.3.1 Linux内核编译简介245.3.2 系统调用的一般过程255.4 实验参考程序256 进程管理与调度276.1 实验目的276.2 实验内容276.3 实验原理与方法276.3.1 Linux进程工作原理276.3.2 进程操作函数276.4 实验参考程序287 定时器与信号307.1 实验目的307.2 实验内容307.3 实验原理与方法307.3.1 进程间通信与信号307.3.2 定时器使用简介307.3.3 实验中涉及到的函数317.4 实验参考程序318 设备驱动程序358.1 实验目的358.2 实验内容358.3 实验原理与方法358.3.1 Linux设备驱动程序简介358.3.2 Linux驱动核心数据结构358.3.3 设备的内核操作函数378.3.4 实验中涉及到的函数388.4 实验参考程序399 内存管理459.1 实验目的459.2 实验内容459.3 实验原理与方法459.3.1 伙伴算法简介459.3.2 slab分配器原理459.3.3 实验中涉及到的函数469.4 实验参考程序4610进程同步4910.1 实验目的4910.2 实验内容4910.3 实验原理和方法4910.3.1 信号量简介4910.3.2 实验中涉及到的函数4910.4 实验参考程序501 初步使用Linux1.1 实验目的(1) 掌握在VMware Workstation 虚拟机上安装Linux操作系统的过程。(2) 熟练掌握vi 编辑器的使用。(3) 掌握GCC编辑器调试C程序的方法。(4) 设计C程序并编译。1.2 准备知识1.2.1 C语言使用简介 C语言由Bell实验室的Dennis Ritchie与1972年推出,发展迅速,受到人们的普遍欢迎,而且被公认为最优秀的结构程序设计语言之一。像Unix内核一样,Linux内核是用C语言编写的,而且包含许多软件开发工具,它们中许多都是用C和C+应用程序开发的。C语言之所以在编程领域里得到广泛支持有以下原因:(1) 语言简洁紧凑,灵活方便,运算符和数据类型丰富。(2) 程序设计自由度大,生成目标代码质量高,程序执行速度很快。(3) C语言适用范围大,可移植性好,适合于多种操作系统和机型。(4) Linux的所有版本都使用C作为系统语言。1.2.2 文本编辑器vi使用说明 vi是UNIX和Linux操作系统使用的全屏幕文本编辑器,它的用法和DOS下的文本编辑器有很大区别,初次使用时可能不大习惯,但作为系统配置的编辑器,应该熟练掌握。vim作为vi的高级版本,则可以说是一个“程序开发工具“而不是文字处理器。vi工作分为3种模式:一般模式、编辑模式和命令行模式。它们的功能分别如下:(1) 一般模式vi打开一个文件就进入一般模式,这是默认的模式。在这个模式中,可以使用方向键来移动光标,可以删除、复制和粘贴文件数据。(2) 编辑模式在一般模式中无法编辑文件内容,只有等你按下“i,I,o,O,a,A,r,R“中任何一个字母之后才会进入编辑模式,按下这些字母同时,在界面的左下方会出现INSERT或REPLACE的字样,此时才可以进行编辑。按下esc这个按键可退出编辑模式,回到一般模式。(3) 命令行模式在一般模式下输入“:、/、?“中任何一个按键,推荐使用”:“按键,就可以将光标移到最下面那一行,进入命令行模式。在此模式下,可执行查找数据、读取、保存、大量替换字符、离开vi、显示行号等操作。经过上面介绍,初学者对这三个模式可能还不是很清楚,我们可以用下图表示三种工作模式的关系: 一般模式光标的移动删除字符,删除整行复制整行,粘贴整行编辑模式以插入或替换编辑文件内容命令行模式读取、保存文件,离开vi等i,o,a(插入) r(替换)ESCESC:,/,?vi编辑器的三种工作模式vi的基本操作:(1) 使用vi进入一般模式如果要编辑文件test.txt,执行如下指令即可:rootubuntu:/# vi test.txt也可以直接输入vi,在退出时保存文件。(2) 按下如下任何一个字母进入编辑模式,开始编辑文字a,A 进入插入模式,a为从目前光标所在的下一个字符处开始插入,A为从光标所在行的最后一个字符处开始插入i,I 进入插入模式,i为从目前光标所在处插入,I为在目前所在行的第一个非空格符处开始插入o,O 进入插入模式,o为在目前光标所在的下一行处插入新的一行,O为在目前光标所在处的上一行插入新的一行r,R 进入替换模式,r只会替换光标所在的那个字符一次,R会一只替换光标所在的文字,直到按下Esc键为止(3) 退出vi如果在编辑模式,可以按Esc键进入一般模式,然后按下面任意一命令可退出vi。:W 将编辑的数据写入硬盘文件,但不退出:w! 强制写入该文件,最终能否写入,跟你对文件所拥有的权限有关:q 离开vi :q! 强制离开vi不保存修改过的文件:wq 保存后离开vi:ZZ 若文件没有更动,则不保存离开,若文件已经被更动过,则保存后离开以上是vi的一些基本操作,vi的常用命令还有许多,此处就不一一列举了。1.2.3 GNU C编辑器 GCC的全称是the GNU Compiler Collection,它是Linux操作系统上的C编译器,是整个GNU项目中的一个重要组成部分。 下面介绍GCC命令的基本用法: gcc options filename 命令行选项指定编译过程中的具体操作,GCC的编译选项超过100个,许多选项都用不到,但一些主要的选项将会频繁使用。 如果不使用任何选项编译一个C程序时,将自动生成(假设编译成功)一个名为a.out的可执行文件。例如:gcc test.c编译成功后,在当前目录下就产生一个a.out文件。若要指定输出的文件名,可以使用-o选项。例如:gcc test.c -o test这样就可以生成名为test的可执行文件,而不是a.out。接下来执行文件,这个很简单,其格式为:./可执行文件名。例如:./test1.3 实验基本原理及方法1. Linux常用指令df显示磁盘文件系统空间使用情形。du显示指定的文件或目录所占用的磁盘空间。free显示内存的使用状况。PS报告程序执行状况。tty显示终端机连接标准输入设备的文件名称。clear清屏。cd切换目录,但用户必须拥有足够的权限。chmod变更文件或目录的权限。cp复制文件或目录。date显示系统的日期和时间。find查找文件或目录,由于速度慢,不很常用,通常使用whereis和locate查找。ls列出指定目录的内容,包括文件和子目录的名称。mkdir建立目录,其权限为系统默认权限,可以使用umask查看系统默认权限。mv移动或更名现有的文件或目录。passwd更改密码。pwd显示所在目录的绝对路径名。rm删除文件或目录,删除目录时必须加上r参数。rmdir删除目录。touch创建一个空的文件或者修改文件的日期和时间。tar打包命令,使用非常广泛。2. 用vi编辑器编写C程序,使用GCC进行编译(1) Linux中标准C函数库中有许多常用函数,像字符操作、字符串操作、数学计算操作函数等,熟悉这些库函数对编程大有裨益。下面的hello.c程序用到时间操作的函数,输出当前时间。hello.c程序清单: 实验运行结果: 补充说明:struct tm结构体在time.h定义,用来表示时间。time_t是用typedef定义的long int的同义字。time_t time(time_t *t)函数功能是获取系统当前时间,采用Linux纪元表示,并返回当前时间。Linux纪元是一个整数,它记录了从格林尼治时间1970年1月1日0时起到目前所记录时间的秒数。struct tm *localtime(const time_t *timep)函数将Linux纪元时间转化为现实世界的时间,保存在tm结构体中。char *asctime(struct tm *timeptr)函数将tm结构体转化成字符串形式,并返回表示时间的字符串。(2) Fibonacci数列在现代许多领域都有直接应用,它的前两项均为1,从第三项开始,每一项都等于前两项之和,这个程序比较简单,在此不再过多说明。fibonacci.c程序清单:实验运行结果:2 Shell程序设计2.1 实验目的(1) 熟悉Shell编程,学会编写Shell脚本程序。(2) 掌握Shell编程中用到的变量、流程控制语句、常用命令与符号等。(3) 学会Shell脚本函数的使用。2.2 实验内容(1) 编写Shell脚本,搜索指定目录下的文件,学习向程序传递参数,以及如何使用文件状态测试测试文件的权限。(2) 编写包含控制语句的Shell脚本程序,掌握while循环和case结构相结合这一常用编程方法。(3) C语言中函数有着广泛应用,Shell脚本中也有函数。编写Shell脚本,实现函数调用,以及向函数中传递参数。2.3 实验原理及方法2.3.1 认识ShellShell是Linux操作系统与用户之间交流的平台,采用字符界面的控制台形式。Shell本身并不能完成操作系统与用户交互的功能,它会对用户的Shell命令进行解释,将解释的结果交付Linux内核,再由Linux内核启动相应的程序进行处理,最后将处理的结果返回给用户。其实,我们可以将Shell称作操作应用程序的接口。Shell的版本很多,我们可以在终端下输入cat /etc/shells命令进行查看,不同版本之间在命令输入和Shell编程有一定的区别,但界面是基本一致的。Linux默认的Shell是/bin/bash,这个通过echo $SHELL命令进行查看。Shell平台下可以依次输入单条命令执行,对于重复性和复杂的工作,则可以编写脚本文件实现,这相对更加方便。Shell脚本将需要执行的命令按照类似于编程的方法写到一个文件中,运行这个文件就可以一次执行多个命令,完成指定的任务。2.3.2 Shell脚本的编写与执行(1)新建或打开一个Shell脚本在终端输入命令:vi filename.shfilename为文件名。(2)执行脚本执行的方式分为两种:利用直接执行的方式来执行脚本,既可以利用“bash filename.sh”来执行,也可以利用“chmod a+x filename.sh ; ./filename.sh”来执行; 利用source来执行脚本,即通过命令“source filename.sh”来执行。区别在于前者在子进程bash内执行,后者在父进程bash内执行。2.3.3 Shell系统变量$n: $1表示第一个参数,$2表示第二个参数$#: 传递给程序的参数个数$*: 以“$1 $2 $3”形式的所有参数组成的字符串$: 以“$1”“$2”“$3”形式的所有参数组成的字符串$?: 前一条命令执行后的返回值$-: 在Shell启动或使用set命令时提供选项$: 当前Shell的进程号$!: 上一个子进程的进程号$0: 当前运行的Shell名称2.3.4 条件测试通过判断条件的成立与否,执行不同的命令,以便控制程序运行的方向,完成指定的任务。其语法格式为: par1 判断符号 par2 或 判断符号 par 注意:括号两侧各有一个空格,且返回真用0表示,非0表示假(这与C语言相反)。条件测试分为:文件状态测试、多重条件判定、字符串测试、数值测试。下面简单列举几个说明,其它不过多赘述,有兴趣的同学可下去自学。-d pathname: 判断路径是否存在且为目录,若路径不存在返回假 -r filename: 判断该文件名是否存在且具有“可读”权限,若不成立返回假 -w filename: 判断该文件名是否存在且具有“可写”权限,若不成立返回假-x filename: 判断该文件名是否存在且具有“可执行”权限,若不成立返回假 par1 a par2: 两个条件同时成立,即逻辑与 par1 o par2: 任何一个条件成立,即逻辑或 !par: 取反,即逻辑非 str1 = str2: 判断两个字符串是否相等 str1 != str2: 判断两个字符串是否不等 val1 -eq val2: 判断两个数值是否相等 val1 -lt val2: 判断val1是否小于val2 val1 -gt val2: 判断val1是否大于val2 2.3.5 流程控制语句(1) if语句if语句的功能是:当条件判断成立时,就执行某些指令,否则执行另外一些指令。其具体语法格式如下: if 条件判断式 ; then else fi条件判断式的判断方法与前面的介绍相同,对于多重条件判断除了前面介绍的“-a”和“-o”外,还可以把中括号用&和|隔开,这和C语言是一致的,例如: “$str1” = “Y” a “$str1” = “y” ,可以替换为 “$str1” = “Y” & “$str1” = “y” 还有一点需要注意,条件判断式中判断两个字符串、变量或数字相等,用“=”和“=”一样,所以我们将上式写成 “$str1” = ”Y” & “$str2” = “y” 也对。(2) case语句case语句根据指定的字符串的匹配情况,执行不同的程序分支,其具体语法格式如下:case $par in “$par1”) ; “$par2”) ; *) ;esac这里除了语法格式外,其执行流程和C语言中的case语句大体相同。(3) while语句while循环被称为“当型循环”,即当条件满足时进入循环体,直到条件不满足时退出循环体,其具体语法格式如下:while 条件判断式 do done 还有一种until循环,与while循环恰好相反,被称为“直到型循环”,即当条件不满足时进入循环体,直到条件满足时退出循环体,其具体语法格式如下: until 条件判断式 do done(4) for语句while和until循环必须要符合某个条件,而for语句开始就知道要循环的次数,使用一个变量循环遍历提供的字符串集合中的每一个字符串,遍历结束后退出循环,循环的次数就是字符串集合中的字符串个数,其具体语法格式如下:for var in str1 str2 do done这里$var是循环变量,“str1 str2 ”是字符串集合,第一次循环时,$var的值为str1,第二次$var的值为str2,依次执行下去。(5) Shell函数Shell中函数可以被看做一个小的脚本程序,在当前脚本中调用。其具体语法格式如下:function fname() 这里fname是函数名,也是自定义的执行命令的名称。由于Shell脚本的执行方式是自上而下、从左到右,因此function一般设置在程序的最前面。另外需要注意,function也拥有内置变量,函数名用$0表示,后面接的变量用$1、$2 表示,因此可以像函数传递参数,这要与当前脚本参数相区别。2.4 实验参考程序(1) 将指定目录通过参数传递给脚本,搜索目录下的文件,用最常见的ifthen条件判断式测试所有文件的权限。search.sh程序清单:实验运行结果:(2) Shell脚本程序能和用户进行交互。下面的grade.sh程序实现对用户输入的分数进行分级,并输出该分数的等级。grade.sh程序清单:实验运行结果:(3) Shell脚本中的函数可以简化程序代码,而且可以做成模块,利于结构化程序设计。如果某些代码在Shell脚本中重复时,就要想到function,这点非常重要。下面的func.sh程序调用两个函数实现数学的加减运算,理解该程序函数调用和函数参数传递的方式,这里与C语言有所区别。func.sh程序清单: 实验运行结果:3 Makefile文件的编写3.1 实验目的(1) 熟悉掌握gcc编译器的使用。(2) 理解makefile的基本语法和变量。(3) 掌握make的工作原理即makefile文件的编写。3.2 实验内容(1) 编写几个具有相互依赖关系的C语言程序。(2) 为自己的程序编写Makefile文件。3.3 实验原理及方法3.3.1 make简介如果编写一个简单的源程序,使用一条命令即可编译出可执行文件,但编写一个复杂的工程软件,其编译链接就不是简单的一两条命令,可能需要执行几十条甚至上百条命令,如果源文件发生改变,还得从头再来一遍,可想而知,这个过程相当繁琐。与Windows下的Visual Studio中管理文件的工程类似,Linux中的make帮助我们实现这一功能。make通过Makefile这个脚本文件实现工程的管理。make采用增量编译,简化编译时所需要执行的命令,而且,如果我们修改过某个源文件,则make会主动分析哪个源文件与相依赖的目标文件需要更新,而其它文件不需要重新编译,这样会大大减少编译时间,节省宝贵的CPU时间。3.3.2 Makefile的基本规则Makefile是一个脚本文件,描述软件之间的依赖关系,以及生成可执行文件进行编译链接的方法。Makefile的基本规则如下:变量定义目标:依赖文件列表 命令目标:依赖文件列表 命令这里的目标就是我们想要建立的信息,以按键开头的那一行命令建立可执行文件,注意这里必须是要以按键开始。3.3.3 Makefile文件的一些特性(1) 变量Makefile脚本中可以定义变量,减少重复的数据,方便操作。变量的定义方法如下:VAR = STR习惯上变量使用大写字母,通过$VAR或$(VAR)方式使用。(2) 伪目标文件如果我们想使用make仅执行一条命令,并不需要生成什么目标文件,那么可以考虑使用伪目标文件。伪目标文件需要使用.PHONY声明,调用时必须显示调用,且不能和文件名重名。(3) make命令简介make命令的具体语法格式如下:make 选项 目标选项:-f FILE: 读取FILE作为一个Makefile-n: 不要实际运行任何命令,仅仅输出它们-B: 重新编译所有目标文件-s: 运行时不显示任何输出-p: 输出Makefile文件的所有信息3.4 实验参考程序本次实验程序包括4个源码文件,分别是main.c、hello.c、str_len.c和str_cat.c,这4个文件的目的是:main.c:让用户输入姓名和字符串,调用其它3个子程序;hello.c:输出一些问候信息;str_len.c:计算用户输入的字符串的长度;str_cat.c:将用户输入的两个字符串连接起来。main.c程序清单:hello.c程序清单:str_len.c程序清单:str_cat.c程序清单:Makefile文件脚本程序清单:实验运行过程比较简单,在实验程序所在目录下依次输入以下命令:make和./main即可。实验运行结果:4 内核模块编程4.1 实验目的(1) 掌握内核模块的组成部分。(2) 理解Linux内核的模块机制。(3) 熟练掌握内核模块的编译、安装和卸载的方法。(4) 熟悉Linux内核模块的编写方法与模块Makefile的书写格式。4.2 实验内容编写两个内核模块,使得一个模块可以调用另一个模块的函数,这两个内核模块便具有相互依赖关系。掌握向Linux内核模块传递参数的方法,在模块安装和卸载时,输出一些必要的提示信息。4.3 实验原理及方法4.3.1 Linux内核结构操作系统一般采用两种体系结构:单内核和微内核。对于单内核体系结构的操作系统来说,其内核一般是一个很大的进程。它的内部又被分为若干模块,在运行时,它是一个独立的二进制映像。其模块间通过直接调用其它模块的函数实现通信,而不是消息传递。对于微内核,大部分内核都作为独立的进程在特权状态下运行,它们通过消息传递进行通信。微内核最基本的思想就是要尽量的小。通常微内核只包含了进程调度、内存管理和进程间通信这几个基本的功能,使得系统灵活性高,易于维护,易于移植。Linux操作系统的内核是单体的,也就是说,整个Linux内核是一个非常大的可执行文件。而且Linux内核引入了模块机制,在不需要对内核重新编译的情况下,动态地加载和卸载模块,弥补了单内核可扩展性和可维护性比较差的缺陷。4.3.2 Linux 2.6内核模块的Makefile文件在Linux 2.6 内核中,编译过程会首先到内核源码目录下读取顶层的Makefile文件,然后返回模块源码所在目录,最后生成后缀为.ko的内核模块文件。Linux 2.6内核模块的Makefile模板如下: 上面第一行中的KERNELRELEASE是在内核源码顶层Makefile中定义的一个变量,在第一次执行此Makefile时,由于KERNELRELEASE还未定义,所以ifneq判断为假,执行else之后的内容,设置KDIR和PWD变量。KDIR是定位到内核代码树,如果查看该目录就会发现,build是一个符号链接,指向内核代码树,而PWD表示当前目录。这两个变量所在行中的$(shell uname -r)和$(shell pwd)是shell命令,分别表示Linux操作系统的内核版本号和当前目录。如果make的目标是clean,则会删除当前目录下各个生成文件后结束。如果make的目标是default,-C $(KDIR)指明跳转到内核源码目录下执行那里的Makefile,M=$(PWD)表明返回到当前目录再次执行当前的Makefile,即第二次调用make。此时$(KERNELRELEASE)已被定义,则ifneq判断成功,第二行代码被执行,这行代码指明目标模块module.ko依赖于目标文件module.o。4.3.3 内核模块的主要组成Linux内核模块主要由以下几部分构成:(1)内核模块的初始化与退出:Linux内核模块通过两个宏module_init()和module_exit()调用初始化与退出函数,这两个函数是必须的。用命令insmod加载和rmmod卸载模块时,会分别调用这两个函数。当然也可以直接使用命令modprobe处理模块的加载与删除。(2)模块许可证声明:Linux内核通过MODULE_LICENSE宏声明此模块的许可证,如果不声明,在动态加载模块时,会收到内核被污染的警告。内核接受的许可证很多,最常用的是GPL和Dual BSD/GPL。(3)模块参数:在加载模块时,可以向模块传递参数,模块参数的定义通过module_param(name, type, perm)完成,其中name为参数名,type为参数类型,perm指定了模块在sysfs文件系统下对应的文件权限,一般设置为S_IRUGO,表示任何人可以读。(4)模块导出符号表:只有被内核模块导出的函数其它模块才可以使用,而未导出的模块内部函数其它模块无法调用。内核符号的导出使用语句EXPORT_SYMBOL()完成,而引用模块需要使用extern声明外部符号。(5)模块作者、模块版本和模块功能信息的声明,这部分可选。4.3.4 内核函数printk用户空间里经常使用printf函数来输出信息,而内核使用printk函数输出信息,因为内核模式下不存在libc库。printf接口和printk基本相似,只不过前者运行在用户态,后者运行在内核态,内核模式下编程存在一些限制:不能使用浮点运算,不要让内核进程长时间等待,尽可能保持代码清洁。printk的语法格式如下:printk(记录级别 “输出信息”);内核总共有8个记录等级,实验中用到了KERN_INFO,表示非正式的消息、提示信息,如驱动程序启动,打印硬件信息。内核通过对这个记录等级和当前终端的记录等级console_loglevel进行比较,决定是否向终端打印输出。如果是在虚拟机上运行的Linux操作系统,终端是不会有printk的输出信息,我们可以通过命令tail -6 /var/log/messages进行查看,也可以使用命令dmesg | tail -6查看printk的输出信息。4.4 实验参考程序本次实验设计两个模块,分别是meodule和module1模块,module1模块会调用module模块中的str_len函数对输入的字符串参数计算串长,函数比较简单,希望通过这个实验掌握模块编程的基本过程。运行命令mkdir module和mkdir module1,建立两个目录module和module1。在module目录下编写module.c源文件和对应的Makefile文件,在module1目录下编写module1.c源文件和对应的Makefile文件。module.c程序清单:对应的Makefike脚本文件:module1.c程序清单:此模块对应的Makefile文件脚本只要将前面的Makefile文件第二行中的module改为module1即可,其它地方不变。接下来编译模块,进入module目录,执行make命令,运行结果如下图:进入module1目录,将module目录中的Module.symvers复制到module1目录下后,执行make编译module1.c,具体原因在后面注意事项中介绍,接下来的过程与上面相同。然后安装模块,在root权限下,分别进入module和module1目录,执行命令insmod module.ko和insmod module1.ko string=xaut安装模块。模块成功安装后,使用lsmod | grep module命令进行查看,结果如下:卸载模块,须在root权限下执行以下命令:rmmod module1和rmmod module。查看系统信息,即模块中printk输出地一些信息,执行命令tail -6 /var/log/messages后结果如下:注意事项:(1)如果是Linux kernel 2.6.26版本及其以后的内核版本,在module1目录下执行make命令会出现警告信息:如果继续加载module1.ko模块,会输出如下提示信息:提示信息说明符号str_len对于模块module1来说是不可见的,原因是:生成module1.ko时,无法获得str_len的信息。解决办法便是把module目录下的Module.symvers文件复制到module1目录下。(2)卸载模块时必须先卸载module1模块后再卸载module模块,这是因为module1模块使用module模块中的str_len函数,二者有依赖关系。否则会输出如下提示不能卸载:5 系统调用5.1 实验目的(1) 掌握内核编译的方法。(2) 理解Linux系统调用机制的实现原理。(3) 掌握向Linux系统增加自己的系统调用的方法。5.2 实验内容向Linux操作系统增加一个名为mytest的系统调用,其功能是根据输入的一个整数,计算从0开始到输入的这个数的累加和。5.3 实验原理及方法5.3.1 Linux内核编译简介(1) 内核源码下载Linux官方内核源码可以从/pub/linux/kernel/v2.6/站点下载,将下载的linux-2.6.34.tar.bz2 内核源码包放到Linux系统目录文件夹/usr/src/中。(2) 解压内核进入目录/usr/src/,使用命令tar jxv f linux-2.6.34.tar.bz2解压源码包,发现多出一个linux-2.6.34的文件夹。(3) 一些准备工作进入linux-2.6.34目录后,若是第一次编译内核执行命令make mrproper,否则执行命令make clean即可,删除编译过程生成的中间文件。通过命令cp /boot/config-uname -r-generic ./.config取得旧编译选项,初学者编译内核可以先选择默认编译选项,如果有需要,可以用make menuconfig来重新设定编译选项。挑选内核选项的过程相当费时,最后还有可能编译出错。(4) 编译内核与内核模块此过程需要依次执行3个命令,先执行命令make clean清除临时文件,再执行命令make bzImage编译内核,最后执行命令make modules编译模块。make bzImage执行后,最终结果如下:(5) 安装模块执行命令make modules_install安装模块,结果会在/lib/modules下新建起该内核的相关模块。(6) 安装新内核执行命令mkinitramfs o /boot/initrd.img-2.6.34 /lib/modules/2.6.34生成内核镜像文件。修改/boot/grub/grub.cfg文件,参考原来的grub引导项,复制一个引导向,只需要修改几处就可以。 重新启动系统就可进入新内核,使用命令uname r查看内核版本。5.3.2 系统调用的一般过程通知内核的机制是靠软中断来实现,通过引发一个异常来促使系统切换到内核态执行系统调用处理程序。在x86体系结构的计算机中,系统调用由软中断int $0x80来实现,这条指令会触发一个异常导致系统切换到内核态并执行第128号异常处理程序,而该程序便是名为system_call的系统调用处理程序。进入系统内核后,使用system_call_table和eax中包含的系统调用号来执行真正的系统调用。从系统调用中返回后,最终执行syscall_exit,并调用resume_userspace返回用户空间。添加一个系统调用,通常需要4个步骤:(1) 添加系统调用号。(2) 更新系统调用表。(3) 更新头文件。(4) 添加新的系统调用服务函数。5.4 实验参考程序下面我们添加一个mytest的系统调用:(1) 添加系统调用表将.long sys_mytest添加到/usr/src/linux-2.6.34/arch/x86/kernel/目录下syscall_table_32.S文件的最后一行。(2) 添加系统调用号将对应的系统调用号添加到/usr/src/ linux-2.6.34/arch/x86/include/asm/目录下unistd_32.h文件中。如下图所示:(3) 添加系统调用服务函数将下面的代码添加到/usr/src/linux-2.6.34/arch/x86/kernel/目录下sys_i386_32.c文件的最后一行。(4) 编译内核按照上面5.3.1的介绍重新编译内核,因为之前已经编译过一次内核,所以从第四步开始即可,第六步的grub.cfg文件也不用修改。(5) 重新启动后进入新内核(6) 编写测试程序编写测试程序syscall_test.c,程序清单如下:(7) 实验运行结果执行命令gcc syscall_test.c o syscall_test编译源文件,生成名为syscall_test的可执行文件,再输入./syscall_test运行程序,结果如下:6 进程管理与调度6.1 实验目的(1) 了解Linux进程工作的原理。(2) 掌握获取与设置进程管理与调度的相关信息的方法。(3) 熟悉多进程编程。6.2 实验内容(1) 编写程序,使用系统调用fork()创建子进程。(2) 编写程序,同样使用系统调用fork()创建子进程,并获取子进程的相关信息。6.3 实验原理与方法6.3.1 Linux进程工作原理在Linux操作系统中,进程是一个独立拥有资源和独立调度的基本单位。进程是一段运行的有生命力的程序,是一个动态的概念,而程序是一个静态的概念。Linux进程有五种状态,进程描述符中的state域描述了进程的当前状态,系统中的每个进程必然处于这五种状态之一,这五种状态分别为运行、可中断、不可中断、僵死、停止。Linux的进程在宏观上是并行的,对单核cpu的计算机来说,进程在微观上是串行的,而且各个进程是采用基于优先级的抢占方式运行。Linux系统采用树形结构组织所有进程,通过进程号pid来标识不同的进程。6.3.2 进程操作函数(1) fork函数原型:pid_t fork(void)相关头文件:#include 该函数通过完全复制父进程的方式创建子进程,返回值有三种:父进程则返回新建子进程的进程号;子进程则返回0;若调用失败则返回-1。(2) getpid函数原型:pid_t getpid(void)相关头文件:#include 该函数取得当前进程的进程号,并返回该进程号。(3) getpriority函数原型:int getpriority(int which,int who)相关头文件:#include ,#include 该函数获取指定进程、进程组或用户的优先级,并返回该优先级数。参数which可取三个值:PRIO_PROCESS、PRIO_PGRP或PRIO_USER。(4) wait函数原型:pid_t wait(int *status)相关头文件:#include ,#include 该函数暂停当前进程的执行,等待子进程的中断或结束。(5) nice函数原型:int nice(int inc)相关头文件:#include Linux中进程运行的优先级分为-2019共40个级别,数值越小优先级越高,数值越大优先级越低。nice函数将当前进程运行的优先级增加指定值后,用新的优先级运行该进程。参数指定优先级增加的值。6.4 实验参考程序(1) 实验程序使用系统调用fork()创建两个子进程。程序运行时,系统中有两个子进程和一个父进程活动,父进程输出“Im parent process ! ”信息,两个子进程分别输出“Im child process p1 !”和“Im child process p2 !”信息。运行程序,观察实验输出结果,分析其原因。fork.c程序清单: 实验运行结果: 注意:实验结果不唯一,三条输出信息的顺序是随机的。(2) 使用系统调用fork()创建子进程,可以获取子进程的进程号和优先级,还可以修改其优先级。fork_nice.c程序清单: 实验运行结果:7 定时器与信号7.1 实验目的(1) 熟悉Linux信号操作的相关函数。(2) 通过实验加深对定时器的理解。(3) 掌握设计定时器的方法。7.2 实验内容(1) 编写程序,使用系统调用fork()创建子进程,通过软中断实现进程之间的通信,并输出相关信息。(2) 注册一个定时器,延迟一段时间后执行,输出一些提示信息。7.3 实验原理与方法7.3.1 进程间通信与信号进程间通信实现两个或多个进程之间的信息交换,形式上分为即时通信和非即时通信。要求信息发送给对方后立即被对方所知晓,属于即时通信,相比较而言,非即时通信没有这个要求。信号是实现即时通信的主要方式。信号的工作原理和中断相似,二者均采用异步通信方式,当检测到信号或中断请求时,都暂停正在执行的程序而转去执行相应的处理程序,处理完毕后从原来的断点继续执行,也可以对中断或信号进行屏蔽。但二者又有一些区别,信号处理程序运行在用户态下,而且信号没有优先级,其响应也没有中断响应及时。信号机制通过系统调用kill()发送信号,接收信号的进程通过signal()预置信号的处理方式,这是信号机制中用到的两个最重要的函数。7.3.2 定时器使用简介定时器是管理内核时间的基础,可用于推后执行某些代码。定时器使用简单,运行次数不受限制,在内核中的应用的非常普遍。定时器用结构time_list表示,在文件中定义。struct timer_list struct list_head entry; /定时器链表的入口 unsigned long expires; /以jiffies为单位的定时值 spinlock_t lock; /保护定时器的锁 void (*function) (unsigned long); /定时器处理函数 unsigned long data; /传给处理函数的长整形参数 struct tvec_t_base_s *base; /定时器内部值,用户不要使用;以下是创建一个定时器的步骤:(1) 定义定时器:struct timer_list my_timer;(2) 初始化定时器:init_timer(&my_timer);(3) 赋值:my_timer.expires = jiffies + delay; /定时器超时节拍数 my_timer.data = 0; /给定时器处理函数传入0值 my_t

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论