目录
三、Mission 1:重新实现timer_sleep()函数
一、实验简介
Pintos是Standford大学为操作系统课程专门开发的一个基于80x86架构的简单操作系统框架(A simple operating system framework)。他支持内核线程、加载和运行用户程序以及文件系统。
小组成员:郭鑫玥,胡小波,贾浩男,贾飞阳,陈俊良
二、实验环境的安装与搭建
1. 下载bochs 和 pintos压缩包
2. 安装bochs 和 pintos
1)将pintos/src/utils中的一些文件复制进usr/bin/文件夹
2)配置安装pintos-gdb
3)此处注意:要修改/usr/bin/pintos-gdb中的配置
GDBMACROS=/usr/bin/gdb-macros
4)修改相关文件的权限
5)复制squish-pty到usr/bin,并修改权限
6)链接bochs
7)运行pintos,使用命令pintos -v -- run alarm-multiple
测试pintos样例
8)之后进行makecheck测试,可见此时全部为FAIL
三、Mission 1:重新实现timer_sleep()函数
1、相关函数介绍
首先实验一的操作是需要通过修改pintos的线程休眠函数来保证pintos不会在一个线程休眠时忙等待。
1)用到的相关文件:
pintos/src/devices目录:
timer.h, timer.c
pintos/src/threads目录:
thread.h, thread.c
2)thread.h定义了一个thread的结构体用于存储线程的信息
其中enum thread_status这个枚举类型的变量表示这个线程现在所处的状态
3)timer.c中实现了线程休眠的函数thread_sleep,当线程休眠时必须保证中断是打开的。当前执行进程调用timer_sleep(ticks)
时,函数通过不断轮询检查经过时间是否达到ticks,若还没达到则调用thread_yield函数,达到了ticks就会结束休眠。这个函数作用是实现让某个线程睡眠ticks时间,即让该线程暂时放弃CPU。ASSERT作用是若语句不为真则退出。
4)thread_yield函数会把当前线程放进ready队列,并调度下一个线程,线程调度时要保证中断关闭。Thread_yield函数只是把线程放进调度队列,然后切换线程,此时休眠线程状态是ready,在一个tick内依然有可能会被调度,继续消耗cpu时间,没有完全把时间让给别的进程,这样就违反了线程休眠的原则,造成了忙等待。
其中,schedule()是专门负责线程切换的函数,执行了以后会把当前线程放进队列里并调度出下一个线程
5)pintos默认每一个ticks调用一次时间中断。即每一个线程最多可以占据CPU一个ticks的时长。每隔一段时间操作系统必须获得CPU时间进行进程调度等工作,操作系统是通过中断来获得CPU时间。在timer中断产生时这个函数就会被调用
6)timer_ticks()函数, 就是获取ticks的当前值返回,其中,intr_get_level返回了intr_level的值;intr_disable的作用是返回关中断,然后返回中断关闭前的状态。所以禁止当前行为被中断, 保存禁止被中断前的中断状态(用old_level储存)
enum intr_level这个枚举定义了中断是开还是关,在原子操作中必须保证中断是关的。
7)thread_foreach(thread_action_func *func, void *aux) 遍历当前ready queue中的所有线程,并且对于每一个线程执行一次func操作。这里的func是一个任意给定函数的指针,参数aux则是你想要传给这个函数的参数。pintos中,所有ready的线程被保存在一个链表中。这个函数做得不过是遍历了一遍链表而已。这个函数只能在中断关闭的时候调用。
8)thread_block()和thread_unblock(thread *t)。区别在于thread_block()函数的作用是把当前占用cpu的线程阻塞掉,而thread_unblock(thread *t)函数作用是将已经被阻塞掉的进程t唤醒到ready队列中。
2、具体实验过程
函数重新实现:
实现思路: 调用timer_sleep的时候直接把线程阻塞掉,然后给线程结构体加一个成员ticks_blocked来记录这个线程被sleep了多少时间, 然后利用操作系统自身的时钟中断(每个tick会执行一次)加入对线程状态的检测, 每次检测将ticks_blocked减1, 如果减到0就唤醒这个线程。
具体代码:
/* Sleeps for approximately TICKS timer ticks. Interrupts must
be turned on. */
void
timer_sleep (int64_t ticks)
{
if (ticks <= 0)
{
return;
}
ASSERT (intr_get_level () == INTR_ON);
enum intr_level old_level = intr_disable ();
struct thread *current_thread = thread_current ();
current_thread->tic