操作系统课设_第1页
操作系统课设_第2页
操作系统课设_第3页
操作系统课设_第4页
操作系统课设_第5页
已阅读5页,还剩40页未读 继续免费阅读

下载本文档

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

文档简介

1、课课 程程 设设 计计 报报 告告课程名称课程名称: 计算机操作系统专业班级:专业班级: 学学 号:号: 姓姓 名:名: 指导教师:指导教师: 报告日期:报告日期: 计算机科学与技术学院计算机科学与技术学院目 录1实验目的实验目的 .22实验环境实验环境 .23实验内容实验内容 .23.1实验一.23.2实验二.23.3实验三.23.4实验四(选做).33.5实验五(选做).34设计与实现设计与实现.34.1实验一.34.2实验二.104.3实验三.144.4实验四.205心得体会心得体会 .431实验目的掌握 Linux 操作系统的使用方法;了解 Linux 系统内核代码结构;掌握实例操作系

2、统的实现方法;2实验环境本次课程设计采用的操作系统环境是 windows8、Ubuntu 双系统,Ubuntu 系统版本号为 14.04,内核版本号为 linux 3.13.0;采用的编程环境为 CodeBlocks IDE 和QtCreator。3实验内容3.1实验一掌握 Linux 操作系统的使用方法,包括键盘命令、系统调用;掌握在 Linux 下的编程环境。(1)编写一个 C 程序,其内容为实现文件拷贝的功能。(2)编写一个 C 程序,其内容为分窗口同时显示三个并发进程的运行结果。要求用到 Linux 下的图形库(GTK/Qt) 。3.2实验二掌握系统调用的实现过程,通过编译内核方法,增

3、加一个新的系统调用,另编写一个应用程序,调用新增加的系统调用。实现的功能是:文件拷贝。3.3实验三掌握增加设备驱动程序的方法。通过模块方法,增加一个新的设备驱动程序,其功能可以简单。 (实现字符设备的驱动)3.4实验四(选做)了解和掌握/proc 文件系统的特点和使用方法(1)了解/proc 文件的特点和使用方法;(2)监控系统状态,显示系统中若干部件使用状态;(3)用图形界面实现系统监控状态;3.5实验五(选做)设计并实现一个模拟的文件系统。多用户的多级目录的文件系统设计。多用户、多级目录、login(用户登录) 、系统初始化(建文件卷,提供登录模块) 、文件的创建、文件的打开、文件的读写、

4、文件关闭、删除文件、创建目录(建立子目录) 、改变当前目录、列出文件目录、退出。4设计与实现4.1实验一4.1.1 实验要求掌握 Linux 操作系统的使用方法,包括键盘命令、系统调用;掌握在 Linux 下的编程环境。4.1.2 具体实现本实验内容是用 CodeBlocks IDE 实现的,该软件整合了函数库和编译器,因此使用起来非常方便。(1)编写一个 C 程序,其内容为实现文件拷贝的功能。在 windows 操作系统上实现的文件拷贝功能一般使用 fopen、fread、fwrite 三个来自标准 C 函数库的函数执行对文件的打开、读、写操作,而本次实验要求使用Linux 系统的系统调用

5、open、read、write 实现上述三个操作。用到的主要头文件如下:stdio.h标准输入输出头文件string.h字符串处理相关头文件unistd.hLinux 系统调用头文件,比如 read、writefcntl.h包含 open 系统调用errno.h包含一些调试错误时用到的变量具体实现思路:打开两个文件(分别是源文件和目标文件,可以是任意字符流形式存储的文件,包括文本文件、照片等) ,调用 read 函数读取源文件的内容,将 read 的返回值作为while 循环的判断条件,当返回值大于 0(即还未读取完毕源文件中的内容)时,调用 write 执行向目标文件写的操作,否则跳出循环,

