挑战性任务-Sigaction
挑战性任务报告
首先想要吐槽一点,由于要求不能对Makefile进行修改,导致不能将自己编写的文件链接入可执行文件当中,导致只能把自己写的函数挤压进已有文件当中,显得有点丑陋
本实验需要实现异步通信Sigaction,仅需关注32个普通信号中的6个信号,按照其信号处理函数或默认处理动作来处理,其余忽略即可。
信号数据存放位置由于考虑到不同进程需要存储自己的信号,便于在从内核态返回用户态时直接查询使用,故放置在进程控制块Env结构体内
信号选择由于指导书要求同一普通信号在进程中最多只存在一个,故只要考虑不同信号间的优先级即可,同时要考虑当前进程正在处理的信号的屏蔽集。( 对于SIGKILL信号,该信号不可被阻塞)
内核态到用户态的准备参考助教在讨论区的建议,需要进程从内核态返回至用户态过程中检查是否有信号进行处理,若有,则处理完后再返回中断位置,这就需要使用重新申请一个栈帧用于当前信号的处理,设置传参等,以及保存进程发生中断时的现场。(一个比较好玩的地方在于当完成信号处理后会调用系统调用syscall_set_trapframe恢复原来的栈帧,这个时候既恢复现场(重新设置cp0_e ...
Lab6
Thinking 6.1
示例代码中,父进程操作管道的写端,子进程操作管道的读端。如果现在想让父进程作为“读者”,代码应当如何修改?
123456789101112131415161718192021222324252627282930313233343536#include <stdlib.h>#include <unistd.h>int fildes[2];char buf[100];int status;int main(){ status = pipe(fildes); if (status == -1) { printf("error\n"); } switch (fork()) { case -1: break; case 0: /* 子进程 - 作为管道的写者 */ close(fildes[0]); /* 关闭不用的读端 */ write(fildes[1], "Hello world\n", 12); /* 向管道中写 ...
Lab5
Thinking 5.1
如果通过 kseg0 读写设备,那么对于设备的写入会缓存到 Cache 中。这是一种错误的行为,在实际编写代码的时候这么做会引发不可预知的问题。请思考:这么做这会引发什么问题?对于不同种类的设备(如我们提到的串口设备和 IDE 磁盘)的操作会有差异吗?可以从缓存的性质和缓存更新的策略来考虑。
answer:
缓存Cache是为了提高CPU访问数据的速度,但只有在外部设备进行数据更新或缓存Cache空间不足时,缓存数据才会被写入内存,故在外部设备更新数据时,CPU可能从外设(外部设备对应的内存空间)读入更新前的数据,故引发错误。
串口设备通常是字符设备,按照字节或字符进行数据传输,传输数据的频率高,IDE磁盘是块设备,按块进行数据传输,传输数据的频率低,故前者引发问题的概率大于后者
Thinking 5.2
查找代码中的相关定义,试回答一个磁盘块中最多能存储多少个文件控制块?一个目录下最多能有多少个文件?我们的文件系统支持的单个文件最大为多大?
answer:
宏FILE_STRUCT_SIZE表示文件结构体的大小256B,一个磁盘块的大小为4KB, ...
Lab4
Thinking 4.1
思考并回答下面的问题:
内核在保存现场的时候是如何避免破坏通用寄存器的?
系统陷入内核调用后可以直接从当时的 $a0-$a3参数寄存器中得到用户调用 msyscall留下的信息吗?
我们是怎么做到让 sys 开头的函数“认为”我们提供了和用户调用 msyscall 时同样的参数的?
内核处理系统调用的过程对 Trapframe 做了哪些更改?这种修改对应的用户态的变化是什么?
answer:
内核通过调用宏SAVE_ALL,先保存$sp,$v0两个寄存器,协助将通用寄存器保存在栈空间Trapframe中
可以,因为系统陷入内核调用时,当时的 $a0-$a3参数寄存器并未被修改,可以得到用户调用 msyscall留下的信息。
用户函数syscall_*到内核函数sys_*,$a0-$a3寄存器不会被破坏,也可直接通过内核栈获取
```bashtf->cp0_epc += 4;tf->regs[2] = func(arg1, arg2, arg3, arg4, arg5);
1234567891011121314151617181920212 ...
Lab3
Thinking 3.1
请结合 MOS 中的页目录自映射应用解释代码中 e->env_pgdir[PDX(UVPT)] = PADDR(e->env_pgdir) | PTE_V 的含义。
解释:
该代码设置进程控制块e的页目录下虚拟地址UVPT映射到其本身的物理地址,并设置为只读权限。该页目录项所指向的为一个二级页表,但通过地址判断还是一个一级页表,即页目录自身,这就是页目录的自映射。
分析:
读取该虚拟地址PDX(UVPT)[31:22]PDX(UVPT)[31:22]0000_0000_0000_0000的数据,首先读取页目录项(e->env_pgdir[PDX(UVPT)]),得到二级页表的基地址(物理地址)PADDR(e->env_pgdir) | PTE_V,该二级页表与一级页表为同一个页表,所读取的页表项与一开始读取的页目录项相同,为e->env_pgdir[PDX(UVPT)],最终得到数据PADDR(e->env_pgdir) | PTE_V,所得到的页表为页目录本身,即为自映射。
Thinking 3.2
elf_load_ ...
Lab2
Thinking2.1
Thinking 2.1 请根据上述说明,回答问题:在编写的 C 程序中,指针变量中存储的地址被视为虚拟地址,还是物理地址?MIPS 汇编程序中 lw 和 sw 指令使用的地址被视为虚拟地址,还是物理地址?
answer
两者都是虚拟地址
Thinking2.2
Thinking 2.2 请思考下述两个问题:
从可重用性的角度,阐述用宏来实现链表的好处。
查看实验环境中的 /usr/include/sys/queue.h,了解其中单向链表与循环链表的实现,比较它们与本实验中使用的双向链表,分析三者在插入与删除操作上的性能差异。
answer
类型灵活性:宏可以接受类型参数,可为不同的数据类型创建链表,而无需编写多个不同的链表实现。通过传递不同的类型给宏,为任何数据类型创建链表。
减少代码冗余:使用宏可以避免在多个地方重复编写相同的链表节点结构体定义(通过引用宏即可)。
易于维护:由于链表节点的定义是通过宏来实现的,因此需要修改链表节点的结构,只需要修改宏的定义即可,可以在整个代码中统一更新链表节点的结构。
跨项目重用:由于宏是在预处理阶段展开的 ...
Lab1
Thinking 1.1
请阅读 附录中的编译链接详解,尝试分别使用实验环境中的原生 x86 工具链(gcc、ld、readelf、objdump 等)和 MIPS 交叉编译工具链(带有 mips-linux-gnu-前缀),重复其中的编译和解析过程,观察相应的结果,并解释其中向 objdump 传入的参数的含义。
新建 + 预处理
只编译而不链接 + 反汇编
传入参数为test.o,此处仅生成test.c的目标文件,未链接其他目标文件,故printf 的具体实现依然不在我们的程序中。
编译 + 反汇编
传入的参数为a.out,此处为test.c编译出的可执行文件,在链接(Link)阶段,printf 的实现被插入到最终的可执行文件中的。
objdump 传入的参数的含义
1234-D, --disassemble-all Display assembler contents of all sections --disassemble=<sym> Display assembler contents from <sym& ...
OS_作业1
第一题1. 什么是多道程序设计?多道程序设计与分时系统的区别是什么?
定义: 多道程序设计是一种计算机内存管理技术,其允许在计算机内存中同时存放多个相互独立的程序,并使这些程序在管理程序的控制下相互穿插运行。这种技术使得两个或两个以上的程序在计算机系统中同时处于开始到结束之间的状态。从宏观上看,这些程序似乎是并行运行的,因为多道程序都处于运行中且没有运行结束;但从微观上看,这些程序实际上是串行的,它们轮流使用CPU,交替执行。
多道程序设计技术的引入旨在提高CPU的利用率,提高计算机的硬件资源的利用率,充分发挥计算机系统部件的并行性。当一道程序因某种原因(如I/O请求)而暂停执行时,CPU会立即转去执行另一道程序,从而减少了CPU的等待时间,增加了系统的吞吐量,提高了系统的效率。
特点:多道、宏观上并行、微观上串行的。
区别:
分时系统是一种联机的多用户交互式操作系统,它是多道程序设计的延伸。在分时系统中,多个用户可以通过终端同时与计算机进行交互,每个用户都可以实时得到服务。分时系统采用时间片轮转的方式,每个用户获得一个时间片并运行,如果某个作业在分配的时间片用完之前计算还未完成, ...