L1:操作系统概论

lab通关记录

MIT-6.828实验通关记录

操作系统概论

总览

  • 目标

    • 操作系统设计与实现
    • 手把手建立小os
  • os的功能

    • 运行程序
    • 抽象硬件
    • 多个应用程序之间多路复用硬件
    • 抽象应用程序来包容bug?
    • 允许程序之间共享信息
    • 高性能
  • os设计

    • 小:管理图书馆那样管理
    • 大:硬件抽象
  • 组织:结构图

    • CPU,内存,硬盘,C程序的内核,用户程序:vi,gcc,c
    • 关心系统接口和内核结构
  • os内核典型的能提供哪些服务?

    • 进程
    • 内存分配
    • 文件内容
    • 目录,文件名
    • 安全性
    • 其他:用户,IPC,网络,时间,中断
  • os抽象?

    • 应用程序只能通过system call来使用os

    • 例如:UNIX:

      1
      2
      3
      fd = open("out", 1);
      write(fd, "hello\n",6);
      pid = fork();
  • 为什么os设计或实现会难/有趣?

    • 环境不友好:快速h/w,难debug
    • 底层,高效,逐步抽象
    • 强大且简单
    • 功能抽象
    • 行为互动:CPU级别vs内存分配
    • 开放式问题:安全性,性能
  • 你会。。算了不写了

课程结构

  • https://pdos.csail.mit.edu/6.828
  • 课程
    • os知识
    • 传统os:xv6的细节
    • xv6的编程作业
    • 一些最近(当然现在不是了)的论文
  • 实验:JOS,一个小的os
    • 5+lab的构建
    • 内核接口:接触硬件,保护硬件(通过抽象)
    • 用户级别的同权限的lib:fork. exec, pipe等
    • 构建环境:gcc,qemu(模拟硬件的虚拟机)
    • lab1可以直接开始思考了
  • 2个考试:随便吧