6、表示源文件已经被拷贝到目标文件,然后调用 close 关闭源文件和目标文件。代码编写完成后,在 CodeBlocks 上编译运行即可。程序运行之前,桌面上只有“教程.docx” ,运行之后,桌面上新建了“教程副本.docx” ,并且“教程.docx”中的内容被复制到了“教程副本.docx” ,程序运行结果如下所示:详细代码见 4.1.3。(2)编写一个 C 程序,其内容为分窗口同时显示三个并发进程的运行结果。要求用到 Linux 下的图形库(GTK/Qt) 。本次实验使用的图形库是跨平台的开发工具 Qt。首先下载 Qt 的安装包并安装。Qt 安装完之后,先新建一个 Qt 控制台应用 MAIN

7、作为主进程,用于调用三个并发的子进程。在主进程的 main 函数中,使用 fork 创建三个子进程,若进程创建成功(即 fork 函数返回值等于 0) ,则使用 execv 函数进入对应的子进程(get、copy、put) 。主进程程序编写完成后,再新建三个 Qt Widgets Application,分别作为三个子进程get、copy、put(所实现的功能并不是拷贝) 。由于三个子进程窗口显示的内容形式一模一样,所以以子进程 get 为例。get 进程的窗口显示了一下四个内容:当前时间、子进程名称、子进程的 pid 和父进程 MAIN 的 pid。用 Qt 的对象 QDateTime 获取

8、系统当前时间,然后将时间转换成一个字符串写在一个 QLabel 类的实例中,然后将该实例添加至窗口;直接把当前进程名称写在一个标签上然后添加至窗口;使用 getpid和 getppid 函数分别获取当前进程号和父进程号,然后调用 sprintf 把进程号转换成字符串类型之后写在标签上并添加至窗口即可。主进程和三个子进程的程序全部编写完后,直接在 Qt 上编译运行。程序运行结果如下所示:详细代码见 4.1.3。4.1.3 源代码(1) 文件拷贝源代码#include #include #include #include #include #include #include #define SIZ

9、E 10 /每次读取的字符数目char * srcFile=/home/ilbear/桌面/教程.docx;char *goalFile=/home/ilbear/桌面/教程副本.docx;int main(int argc, const char *argv) int src, goal; int read_len; char buffSIZE; src=open(srcFile,O_RDONLY); if(src0) printf(Fail to open %sn.,srcFile); exit(1); goal=open(goalFile,O_WRONLY|O_CREAT,0666);

10、if(goal0) write(goal,buff,read_len); close(src); close(goal); return 0;(2) 三个并发进程#主进程主进程 MAIN#include #include #include #include #include #include int main(int argc, char *argv) QCoreApplication a(argc, argv); pid_t p1,p2,p3; if(p1=fork()=0) execv(/home/ilbear/桌面/build-get-Desktop_Qt_5_4_1_GCC_64bit

11、-Debug/get,NULL); else if(p2=fork()=0) execv(/home/ilbear/桌面/build-copy-Desktop_Qt_5_4_1_GCC_64bit-Debug/copy,NULL); else if( p3=fork()=0) execv(/home/ilbear/桌面/build-put-Desktop_Qt_5_4_1_GCC_64bit-Debug/put,NULL); waitpid(p1,NULL,0); waitpid(p2,NULL,0); waitpid(p3,NULL,0); return a.exec();#子进程子进程 g

12、etmainwindow.cpp#include mainwindow.h#include ui_mainwindow.h#include #include #include #include MainWindow:MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui:MainWindow),sharememory1(share1) ui-setupUi(this); setWindowTitle(get); setWindowFlags(Qt:Dialog); move(0,0); resize(500,500); char

