操作系统课程设计
代码地址:GitHub - zzering/OS-course-design: 操作系统课设:系统调用,磁盘调度算法,文件调用,进程管理,分页置换算法,进程通信目录实验一:为Linux系统增加系统调用... 31.1程序功能及设计思路... 31.1.1程序功能... 31.1.2设计思路... 31.2程序运行情况及截图... 11实验二:磁盘调度... 112.1程序功能及设计思路... 11
关于完整代码&更详细内容&实验一环境配置 请访问github仓库地址:GitHub - zzering/OS-course-design: 操作系统课设:系统调用,磁盘调度算法,文件调用,进程管理,分页置换算法,进程通信
实验一:为Linux系统增加系统调用
1.1程序功能及设计思路
1.1.1程序功能
通过修改Linux 0.11系统文件(使用Bochs运行), 实现增加一个简单的系统调用
此处是调用nameout.c输出”Hello, I’m lwh”
1.1.2设计思路
在用户层面编写程序nameout.c,通过syscall这个宏开启调用系统函数的窗口,调用sys_nameout系统函数。
编写函数sys_nameout,以name.c的文件格式保存在了linux0.11系统kernel中;
sys_nameout调用了printk()完成打印输出。
修改Makefile文件让我们添加的 kernel/who.c 可以和其它 Linux 代码编译链接到一起
详细步骤:
添加iam和whoami系统调用编号的宏定义(_NR_xxxxxx)
文件路径:/linux-0.11/include/unistd.h
修改系统调用总数
文件路径:/linux-0.11/kernel/system_call.s
为新增的系统调用添加系统调用名并维护系统调用表
文件路径:/linux-0.11/include/linux/sys.h
为新增的系统调用编写代码实现,创建一个文件 name.c
文件路径: /linux-0.11/kernel
name.c中写入printk(”Hello, I’m lwh”)
修改 Makefile
要想让我们添加的 kernel/who.c 可以和其它 Linux 代码编译链接到一起,必须要修改 Makefile 文件
文件路径: / linux-0.11/kernel/Makefile
编写测试程序
到此为止,内核中需要修改的部分已经完成,接下来需要编写测试程序来验证新增的系统调用是否已经被编译到linux-0.11内核可供调用
文件路径:/oslab/namein.c /oslab/nameout.c
/* nameout.c */
#define __LIBRARY__
#include <unistd.h>
#include <errno.h>
#include <asm/segment.h>
#include <linux/kernel.h>
#include <stdio.h>
_syscall2(int, nameout,char *,name,unsigned int,size);
int main(int argc, char *argv[])
{
char username[64] = {0};
/*调用系统调用nameout()*/
nameout(username, 24);
printf("%s\n", username);
return 0;
}
采用挂载方式实现宿主机与虚拟机操作系统的文件共享,在 oslab
目录下执行以下命令挂载hdc目录到虚拟机操作系统上
编译linux内核
文件路径: /oslab/linux
终端执行 make命令
Make成功
运行Bochs虚拟机
文件路径: /oslab/
终端执行 run命令
为linux-0.11新增调用号
文件路径: 虚拟机中/usr/include/unistd.h(也可以挂载后在图形界面中修改)
(若在虚拟机中修改)
(若挂载后在主机的图形界面中修改)
gcc运行 成功输出案例文字
1.2程序运行情况及截图
实验二:磁盘调度
2.1程序功能及设计思路
2.1.1程序功能
使用FIFO(先来先服务)、SSTF(最短寻道优先)以及SCAN(电梯调度算法)进行磁盘调度
显示调度顺序, 计算出平均移动磁道数
2.1.2设计思路
定义两个全局变量
int a[MAX];//存放要用到的磁道号
int start;//记录开始的磁道
主函数中设计一个循环, 生成界面, 并使其能够调用3个磁盘调用算法
2.2算法设计
2.2.1求平均值函数
将每次寻道的距离数组length[]传入函数, 将其累加求平均值
2.2.2先来先服务算法
定义visit[]数组, 来记录请求是否被处理, 若处理过, 则查看下一个请求
求出每次寻道的距离, 将其放入length[]中
2.2.3最短寻道时间优先算法
定义flag记录当前最短路径下标
用for循环找没有访问过的中最近的
每找到一个将其放入length[]中, 并设为已访问
2.2.4扫描算法
调用sort函数将所有请求按从小到大排序
通过for循环找到离当前磁头最近的请求磁道, 随后往递增方向访问, 全部访问完成, 再往递减方向访问
每次访问完更新磁头位置
2.3程序运行情况及截图
实验三: Linux系统文件调用接口
3.1程序功能及设计思路
3.1.1程序功能
使用文件系统调用编写一个文件工具 filetools,使其具有以下功能:
创建新文件, 写文件, 读文件, 修改文件权限, 查看当前文件权限, 退出
3.1.2设计思路
模拟类似shell的效果即通过touch a.cpp, echo “hello” >> a.cpp这样的方式实现文件管理
实现各个文件操作的函数
编写一个函数对输入的操作进行字符串处理和判断, 然后调用相应的函数
3.2算法设计
3.2.1创建新文件函数
umask(0000); //建立新文件时的权限遮罩
通过open(filename, O_RDWR | O_CREAT, 0666)函数创建文件
得到的文件权限为0666-0000
fd<0时, 提示创建失败
3.2.2写文件函数
通过open(filename, O_WRONLY);打开指定文件, 权限是只写
write(fd, buffer, strlen(buffer));将缓存区的内容写入
3.2.3读文件函数
open(filename, O_RDONLY); 打开指定文件, 权限是只读
lseek(fd, 0, SEEK_SET); lseek函数定位一个已经打开的文件, 第2 3参数将读写位置移到文件开头
创建缓存区
read(fd, buffer, 1 << 15);读取内容到缓存区
打印缓冲区内容
3.2.4修改文件权限函数
打开指定文件
十进制转八进制
int mode_u = mode / 100; // user
int mode_g = mode / 10 % 10; // group
int mode_o = mode % 10; // others
mode = (mode_u * 8 * 8) + (mode_g * 8) + mode_o;
chmod(filename, mode);修改权限
3.2.5查看文件权限
打开指定文件
char *pargv[4] = {"ls", "-l", NULL, NULL};
需要将文件名传到*pargv[2]
pargv[2] = (char *)malloc(50);
strcpy(pargv[2], filename);
查看指定文件的权限
execv("/bin/ls", pargv);
3.2.6输入处理函数
通过sstream流, 处理输入的字符
取touch cat echo chmod ll 的前两个字母通过s.find来查找字符中是否存在对应的关键字, 若存在, 就调用对应函数
2.3程序运行情况及截图
交互界面
新建文件
写入文件
查看文件
改变文件权限
查看文件权限
实验四: 进程管理
4.1程序功能及设计思路
4.1.1程序功能
父进程使用pipe()建立一个管道,然后调用fork()创建子进程1和子进程2
子进程1每隔1秒通过管道向子进程2发送数据“I send message x times”
子进程2从管道读出信息,并显示在屏幕上
父进程用系统调用signal()来捕捉中断信号,用kill()向两个子进程发出信号,子进程输出如下信息后终止: Child Process 1 is killed by Parent! Child Process 2 is killed by Parent!
父进程等待两个子进程终止后,释放管道并输出Parent Process is Killed!
4.1.2设计思路
定义两个进程
定义两个缓存区msg和buffer
子进程1中输出字符串到msg中,调用write函数将其写入到fd[1]中
子进程2调用read函数将fd[0]中的数据读入到buffer中, 然后将其输出
两进程中都使用signal(SIGINT, SIG_IGN);屏蔽系统定义的结束, 通过signal(SIGUSR1, userDefinedSignal);来调用自定义的信号对应的结束的函数
4.2程序运行情况及截图
实验五: 请求分页系统中的置换算法
5.1程序功能及设计思路
5.1.1程序功能
产生320条指令序列
将指令序列变换成页地址流
分别计算先进先出(FIFO)页面置换算法,最近最久未使用(LRU)页面置换算法,最佳(Optimal)页面置换算法在不同内存页块下的命中率
5.1.2设计思路
实现三种算法
设计一个取指令函数,得到320个随机的指令序列
主函数中设计一个循环, 依次输出计算出的值
5.2算法设计
5.2.1 FIFO算法
用链表模拟队列。初始化之后,每次取得下一个指令,检查队列中存在对应的页号,如果存在命中次数加1,否则删除队列中第一个页号,插入当前页号
5.2.2 LRU算法
当需要淘汰一个页面时,总是选择在最近一段时间内最久不用的页面予以淘汰。定义一个结构体,保存指令所在的页号和在队列中没有被访问的次数。如果需要淘汰,每次淘汰没有被访问次数最多的页号
5.2.3 OPT算法
从主存中移出永远不再需要的页面;如无这样的页面存在,则选择最长时间不需要访问的页面。于所选择的被淘汰页面将是以后永不使用的,或者是在最长时间内不再被访问的页面,这样可以保证获得最低的缺页率。每次淘汰时,评估每一个页号将来的位置,淘汰最长时间不需要访问的页面
5.2.4 取指令函数
使用srand()函数 设定时间种子。使用随机函数rand() % M得到0~M - 1的随机数(M < MAX_INT),当指令到达320时,停止生成指令。最后除以1024得到所在的页号。
主函数中设计一个循环, 依次输出计算出的值
5.3程序运行情况及截图
实验六: 进程通信
6.1程序功能及设计思路
6.1.1程序功能
使用管道来实现父子进程之间的进程通信
使用消息缓冲队列来实现 client 进程和 server 进程之间的通信
使用共享存储区来实现两个进程之间的进程通信
6.1.2设计思路
1.通过管道通信
定义两个缓存区msg和buffer
子进程1中输出字符串到msg中,调用write函数将其写入到fd[1]中
父进程调用read函数将fd[0]中的数据读入到buffer中, 然后将其输出
2.通过消息缓冲队列通信
server端:
server 进程先建立一个关键字为 SVKEY(如 75)的消息队列,然后等待接收类型为 REQ(例如 1)的消息;
在收到请求消息后,它便显示字符串“serving for client”和接收到的 client 进程的进程标识数,表示正在为 client 进程服务;
然后再向 client 进程发送应答消息,该消息的类型是 client 进程的进程标识数,而正文则是 server 进程自己的标识ID。
client端:
client 进程则向消息队列发送类型为 REQ 的消息(消息的正文为自己的进程标识 ID) 以取得 sever 进程的服务,并等待 server 进程发来的应答;
然后显示字符串“receive reply from”和接收到的 server 进程的标识 ID
3.通过共享缓存区通信量
server端
server创建共享存储区, 然后获取其首地址, 使用while (*addr == -1)阻塞自身, 用于进程同步
client端
client打开共享存储区, 然后获取其首地址, 使用while (*addr != -1)阻塞自身
6.2程序运行情况及截图
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)