程序锅

  • 首页
  • 分类
  • 标签
  • 归档
  • 关于

  • 搜索
基础知识 Etcd LeetCode 计算机体系结构 Kubernetes Containerd Docker 容器 云原生 Serverless 项目开发维护 ELF 深入理解程序 Tmux Vim Linux Kernel Linux numpy matplotlib 机器学习 MQTT 网络基础 Thrift RPC OS 操作系统 Clang 研途 数据结构和算法 Java 编程语言 Golang Python 个人网站搭建 Nginx 计算机通用技术 Git

MIT 6.828 课程 | HW5-CPU alarm

发表于 2019-11-25 | 分类于 MIT6.828 | 0 | 阅读次数 3254

在这个实验中,我们将会向xv6里面添加一个特性,这个特性将会定期发出一个警告当一个进程在使用CPU time的时候。这对compute-bound 进程来说是相当有用的,因为我们可以限制他们消耗CPU的时间,或者对于那些想要定期的行为的进程来说也是很有用的。更加普遍的来说,你将会实现一个用户级的中断错误处理的基本方式,而这跟HW4这个实验很相似(Hint:在HW4中我们延迟了页面分配的时间点,而这会产生一个page fault,我们主要是在对这个page fault进行处理)。

在这个实验中,我们需要新增一个alarm system call。如果一个应用程序调用了alarm(n, fn),那么在程序消耗n个”tick“的CPU时间之后(tick在xv6中是一个相当随意的单元时间,由硬件时间产生中断的评率决定),kernel会调用函数fn。需要注意的是:当fn返回之后,应用程序将会从它之前离开的地方重新开始(Hint:这一步需要用到栈tf)。

综合上述,简单来说我们需要实现的就是类似定时器一样的东西,它会定时执行一条函数。那么下面我们根据homework中给出的代码和提示来完成。

首先是在alarmtest.c中添加如下代码:

#include "types.h"
#include "stat.h"
#include "user.h"

void periodic();

int
main(int argc, char *argv[])
{
  int i;
  printf(1, "alarmtest starting\n");
  alarm(10, periodic);
  for(i = 0; i < 25*500000; i++){
    if((i % 250000) == 0)
      write(2, ".", 1);
  }
  exit();
}

void
periodic()
{
  printf(1, "alarm!\n");
}

上述添加的代码中会调用alarm(10, periodic),而这个调用的意思是让kernel每隔10ticks调用一次periodic()。添加完上述代码之后,我们需要在Makefile文件中,添加编译项,让新添加的alarmtest.c编译成一个xv6用户程序。这些步骤和HW3中是很相似的(Hint:HW3让我们添加一个system call)。如下所示在Makefile的UPROGS中添加_alarmtest\

UPROGS=\
	......
  _alarmtest\

之后修改user.h文件,添加alarm的声明:

int alarm(int ticks, void (*handler)());

修改syscall.h和usys.S,让alarm可以调用alarm system call

// syscalll.h中添加如下
#define SYS_alarm  23

// usys.S中添加如下
SYSCALL(alarm)

接下来就是sys_alarm的实现,在sysproc.c中添加:

//hw5 CPU alarm
int sys_alarm(void){
  int ticks;
  void (*handler)();

  if(argint(0, &ticks) < 0){
    return -1;
  }

  if(argptr(1, (char **)&handler, 1) < 0){
    return  -1;
  }
  myproc()->alarmticks = ticks;
  myproc()->alarmhandler = handler;
  return 0;
}

并且在syscall.c中添加如下内容:

extern int sys_alarm(void);

static int (*syscalls[])(void) = {
		......
[SYS_alarm]   sys_alarm,
};

因为上述代码中把alarm interval和handler函数的指针存储到了struct proc中,而且我们还需要跟踪当前过了多少ticks了,所以我们还需要在proc中添加一个记录值,最终往proc.h中的struct proc中添加如下内容:

int alarmticks;              // hw5 alarmticks
void (*alarmhandler)();      // hw5 alarmhandler
int tickspassed;             // hw5 alarmticks passed

并且在proc.c的allocproc()中对tickspassed进行初始化:

found:
  p->state = EMBRYO;
  p->pid = nextpid++;
  p->tickspassed = 0; // hw5 alarmticks passed

下面就是最重要的实现了!!!!!!每一个ticks,硬件时钟都会强制中断,在trap.c的trap()中,case T_IRQ0 + IRQ_TIMER就是针对这个中断进行处理的,最终我们将这个case的代码修改为如下所示:

case T_IRQ0 + IRQ_TIMER:
    // hw5 alarmhandler
    if(myproc() != 0 && (tf->cs &3) == 3){
      struct proc *p = myproc();
      p->tickspassed ++;  // ticks need ++
      if(p->tickspassed >= p->alarmticks){// the passed ticks more and equal the ticks user set
        p->tickspassed = 0;
        tf->esp -= 4;
        (*(uint *)(tf->esp)) = tf->eip; // resume where it left off
        tf->eip = (uint)p->alarmhandler;  // handler
      }
    }
    if(cpuid() == 0){
      acquire(&tickslock);
      ticks++;
      wakeup(&ticks);
      release(&tickslock);
    }
    lapiceoi();

    break;

晚上上述代码之后,重新make,运行效果如下:

修改alarmtest.c中循环的条件

for(i = 0; i < 25*5000000; i++){
    if((i % 2500000) == 0)
        write(2, ".", 1);
}

运行make并运行之后的效果如下

总体感觉对进程这块理解还不够透彻。

卷死我
dawnguo 微信支付

微信支付

dawnguo 支付宝

支付宝

  • 本文作者: dawnguo
  • 本文链接: /archives/50
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!
# 操作系统 # OS
RPC | RPC 概念及 Thrift 简介
深入理解程序 | 静态链接的过程
  • 文章目录
  • 站点概览
dawnguo

dawnguo

215 日志
24 分类
37 标签
RSS
Creative Commons
© 2018 — 2025 程序锅
0%