13、 str128,f_id128; sprintf(str,%d,getpid(); sprintf(f_id,%d,getppid(); ui-textBrowser-setText(get); ui-textBrowser_2-setText(str); ui-textBrowser_3-setText(f_id); QTimer *timer = new QTimer(this); connect(timer, SIGNAL(timeout(), this, SLOT(timerUpDate(); timer-start(1);MainWindow:MainWindow() delete

14、ui;void MainWindow:timerUpDate() QDateTime time = QDateTime:currentDateTime(); QString str = time.toString(yyyy-MM-dd hh:mm:ss dddd); ui-labelCurDate-setText(str);#子进程子进程 copymainwindow.cpp#include mainwindow.h#include ui_mainwindow.h#include #include #include #include MainWindow:MainWindow(QWidget

15、*parent) : QMainWindow(parent), ui(new Ui:MainWindow),sharememory1(share1),sharememory2(share2) char str128,f_id128; ui-setupUi(this); setWindowTitle(copy); setWindowFlags(Qt:Dialog); move(500,500); resize(500,500); sprintf(str,%d,getpid(); sprintf(f_id,%d,getppid(); ui-textBrowser-setText(copy); ui

16、-textBrowser_2-setText(str); ui-textBrowser_3-setText(f_id); QTimer *timer = new QTimer(this); connect(timer, SIGNAL(timeout(), this, SLOT(timerUpDate(); timer-start(1);MainWindow:MainWindow() delete ui;void MainWindow:timerUpDate() QDateTime time = QDateTime:currentDateTime(); QString str = time.to

17、String(yyyy-MM-dd hh:mm:ss dddd); ui-labelCurDate-setText(str);#子进程子进程 putmainwindow.cpp#include mainwindow.h#include ui_mainwindow.h#include #include #include #include MainWindow:MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui:MainWindow),sharememory2(share2) char str128,f_id128; ui-se

18、tupUi(this); setWindowTitle(put); setWindowFlags(Qt:Dialog); move(1000,0); resize(500,500); sprintf(str,%d,getpid(); sprintf(f_id,%d,getppid(); ui-textBrowser-setText(put); ui-textBrowser_2-setText(str); ui-textBrowser_3-setText(f_id); QTimer *timer = new QTimer(this); connect(timer, SIGNAL(timeout(

19、), this, SLOT(timerUpDate(); timer-start(1);MainWindow:MainWindow() delete ui;void MainWindow:timerUpDate() QDateTime time = QDateTime:currentDateTime(); QString str = time.toString(yyyy-MM-dd hh:mm:ss dddd); ui-labelCurDate-setText(str);4.2实验二4.2.1 实验要求掌握系统调用的实现过程,通过编译内核方法,增加一个新的系统调用,另编写一个应用程序,调用新增

20、加的系统调用。4.2.2 具体实现(1) 系统调用的原理用户进程不能访问内核所占内存空间,也不能调用内核函数。进程调用一个特殊的指令,这个指令会跳到一个事先定义的内核中的一个位置。在 Intel CPU 中,由中断 INT 0 x80 实现。 (与 DOS 功能调用 int0 x21 很相似)跳转到的内核位置叫做sysem_call。检查系统调用号,这个号码代表进程请求哪种服务。然后,它查看系统调用表(sys_call_table)找到所调用的内核函数入口地址。接着,就调用函数,等返回后,做一些系统检查,最后返回到进程(如果这个进程时间用尽,就返回到其他进程) 。(2) 编写新的系统调用程序新

21、的系统调用程序实现的功能是:将一个文件中的内容拷贝到另一个文件中。这个系统调用的参数是两个 char*型的字符指针 SourceFile、GoalFile,分别表示源文件和目标文件的路径名。用户进程中的 open、read、write、close 函数此时对应内核函数 sys_open、 sys_read、 sys_write、 sys_close 函数。循环拷贝的判断条件还是 sys_read的返回值,当其大于 0 的时候执行循环,否则表示源文件已拷贝到了目标文件。 mm_segment_t 类型的变量 fs 的作用是在读写文件前得到当前 fs,避免使用的缓冲区超过了用户空间的地址范围而报错

22、。详细代码见 4.2.3。(3) 编译内核下载并解压内核先到 Linux 官方网站 /下载内核 linux-3.14.36.tar.xz。打开终端,使用 sudo su 获取 root 权限,然后使用 cp linux-3.14.36.tar.xz /usr/src 命令将linux-3.14.36.tar.xz 复制到文件夹/usr/src 下,复制完毕之后将其解压,用到的命令为:xz -d linux-3.14.36.tar.xz 和 tar xvf linux-3.14.36.tar。修改内核新的内核解压完毕后,使用 cd /usr/src/lin

23、ux-3.14.36 命令进入目录 /usr/src/linux-3.14.36。然后使用命令 sudo gedit kernel/sys.c 打开 sys.c,将新的系统调用程序复制到该文件的文件末尾,保存退出,系统调用程序详细代码见 4.2.3。使用命令 sudo gedit arch/x86/syscalls/syscall_64.tbl 打开 syscall_64.tbl 添加系统调用号。在该文件中添加一行内容 317 common mycall sys_mycall,其中系统调用号317 不是固定的,只要该文件中没有出现的数字都可以使用。添加之后保存退出。使用命令 sudo gedi

24、t include/asm-generic/syscalls.h 打开 syscalls.h,在“#endif /* _ASM_GENERIC_SYSCALLS_H */ 这一行的上面一行添加新的系统调用程序的函数定义,即:#ifndef sys_mycallasmlinkage int sys_mycall(char* sourceFile,char* destFile);#endif然后保存退出。编译内核在编译内核之前先要安装 ncurses 库,使用命令 sudo apt-get install libncurses5-dev安装。安装完毕后,进入 /usr/src/linux-3.14

25、.36 目录下,新建一个脚本文件mysyscall.sh,通过命令 gedit mysyscall.sh 打开该脚本文件进行编辑。将以下内容添加到脚本中:#!/bin/bashmake mrproper make menuconfig make depmake clean make bzImage j4make modules j4make modules_install j4make install j4mkinitramfs -o /boot/initrd.img-3.14.34 update-grub reboot保存退出,然后修改脚本文件的权限,使其可以对内核文件进行操作,修改权限的命

26、令为 chmod 777 mysyscall.sh。权限修改成功后,在终端中运行该脚本文件./mysyscall.sh,内核开始编译,期间会出现配置 linux 过程,直接先 save,然后 OK,再 exit 即可,继续等待编译结束。编译完成后,电脑会自动重启,重启选择进入Ubuntu 高级选项,在选项列表中选择新内核 linux-3.14.36 进入,打开终端输入uname -a 查看系统版本号,执行情况如下所示:说明已经成功进入新的内核 linux-3.14.36 中。(4) 编写系统调用测试程序需要用到的头文件是 syscall.h、unistd.h、stdlib.h。在 main 函

27、数中直接调用头文件 syscall.h 中定义的函数 syscall,该函数有三个参数,第一个参数是系统调用号(317) ,第二个参数是源文件(main.c,即测试程序的源代码文件) ,第三个参数是目标文件(yyk.text) 。程序运行结果为:在 main.c 所在目录下新建了一个 yyk.text 文件,并将 main.c中的代码拷贝到了 yyk.text 中。详细代码见 4.2.3。4.2.3 源代码(1) 系统调用程序asmlinkage int sys_mycall(char* SourceFile,char* GoalFile) int source=sys_open(Source

28、File,O_RDONLY,0); int goal=sys_open(GoalFile,O_WRONLY|O_CREAT|O_TRUNC,0600); char buff4096; mm_segment_t fs; fs = get_fs(); set_fs(get_ds(); int i; if(source0 & goal0) do i=sys_read(source,buff,4096); sys_write(goal,buff,i); while(i); else printk(Error!); sys_close(source); sys_close(goal); set_

29、fs(fs); return 10;(2) 测试程序#include #include #include int main() syscall(317,main.c,yyk.text); return 0;4.3实验三4.3.1 实验要求掌握增加设备驱动程序的方法。通过模块方法,增加一个新的设备驱动程序,其功能可以简单。 (实现字符设备的驱动)4.3.2 具体实现(1)Linux 核心是一种 monolithic 类型的内核,即单一的大核心,另外一种形式是MicroKernel,核心的所有功能部件都被拆成独立部分, 这些部分之间通过严格的通讯机制进行联系。Linux 内核是一个整体结构,因此向

30、内核添加任何东西.或者删除某些功能,都十分困难 。为了解决这个问题,引入了模块机制,从而可以动态的在内核中添加或者删除模块。模块一旦被插入内核,就和内核其他部分一样。Linux 内核中的设备驱动程序是一组常驻内存的具有特权的共享库,是低级硬件处理例程。对用户程序而言,设备驱动程序隐藏了设备的具体细节, 对各种不同设备提供了一致的接口,一般来说是把设备映射为一个特殊的设备文 件,用户程序可以像对其它文件一样对此设备文件进行操作。Linux 支持 3 种设备:字符设备、块设备和网络设备。设备由一个主设备号和一个次设备号标识。主设备号唯一标识了设备类型, 即设备驱动程序类型,它是块设备表或字符设备表

31、中设备表项的索引。次设备号仅由设备驱动程序解释 ,一般用于识别在若干可能的硬件设备中,I/O 请求所涉及到的那个设备。典型的 Linux 模块实现机制有如下几步:注册设备:在系统初启或者加载模块的时候,必须将设备登记到相应的设备数组,并返回主设备号。定义功能函数:对于每一个驱动函数来说,都有一些和此设备密切相关的功能函数。以最常用的块设备或者字符设备来说,都存在着诸如 open()、read()这一类的操作。当系统调用这些调用时,将自动的使用驱动函数中特定的模块来实现具体的操作。卸载设备:在不用这个设备时,可以将它卸载,主要是从/proc 中取消这个设备的特殊文件。(2) 编写 Makefil

32、e 文件Makefile 文件用于编译设备驱动程序,其内容如下:ifneq ($(KERNELRELEASE),) #kbuild syntax.#模块的文件组成mymodule-objs :=MyDeviceDriver.o #生成的模块文件名 obj-m := MyDeviceDriver.o elsePWD :=$(shell pwd)KVER :=$(shell uname -r)KDIR :=/lib/modules/$(KVER)/buildall:$(MAKE) -C $(KDIR) M=$(PWD)clean:#rm -f *.cmd *.o *.mod *.korm -rf

33、.*.cmd *.o *.mod.c *.ko .tmp_versions#$(MAKE) -C $(KDIR) M=$(PWD) cleanendif(3)编写设备功能函数编写设备驱动程序的主要工作就是编写子功能函数,并填充 file_operations 的各个域 。结构体 file_operations 的具体定义如下:struct file_operations struct module *owner;/拥有该结构的模块的指针,一般为 THIS_MODULES loff_t (*llseek) (struct file *, loff_t, int);/用来修改文件当前的读写位置 s

34、size_t (*read) (struct file *, char _user *, size_t, loff_t *);/从设备中同步读取数据 ssize_t (*write) (struct file *, const char _user *, size_t, loff_t *);/向设备发送数据ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);/初始化一个异步的读取操作 ssize_t (*aio_write) (struct kiocb *, const struct

35、 iovec *, unsigned long, loff_t);/初始化一个异步的写入操作 int (*readdir) (struct file *, void *, filldir_t);/仅用于读取目录,对于设备文件,该字段为NULL unsigned int (*poll) (struct file *, struct poll_table_struct *); /轮询函数,判断目前是否可以进行非阻塞的读写或写入 int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); /执行设备 I/O 控

36、制命令 long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); /不使用 BLK 文件系统,将使用此种函数指针代替 ioctl long (*compat_ioctl) (struct file *, unsigned int, unsigned long); /在 64 位系统上,32 位的ioctl 调用将使用此函数指针代替 int (*mmap) (struct file *, struct vm_area_struct *); /用于请求将设备内存映射到进程地址空间 int (*open) (struct

37、 inode *, struct file *); /打开 int (*flush) (struct file *, fl_owner_t id); int (*release) (struct inode *, struct file *); /关闭 int (*fsync) (struct file *, struct dentry *, int datasync); /刷新待处理的数据 int (*aio_fsync) (struct kiocb *, int datasync); /异步刷新待处理的数据 int (*fasync) (int, struct file *, int);

38、/通知设备 FASYNC 标志发生变化 int (*lock) (struct file *, int, struct file_lock *); ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); int (*check_flags)(int); int (*floc

39、k) (struct file *, int, struct file_lock *); ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); int (*setlease)(struct file *, long, struct file_lock *); ;子

40、功能函数详细代码见 4.4.3。(4) 设备驱动程序安装 make clean,清除 make 产生的残留 make,重新调用 Makefile 编译设备驱动程序 insmod -f MyDeviceDriver.ko,加载生成的 MyDeviceDriver.ko 模块 cat /proc/devices,获取设备驱动程序的主设备号mknod /dev/MyDeviceDriver c 250 0,创建设备文件,250 为主设备号,0 为从设备号(5)测试驱动程序此设备驱动程序实现的功能是将一个字符串中内容拷贝到另外一个字符串中。测试程序编写完成后,在终端输入 gcc test.c -o t

41、est 进行编译。测试结果如下:详细代码见 4.3.3。4.3.3 源代码(1) 设备驱动程序#include #include #include #include #include #include #include #include #define DEV_SIZE 102400 /设备申请的最大内存空间struct Device char *data;/数组指针,用于存放从用户读入的数据 long size;/存储的数据长度*devp;struct cdev cdev;/字符设备结构体static int devNum_major = 0;/主设备号变量/对应用户态的 lseekstat

42、ic loff_t my_llseek(struct file *file,loff_t offset, int whence) loff_t cfo=0;/文件当前偏移量,current file offset switch(whence) case 0:/SEEK_SET cfo=offset;break;case 1:/SEEK_CUR cfo=file-f_pos+offset;break;case 2:/SEEK_END cfo=DEV_SIZE-1+offset;break; if (cfoDEV_SIZE)/文件偏移量越界 return -EINVAL; file-f_pos =

43、 cfo; return cfo;/对应用户态的 read,写数据到用户空间static ssize_t my_read(struct file *file, char _user *buf, size_t count, loff_t *p_cfo) int val = 0; struct Device *dev = file-private_data; /设备描述结构体指针,获取设备信息 if (copy_to_user(buf, (void*)(dev-data + *p_cfo), count)/如果成功返回 0;如果失败,返回未完成 copy 的长度 val = -EFAULT; el

44、se *p_cfo += count;/copy 成功,文件偏移量加上 count val = count; return val;/对应用户态的 write,从用户空间读入数据static ssize_t my_write(struct file *file, const char _user *buf, size_t count, loff_t *p_cfo) int val = 0; struct Device *dev = file-private_data; if (copy_from_user(dev-data + *p_cfo, buf, count)/如果成功返回 0;如果失败

45、,返回未完成 copy 的长度 val = -EFAULT; else *p_cfo += count;/copy 成功,文件偏移量加上 count val = count; return val;static int my_open(struct inode *inode, struct file *file) file-private_data = devp; return 0;struct file_operations fops= .owner = THIS_MODULE, .llseek = my_llseek, .read = my_read, .write = my_write,

46、 .open = my_open,;int init_module(void)int dev_num;dev_num = register_chrdev(0,MyDeviceDriver,&fops);if (dev_num 0) printk(KERN_INFO MyDeviceDriver: FAIL to get major numbern);return dev_num;if (devNum_major = 0) devNum_major = dev_num; /初始化 cdev 结构 cdev_init(&cdev, &fops); cdev.owner =

47、THIS_MODULE; cdev.ops = &fops; cdev_add(&cdev,MKDEV(devNum_major, 0), 1);/注册 1 个字符设备 /为设备描述结构体分配内存 devp = kmalloc(sizeof(struct Device), GFP_KERNEL); if (!devp) dev_num = -ENOMEM; printk(KERN_INFO MyDeviceDriver: FAIL to get memoryn); return dev_num; (*devp).size = DEV_SIZE; (*devp).data = k

48、malloc(DEV_SIZE, GFP_KERNEL); memset(*devp).data, 0, (*devp).size);/初始化为 0 return 0;void cleanup_module(void)cdev_del(&cdev);/注销设备 kfree(devp);/注销设备结构体 kfree(*devp).data);/注销设备内存空间 unregister_chrdev(devNum_major,MyDeviceDriver);/卸载主设备号MODULE_LICENSE(GPL);(2) 驱动程序测试程序#include #include #include #d

49、efine BUFFER_SIZE 102400int main(void)int dev,i=0;char c; char sourceBUFFER_SIZE;/写入 MyDeviceDriver 设备的内容 char goalBUFFER_SIZE; /MyDeviceDriver 设备的内容读入到该 goal 中printf(input the string you want to write in your device:n);while(c=getchar()!=n)sourcei+=c;printf(n); if(dev=open(/dev/MyDeviceDriver,O_RDW

50、R)=-1) /打开 MyDeviceDriver 设备失败 printf(FAIL to open MyDeviceDriver!n);else/成功 printf(SUCCESS to open MyDeviceDriver!n); printf(source:n%snn,source); write(dev,source,sizeof(source); /把 source 中的内容写入 MyDeviceDriver 设备 lseek(dev,0,SEEK_SET); /把文件指针定位到文件开始的位置 read(dev,goal,sizeof(source); /把 MyDeviceDri

51、ver 设备中的内容读入到 goal 中 printf(goal:n%snn,goal); return 0;4.4实验四实验四有两个选做题目,分别是 proc 文件监控系统和小型文件系统,本次实验我选择的题目是 proc 文件监控系统。4.4.1 实验要求了解/proc 文件的特点和使用方法;监控系统状态,显示系统中若干部件使用状态;用图形界面实现系统监控状态。4.4.2 具体实现(1)/proc 文件系统的特点Linux 的 PROC 文件系统是进程文件系统和内核文件系统的组成的复合体,是将内核数据对象化为文件形式进行存取的一种内存文件系统,是监控内核的一种用户接口。它拥有一些特殊的文件(

52、纯文本) ,从中可以获取系统状态信息。(2)功能清单获取并显示主机名,与之相关的 proc 文件为/proc/sys/kernel/hostname;获取并显示系统启动的时间,与之相关的 proc 文件为/proc/uptime;显示系统到目前为止持续运行的时间,与之相关的 proc 文件为/proc/uptime;显示系统的版本号,与之相关的 proc 文件为/proc/sys/kernel/ostype 和/proc/sys/kernel/osrelease; 显示 CPU 的型号和主频大小,与之相关的 proc 文件为/proc/cpuinfo;通过 pid 或者进程名查询一个进程,并显

53、示该进程的详细信息,提供杀掉该进程的功能,与之相关的 proc 文件为/proc/(pid)/stat;显示系统所有进程的一些信息,包括 pid、ppid、占用内存大小、优先级等,与之相关的 proc 文件为/proc/(pid)/stat, /proc/(pid)/statm;CPU 使用率的图形化显示(2 分钟内的历史记录曲线) ,与之相关的 proc 文件为/proc/stat;内存和交换分区的使用率的图形化显示(2 分钟内的历史曲线) ,与之有关的proc 文件为/proc/meminfo;在状态栏显示当前时间,未使用到/proc 中的文件;在状态栏显示当前 CPU 使用率,与之相关的

54、 proc 文件为/proc/stat;在状态栏显示当前内存使用情况,与之相关的 proc 文件为/proc/meminfo;用新线程运行一个其他程序,未使用到/proc 中的文件;关机功能,未使用到/proc 中的文件;(3)功能实现获取并显示主机名用 fopen 函数打开/proc/sys/kernel/hostname 文件,然后以文件指针为输入流,用fgets 从其中读出一行字符包含主机名,然后用格式化输出函数 sscanf 函数输出一个字符串,即主机名。获取并显示系统启动的时间从文件/proc/uptime 中获取系统启动到现在的运行时间(单位是 s) ,然后调用time 函数获取系

55、统当前时间(单位是 s) ,用当前时间秒数减去运行时间秒数即为系统启动的时间秒数,然后调用 localtime 函数将系统启动时间秒数转换成 tm 结构体类型的变量,该变量中的成员包括年份、月份、日期、星期几、时、分、秒等,再调用输出函数输出即可。显示系统到目前为止持续运行的时间用 fopen 函数打开/proc/uptime 文件,然后以文件指针为输入流,用 fgets 从其中读出一行字符包含系统运行时间,然后用格式化输入函数 sscanf 从读取出的字符流中输入一个 float 类型的数到 runtime,即系统运行的时间。显示系统的版本号从/proc/sys/kernel/ostype

56、和/proc/sys/kernel/osrelease 中读取系统类型(比如linux)和系统内核版本号,处理方法和获取系统运行时间的方法一样。得到系统类型和系统内核版本号之后,调用 QString 类的方法 arg 将两个字符串连接起来,再输出显示即可。显示 CPU 的型号和主频大小打开/proc/cpuinfo 文件后发现 CPU 有四个,相同的型号,不同的主频,后来才弄清楚所谓的四个 CPU 是 CPU 的四个核心,而“主频”并不是主频,而是当前时刻该核心所使用的 CPU 核心频率,随时间而变化的。弄清楚文件中的内容的含义之后,开始处理/proc/cpuinfo,从中读取 CPU 的型号

57、和频率。处理这个文件没有用到 fopen 等函数,而是使用了 Qt 自带的两个类 QFile和 QTextStream,定义一个 QFile 类型的变量 file,并用路径名“/proc/cpuinfo”初始化该变量,其作用是以只读方式打开文件/proc/cpuinfo,然后以 file 的地址作为参数初始化 QTextStream 类型的变量 stream,其作用是将/proc/cpuinfo 文件中的内容以字符流的形式存入变量 stream 中,相当于一个文本流。由于 CPU 的型号是一样的,所以只读取第一个型号名称即可,根据 CPU 型号名称所在的行,采用 while 循环读取strea

58、m 中的内容,每次读取一行,当行数等于 CPU 型号所在行时,将读取出的一行赋值给一个 QString 类型的变量,再调用 QString 的方法 mid 截取 CPU 型号名称,file.close()关闭 file。CPU 四个核心的主频处理方法和 CPU 型号的处理方法一致,参照上述步骤即可。通过 pid 或者进程名查询一个进程,并显示该进程的详细信息,提供杀掉该进程的功能在获取所有进程信息的时候,获取到的所有信息已经被存储在一个全局结构体数组变量中了,所以查询的时候,先获取输入 lineEdit 中的文本(QString 类型) ,然后将文本与全局结构体数组变量的每一个数组元素的 na

59、me 成员和 pid 成员作比较,若相等,说明待查询的进程存在,将该进程的详细信息输出即可。杀死进程前先要获取将要被杀死进程的名称或者 pid,而且该进程必须存在于/proc 目录下,即先查询一次待杀死的进程,处理方法如上所述。Linux 系统提供了kill、pkill 等杀死进程的命令,pkill 通过 pid 杀死进程,kill 通过进程名称杀死进程。通过将 lineEdit 中的内容和 kill 或 pkill 组成终端命令,然后调用 system 函数执行这些命令即可杀死相应的进程。显示系统所有进程的一些信息,包括 pid、ppid、占用内存大小、优先级等系统的进程众多,且进程号从 1

60、 到几万的都有,如果从 1 开始遍历访问,效率就会很低。所以本次实验我采用的是 Linux 中对目录进行操作的函数 opendir(),readdir()。这两个目录操作函数在上学期的操作系统第三次课程实验中已经学习使用过,所以再次使用没遇到多大的障碍。实现思路为:声明一个 DIR 类型的指针 dir,用 opendir 函数打开/proc 目录,返回值赋值给 dir,然后将 dir 作为函数 readdir 的参数,readdir 函数返回值复制给dirent 结构体指针 ptr。ptr 指向的结构体包含 d_name char 数组成员,即文件或者目录名,将 d_name 数组的 0 号元素分别和字符1、 9比较,若处于这两者之间,则表明该

温馨提示

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

评论

0/150

提交评论