【写在前面】
这是2023-2024春季学期操作系统课程有关xv6 lab部分的实验报告,参考了很多网络资源,解释也不一定正确,仅作为留档,参考需谨慎。
Lab 地址:6.1810 / Fall 2023
sleep
应用层
在 sleep 程序中,用户通过命令行输入一个时间参数,程序调用 sleep 系统调用使当前进程暂停指定的时间。
|
|
系统调用
当 sleep 被调用时,它是一个系统调用,会触发一个上下文切换,从用户空间切换到内核空间。
- 上下文切换:保存当前进程的上下文(包括寄存器状态、程序计数器等),并加载内核的上下文。
- 系统调用处理:内核接收到
sleep系统调用后,会将当前进程的状态设置为SLEEPING,并将其加入到等待队列中。
内核内部
在内核中,sleep 系统调用的处理如下:
-
设置进程状态:
1current->state = SLEEPING;将当前进程的状态设置为
SLEEPING,表示该进程正在等待某个事件(在这里是时间到期)。 -
加入等待队列:
1sleep_on(&ticks);将当前进程加入到等待队列中。
ticks是一个全局变量,表示系统启动后的时钟滴答数。 -
调度器: 内核的调度器会检查等待队列中的进程。如果进程的等待时间已到(
ticks >= current->wakeup),则将其从等待队列中移除,并将其状态设置为RUNNABLE。 -
唤醒进程: 当进程的等待时间到期后,调度器会将其唤醒,重新加入到就绪队列中,等待被调度运行。
线程切换
在 sleep 的过程中,内核会切换到其他就绪的进程运行。具体步骤如下:
- 保存上下文:保存当前进程的上下文。
- 选择下一个进程:调度器选择一个就绪的进程。
- 恢复上下文:恢复新进程的上下文。
- 切换执行:开始执行新进程。
完整代码
|
|

pingpong
应用层
pingpong 程序通过父子进程之间的管道通信实现简单的消息传递。
|
|
系统调用
-
pipe系统调用:1pipe(p);创建一个管道,返回两个文件描述符:
p[0]用于读取,p[1]用于写入。 -
fork系统调用:1fork();创建一个子进程。子进程继承父进程的文件描述符。
-
read和write系统调用:1 2read(p[0], &receive, 1); write(p[1], &send, 1);这些调用在父子进程之间传递数据。
内核内部
pipe的实现:内核分配一个管道结构体,包含两个文件描述符。设置文件描述符的读写指针。fork的实现:创建一个新进程,复制父进程的内存空间和文件描述符。新进程的初始状态为RUNNABLE。read和write的实现:write:将数据写入管道的缓冲区。read:从管道的缓冲区读取数据。如果没有数据可读,进程会被阻塞,直到有数据可用。
线程切换
在 pingpong 程序中,父子进程之间的通信会触发线程切换:
- 父进程写入数据:父进程调用
write,将数据写入管道。如果管道缓冲区已满,父进程会被阻塞。 - 子进程读取数据:子进程调用
read,从管道读取数据。如果管道缓冲区为空,子进程会被阻塞。 - 调度器的作用:调度器会根据进程的状态(
RUNNABLE或SLEEPING)选择合适的进程运行。当一个进程被阻塞时,调度器会切换到另一个就绪的进程。
完整代码
|
|


find
应用层
find 程序通过递归搜索目录,查找指定的文件名。
|
|
系统调用
-
open系统调用:1open(path, 0);打开一个目录或文件,返回一个文件描述符。
-
read系统调用:1read(fd, &de, sizeof(de));从目录文件描述符中读取目录项。
-
stat系统调用:1stat(buf, &st);获取文件或目录的状态信息。
内核内部
open的实现:内核查找路径对应的文件或目录。分配一个文件表项,设置文件描述符。read的实现:内核从目录文件中读取目录项。如果目录项为空,返回 0。stat的实现:内核查找路径对应的文件或目录。返回文件或目录的状态信息,包括类型、大小等。
线程切换
在 find 程序中,主要涉及文件系统操作,线程切换较少。但如果文件系统操作阻塞(如磁盘 I/O),调度器会切换到其他就绪的进程。
完整代码
|
|

