操作系统课程设计报告.docx
《操作系统课程设计报告.docx》由会员分享,可在线阅读,更多相关《操作系统课程设计报告.docx(19页珍藏版)》请在冰豆网上搜索。
操作系统课程设计报告
课程设计报告
课程名称:
操作系统原理
院系:
计算机科学与技术
专业班级:
CS140______
学号:
U201414_____
姓名:
_________
指导教师:
_________
完成时间:
2017年3月11日_
1实验目的
·掌握Linux操作系统的使用方法;
·了解Linux系统内核代码结构;
·掌握实例操作系统的实现方法;
2实验环境
本次课程设计采用的操作系统环境是windows10、Ubuntu双系统,Ubuntu系统版本号为,内核版本号为linux;前两个实验在当前Ubuntu环境下完成,后两个实验在win10下虚拟机VirtualBox的Ubuntu(内核为)中完成。
3实验内容
3.1实验一
要求熟悉和理解Linux下的编程环境。
(1)编写一个C程序,用fread、fwrite等库函数实现文件拷贝功能。
(2)编写一个C程序,使用基于文本的终端图形编程库(curses)或图形界面(QT/GTK),分窗口显示三个并发进程的运行(一个窗口实时显示当前时间,一个窗口实时监测CPU的利用率,一个窗口做1到100的累加求和,刷新周期分别为1秒,2秒和3秒)。
3.2实验二
要求掌握添加系统调用的方法,采用编译内核方法,添加一个新的系统调用,实现文件拷贝的功能,另外编写一个应用程序,测试新增加的系统调用。
3.3实验三
掌握增加设备驱动程序的方法。
采用模块方法,添加一个新的字符设备驱动程序,实现打开/关闭,读/写等基本操作。
另外编写一个应用程序,测试新添加的驱动程序。
3.4实验四
要求理解和分析/proc文件。
(1)了解/proc文件的特点和使用方法;
(2)监控系统状态,显示系统部件的使用状态;
(3)用图形界面实现系统监控状态,包括CPU和内存利用率、所有进程信息等(可自己补充、添加其他功能);
3.5实验五(选做)
要求理解和掌握文件系统的设计方法(选做)。
设计、实现一个模拟的文件系统。
包括文件/目录创建/删除,目录显示等基本功能(可自行扩充文件读/写、用户登录、权限控制、读写保护等其他功能)。
4设计与实现
4.1实验一
4.1.1实验要求
要求熟悉和理解Linux下的编程环境。
4.1.2实验设计及调试
(1)编写一个C程序,其内容为实现文件拷贝的功能。
这个实验的思路是声明两个文件指针*fp_read和*fp_write,前者用来打开要读的文件,后者打开要写的文件,再创建一个1000个字节大小的缓冲区buff[],然后调用fread将内容从文件1读到buff里,再调用fwrite把内容从buff写到文件2中。
这个实验重点要掌握fread和fwrite的使用方法,注意它们的参数和返回值。
代码见附件中源码。
实验结果如下图:
图运行之前图
运行./lab1_1后结果如下图:
图运行之后图
由上图可见成功拷贝至
(2)编写一个C程序,本次实验使用的是图形界面GTK,分窗口显示三个并发进程的运行(一个窗口实时显示当前时间,一个窗口实时监测CPU的利用率,一个窗口做1到100的累加求和,刷新周期分别为1秒,2秒和3秒)。
这个实验要用到gtk,首先要配置gtk,在终端中输入:
sudoapt-getinstall
涉及到3个进程的并发,所以要调用函数fork来创建3个进程。
我的思路是在这3个进程中分别创建一个线程,去完成相应的功能:
显示当前时间,监测CPU利用率,做累加求和。
分别通过函数voidhavetime()、voidcpu_usage()、voidadd()实现,在main函数里,初步画出3个进程相应的界面。
具体的是调用gtk_window_new()函数创建一个窗口、gtk_window_set_title()设置窗口标题、gtk_window_set_position设置窗口在屏幕的位置、gtk_label_new()创建一个标签用来显示文本、gtk_container_add()把标签添加到窗口中、gtk_widget_show_all()来展示需要展示的控件。
例如创建第一个线程:
g_thread_create((GThreadFunc)havetime,NULL,FALSE,NULL);
通过在线程havetime()中实时更新标签label的内容,然后在main()中创建的窗口中展示来完成所要求的功能。
进程2和3所要求的功能也是通过这种方法实现。
注意用到gtk的编译命令与以往不同,为:
gcc-olab1_2`pkg-config--cflags--libsgtk+`
代码见附件中的源码,实验结果如下图:
图运行结果图
小插曲:
在调用sprintf(s,"CPU利用率为%f%%",usage)想把利用率的“%”拷进缓冲区s后打印出来时,一个百分号是不能够打印出来的,要写两个%,如想要打印两个%,则要写4个%,以此类推。
4.2实验二
4.2.1实验要求
要求掌握添加系统调用的方法,采用编译内核方法,添加一个新的系统调用,实现文件拷贝的功能,另外编写一个应用程序,测试新增加的系统调用。
4.2.2实验设计及调试
下载一个内核下载在/usr/src/目录下解压(用超级用户权限),
(1)编写新的系统调用程序
用户空间所使用的open、read、write、close函数此时对应内核函数为sys_open、sys_read、sys_write、sys_close。
首先通过sys_open()打开源文件和目标文件,分别返回文件描述符source和dest,然后把当前的用户地址范围保存在fs,再把当前内存访问地址范围设置为内核的内存地址访问范围,再通过sys_read()把源文件内容写到buf,再用sys_write()把buf内容写到dest,接着用sys_close()来关闭文件,最后再把内存访问地址范围设置为用户的。
保存fs是避免使用的缓冲区超过了用户空间的地址范围而报错。
把自己写的这个系统调用程序添加至/usr/src/目录下的最后。
(2)添加系统调用号
在/usr/src/目录下修改文件,添加一个自己的调用程序的系统调用号,我的之前用到了325好,所以添加326号,如下:
326commonmysyscallsys_mysyscall
(3)添加系统调用程序的声明
在/usr/src/目录下的最后加上自己添加的系统调用程序的声明如下:
asmlinkageintsys_mysyscall(char*sourceFile,char*destFile);
(4)编译、安装内核
在/usr/src/目录下对内核选项进行配置:
sudomakemenuconfig
图内核配置图
选择save后退出
接下来就是漫长的编译内核了(4个线程跑会快一些):
sudomake-j4
大概1个小时左右编译完毕,再安装内核:
sudomakemodules_install
lab2后如下图:
图运行之后的图
可见系统调用成功。
4.3实验三
4.3.1实验要求
掌握增加设备驱动程序的方法。
采用模块方法,添加一个新的字符设备驱动程序,实现打开/关闭,读/写等基本操作。
另外编写一个应用程序,测试新添加的驱动程序。
4.3.2实验设计及调试
(1)添加设备驱动原理:
linux设备一般分为:
字符设备、块设备和网络设备。
驱动程序运行在内核空间,应用程序通常通过文件系统接口函数访问/dev目录下的设备文件来访问驱动程序。
编写设备驱动程序的主要工作就是编写file_operations子函数,这次实验主要完成的就是file-operations数据结构中的.open\.release\.read\.write4个模块,file_operations结构的每个域都对应一个系统调用。
用户进程利用系统调用在对设备文件进行诸如read/write等操作时,系统调用通过设备文件的主设备号找到相应的设备驱动程序,然后读取该数据结构相应的函数指针,接着把控制权交给该函数。
(2)编写Makefile文件
Makefile文件用于编译设备驱动程序,其内容如下:
iifeq($(KERNELRELEASE),)
KERNELDIR=/lib/modules/$(shelluname-r)/build
PWD:
=$(shellpwd)
modules:
$(MAKE)-C$(KERNELDIR)M=$(PWD)modules
modules_install:
$(MAKE)-C$(KERNELDIR)M=$(PWD)modules_install
clean:
rm-rf*.o*~core.depend.*.cmd*.ko*..tmp_versions
.PHONY:
modulesmodules_installclean
else
obj-m:
=
endif
(3)编写设备功能函数
编写设备驱动程序的主要工作就是编写子功能函数。
open()函数用来打开一个设备,在该函数中可以对设备进行初始化。
如果这个函数被赋值NULL,那么设备打开永远成功,并不会对设备产生影响。
release()函数用来释放open()函数中申请的资源,并在文件引用计数为0时,被系统调用。
其对应应用程序的close()方法,但并不是每一次调用close()方法,都会触发release()函数,只有在打开的所有设备文件都释放后,该函数才会被调用。
read()函数用来从设备中获取数据,成功时返回读取的字节数,失败时返回一个负的错误码。
write()函数用来写数据到设备中。
成功时该函数返回写入的字节数。
详细实现见附件中源码。
(4)设备驱动程序安装
1make,调用Makefile编译设备驱动程序
图make图
编译成功,生成文件
2sudoinsmod挂载模块,再查看设备的主设备号:
cat/proc/devices
图主设备号的图
可见系统为mydev生成的主设备号为248
3sudo/dev/mydevc2480
mydev是设备文件的名字,“c”是指创建的是字符设备文件,248是主设备号,0是从设备号。
图生成设备文件图
可见生成了正确的设备文件mydev
(5)测试驱动程序
测试程序实现的是先从设备中读出里面初始的字符串U3,再把一个字符串写进去,然后再读出来,测试程序详见附件源码,测试实验结果如下图:
先运行命令执行程序:
sudo./test
图结果图
可见打开、读、写均正确。
最后执行sudormmodmydev来删除模块
sudorm/dev/mydev来删除设备文件
4.4实验四
要求理解和分析/proc文件。
4.4.1实验要求
了解/proc文件的特点和使用方法;监控系统状态,显示系统部件的使用状态;用图形界面实现系统监控状态,包括CPU和内存利用率、所有进程信息等(可自己补充、添加其他功能)。
4.4.2实验设计及调试
这个实验主要是对/proc文件的理解和对gtk的熟练运用。
我用gtk里的笔记本构件画了3个页面,分别为pageone、pagetwo、pagethree。
pageone:
显示CPU利用率
计算和显示CPU直接用到的实验一第二个部分的显示CPU利用率部分,不同的是这儿用到了笔记本控件,要把“pageone”作为一个button加到notebook上,还要把算出来的CPU利用率作为一个标签内容加到notebook上,即:
hbox
scrolled_window
vbox
frame
button
clist
GtkWidget*button4=gtk_label_new("Pageone");
label1=gtk_label_new("begin");lab4
实验结果如下图、、:
图第一个页面图
图第二个页面图
图第三个页面图
5心得体会
本次课程设计,第一个题目第一问很简单,因为之前在实验中写过文件拷贝的程序,所以很快就顺利实现了,要注意fopen、fread、fwrite几个函数的用法,第二问刚开始不知怎么做,主要是因为之前没接触过gtk这种画界面的环境,在网上查阅相关资料后发现套路都是一样的,个人觉得把握住gtk中控件的概念,实现简单的界面都还是比较简单的,除了gtk,在CPU利用率的计算上还卡了一段时间,主要是没弄清到底应该怎么计算,查了大量资料后找到一种比较简单的计算方法去实现,结果也很准确;第二题和第三题是同一类型,都是需要对内核、系统调用、设备驱动文件有很好的理解才能很快做出来,自己还掌握得不是很好,所以也花了不少的时间去查资料、实现要求的功能,但现在回过头来看收获很大,对课上所学的部分内容有了更加深刻的理解,对linux系统调用和设备文件有了更深的认识;第四题确实是花的时间最多的,因为不仅涉及到复杂的gtk运用,还包括对/proc文件的理解,这两方面都是查了大量资料后才一点点完成的,时间花了,确实也有了成效,看到自己画的界面和读出的进程、CPU信息,成就感瞬间爆棚,但这还远远不够,相信以后学习工作中还会遇到更加困难的类似的问题,这次课设只是打下了个小小的基础,任重道远!
总之,这次课设受益匪浅。
6附录(源码)
实验一:
第一题:
#include<>
#definebuffer_size1000
intmain(intargc,char*argv[])
{
if(argc!
=3)ead=my_read,
.write=my_write,
.open=my_open,
.release=my_release
};
intinit_module(){
intret;
ret=register_chrdev(0,devname,&pstruct);
if(ret<0){
printk("registfailure\n");
return-1;
}
else{
printk("thedevicehasbeenregistered!
\n");
device_num=ret;
printk("<1>thevirtualdevice'smajornumber%d.\n",device_num);
printk("<1>Oryoucanseeitbyusing\n");
printk("<1>------more/proc/devices-------\n");
printk("<1>Totalktothedriver,createadevfilewith\n");
printk("<1>------'mknod/dev/myDevicec%d0'-------\n",device_num);
printk("<1>Use\"rmmode\"toremovethemodule\n");
return0;
}
}
voidcleanup_module(){
unregister_chrdev(device_num,devname);
printk("unregisteritsuccess\n");
}
staticintmy_open(structinode*inode,structfile*file){
printk("<1>maindevice:
%d\n",MAJOR(inode->i_rdev));
printk("<1>slavedevice:
%d\n",MINOR(inode->i_rdev));
printk("<1>%dtimestocallthedevice\n",++counter);
try_module_get(THIS_MODULE);
return0;
}
staticintmy_release(structinode*inode,structfile*file){
printk("Devicereleased!
\n");
module_put(THIS_MODULE);
return0;
}
staticssize_tmy_write(structfile*file,constchar__user*user,size_tt,loff_t*f){
if(copy_from_user(message,user,sizeof(message)))
{
return-EFAULT;
}
returnsizeof(message);
}
staticssize_tmy_read(structfile*file,char__user*user,size_tt,loff_t*f){
if(copy_to_user(user,message,sizeof(message)))
{
return-EFAULT;
}
returnsizeof(message);
}
:
#include
#include
#include<>
#include<>
#include<>
#include<>
#include<>
#defineMAX_SIZE1024
intmain(void)
{
intfd;
charbuf[MAX_SIZE];
charget[MAX_SIZE];
chardevName[20],dir[50]="/dev/";
system("ls/dev/");
printf("Pleaseinputthedevice'snameyouwannatouse:
");
gets(devName);
strcat(dir,devName);
fd=open(dir,O_RDWR|O_NONBLOCK);
if(fd!
=-1)
{
read(fd,buf,sizeof(buf));
printf("Thedevicewasinitedwithastring:
%s\n",buf);
/*测试写*/
printf("Pleaseinputastring:
\n");
gets(get);
write(fd,get,sizeof(get));
/*测试读*/
read(fd,buf,sizeof(buf));
system("dmesg");
printf("\nThestringinthedevicenowis:
%s\n",buf);
close(fd);
return0;
}
else
{
printf("Deviceopenfailed\n");
return-1;
}
}
makefile:
ifeq($(KERNELRELEASE),)
KERNELDIR=/lib/modules/$(shelluname-r)/build
PWD:
=$(shellpwd)
modules:
$(MAKE)-C$(KERNELDIR)M=$(PWD)modules
modules_install:
$(MAKE)-C$(KERNELDIR)M=$(PWD)modules_install
clean:
rm-rf*.o*~core.depend.*.cmd*.ko*..tmp_versions
.PHONY:
modulesmodules_installclean
else
obj-m:
=
endif
实验四:
#include
建笔记本控件
GtkWidget*notebook=gtk_notebook_new();
gtk_container_add(GTK_CONTAINER(window),notebook);
gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook),GTK_POS_TOP);立进程信息选项卡*/
intp=0,q=0,r=0,s=0;
charbufferf1[1000];
sprintf(bufferl,"Pagetwo");
GtkWidget*hbox=gtk_hbox_new(FALSE,5);
GtkWidget*scrolled_window=gtk_scrolled_window_new(NULL,NULL);示所有网页
gtk_widget_show_all(window);
事件循环
gtk_main();
return0;
}
参考文献:
[1]计算机操作系统实验指导.人民邮电出版社.2014年.
[2]计算机操作系统(第二版).人民邮电出版社.