system calls 的介绍

  • 6.828主要就是完成这部分,你应该知道如何使用这些接口(在UNIX系的系统下)

  • 注意:对于命令不理解或者没有这个命令,使用man 和你的翻译来确定和进一步了解!

  • 例子:ls

    • 跟踪你的ls命令执行(这两种系统我都只要ls一个命令就行了)
      • OSX: sudo dtruss /bin/ls
      • Linux: strace /bin/ls
    • 有很多这样的system calls(系统调用)
  • 例子:cat//只要明白功能,会使用cat就行了

    1
    2
    3
    4
    5
    6
    cat copy.c//前提是这个文件已经存在
    cc -o copy copy.c//编译
    ./copy//使用

    //copy.c的功能:读取一行,写一行
    //note:用C写
    • R/W第一个参数是fd(文件描述符),是调用open的返回值,告诉内核打开的文件的位置,0代表了“标准输入”,1代表“标准输出”,当然你

    • sudo dtruss ./copy

      1
      2
      3
      //结果举例:
      read(0x0, "123\n\0", 0x80) =40
      write(0x1, "123\n@\213\002\0", 0x4) =40
  • 创建文件//同样的cat使用即可

    1
    2
    3
    4
    5
    6
    cat open.c
    cc -o open open.c
    ./open
    cat output.txt
    //note:creat()调用open()
    //note:这些代码忽略错误,一般不要这么写
  • 更有趣的程序:shell(就是你的terminal )

    • 通过它你才能使用命令,和内核交互,进行系统调用

    • 一些例子//查或者实践,得到这些命令的意义

      1
      2
      3
      4
      ls
      ls >junk
      ls |wc -l
      ls |wc -l >junk
    • shell里面的命令很多功能也很强大,你可以当作一门新的语言来稍作学习

    • 同时,通过这些命令,你也能写一个脚本来在shell上执行

      1
      2
      3
      4
      5
      cat > script
      echo one
      echo two//按ctrl+c退出
      sh < script//使用该脚本
      //哈哈我第一次把最后一行命令也输了进去,然后无限循环
    • 以上的命令使用了ls, cat, pipe, wc这些常用的命令,了解他们的功能和配合

  • 让我们看看一个简单的sh.c执行过程:明白fork,wait,execv,pipe功能和配合即可

    • main()

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      首先编译为一棵树,然后执行main进程:getcmd, fork, wait
      执行子进程:parsecmd, runcmd

      为什么fork()来产生子进程?
      这是一种组织方式,以后就知道了

      fork()功能?
      1.复制:
      复制用户的内存
      分组值内核状态,fd
      因此子进程几乎和父进程相同:如果不了解进程,你可以先思考:进程即“进行的程序”,一个进程在机器上需要哪些东西才能称之为进程?然后在后续的学习中验证你的想法
      2.子进程pid不同于父进程,fork()函数返回子pid,而子进程pid我们让它返回0,这样进程使用时候来区分
      3.紧接着运行,然后根据系统的调度(你可以认为随机,因为你管不着)两个进程的切换

      wait()是什么?
      父进程fork()后会wait(),等待子进程结束后得到一些信息,给一个实例:
      #include <stdio.h>
      #include <unistd.h>
      #include <sys/types.h>
      #include <sys/wait.h>

      int main(void)
      {
      pid_t p1 = -1;
      pid_t ret = -1;
      int status = 0;

      p1 = fork();

      if(p1 == 0)
      {
      //这里一定是子进程
      printf("子进程,pid = %d.\n", getpid());
      }
      else if(p1 > 0)
      {
      //这里一定是父进程
      printf("parent.\n");
      ret = wait(&status);

      printf("子进程已经被回收,子进程pid = %d.\n", ret);
      printf("子进程是否被正常回收: %d.\n", WIFEXITED(status));
      }

      else
      {
      //这里一定是fork出错了
      perror("fork");
      return -1;
      }

      return 0;
      }

      如果子进程在父进程call wait()之前结束了怎么办?
      你猜

    • runcmd():就是跟你shell有关的调用

      • 是一种简单的,重定向,管道概念的cmd类型
      • 通过parsecmd()执行转换树
      • 调用execvp(cmd, args)
      • 即从内存加载可执行文件到进程里
      • 跳回main程序//只有出错才有返回值
      • 此时:子进程对execvp没有感知,父进程仍然等待子进程
    • runcmd如何处理IO重定向?例如:

      1
      echo hello > junk
      • 为什么重定向?子进程的缘故

      • 哪里重定向?shell中的子进程

      • 改什么?由于不同进程的不同fd表,所以改fd:从0改为1

      • 是Parsecmd()的作用:从两个节点开始产生树

        1
        2
        cmd->type='>', cmd->file="junk", cmd->cmd=...
        cmd->type=' ', cmd->argv=["echo", "hello"]
      • open(),dup2()产生了fd=1(子进程)

    • 为什么fork要和exec区分?

      • 想想fork干了什么,exec干了什么,你就知道两个干的不是一件事
    • 如何实现pipe?

      ls |wc -l

    • 内核提供pipe抽象在fd表(告诉你pipe的一些实现)

      1
      2
      fd[2]:一个写fd,一个读fd
      还有一个buffer
    • 具体例子:pipe1.c:直到数据可用时读,直到buffer满时写

    • 因此,pipe的功能:进程之间通过fork保存了fd来成功通信

    • 对于
      ls |wc -l,shell做的事
          - 创建管道
          - fork
          - 设置fd为1来保证写
          - 执行ls:写入buffer
          - 设置fd为0来保证读
          - 执行wc:读buffer
          - 等待
      ps:写动作会在末尾加一个EOF代表结束
      
    • 不用担心,这些东西告诉你抽象的过程,后续的具体实现都会涉及

Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2020-2024 环烷烃
  • Visitors: | Views:

我很可爱,请我喝一瓶怡宝吧~

支付宝
微信