marp: true theme: default paginate: true _paginate: false header: '' footer: '' backgroundColor: white

第一讲 操作系统概述

第五节 实践:试试UNIX/Linux



向勇 陈渝 李国良 任炬



2024年春季


UNIX/Linux?

  • Linux
    • Ubuntu、Fedora、SuSE、openEuler
    • 麒麟 统信
  • Windows with WSL (Windows Subsystem of Linux)
  • MacOS with UNIX shell

bg right 90%


UNIX/Linux?

  • 开放源码,有很好的文档,设计简洁,使用广泛
  • 如果你了解Linux的内部情况,学习ucore/rcore会有帮助。

bg right 100%


Try UNIX/Linux

  • shell

    • bash 基本的shell环境
    • fish 强调交互性和可用性
    • zsh 带有自动补全、支持插件
    • starship 轻量、迅速、可无限定制
  • program

    • ls, rm,gcc,gdb, vim ...

bg right:40% 100%


UNIX/Linux提供哪些服务?

  • 进程(正在运行的程序)
  • 内存分配
  • 文件内容、文件名、目录
  • 访问控制(安全)
  • 许多其他的:用户、IPC、网络、时间

bg right 100%


UNIX/Linux提供的应用/内核接口?

  • APP -> C lib -> Syscall -> Kernel

  • 用C语言,来自类UNIX OS

        fd = open("out", 1);
        write(fd, "hello\n", 6);
    
  • 看起来像函数调用,其实是系统调用

  • 核心的系统调用数量并不多

bg right:50% 100%


UNIX/Linux提供的应用/内核接口?

系统调用名含义
int fork()创建一个进程,返回子进程的PID。
int exit(int status)终止当前进程;报告状态给执行wait()系统调用的父进程。没有返回。
int wait(int *status)等待子进程退出;退出状态为 *status ;返回子进程的PID。
int kill (int pid)终止进程号为PID的进程。返回0表示成功,或-1表示错误。
int getpid()返回当前进程的PID。

UNIX/Linux提供的应用/内核接口?

系统调用名含义
int sleep(int n)暂停n个时钟周期。
int exec(char *file,char *argv[])用参数加载文件并执行;仅当出错时返回。
char *sbrk(int n)将进程内存增加n个字节。返回新内存的开始地址。
int open(char *file,int flags)打开文件;标志flag表示文件操作的读/写属性;返回一个fd(文件描述符)。
int write(int fd,char *buf,int n)从buf向文件描述符fd写入n个字节;返回n。

UNIX/Linux提供的应用/内核接口?

系统调用名含义
int read(int fd,char *buf,int n)将n个字节读入buf;返回读取的数字;如果文件结束,则为0。
int close(int fd)释放打开的描述符为fd的文件。
int dup(int fd)返回一个新的文件描述符,引用与文件描述符相同的文件。
int pipe(int p[])创建一个管道,将读/写文件描述符放在p[0]和p[1]中。
int chdir(char *dir)更改当前目录。

UNIX/Linux提供的应用/内核接口?

系统调用名含义
int mkdir(char *dir) 创建一个新目录。
int mknod(char *file, int, int)创建一个设备文件。
int fstat(int fd,struct stat *st)将文件fd的元信息放入*st
int stat(char *file,struct stat *st)将文件 *file 的元信息放入 *st
int link(char *file1,char *file2)为文件file1创建另一个名称(file2)
int unlink(char *file)删除文件。

UNIX/Linux应用

分析一些非常简单的小程序

进程相关

fork.c exec.c forkexec.c

文件系统相关

list.c open.c echo.c copy.c

进程间通信相关

pipe1.c pipe2.c redirect.c

bg right:55% 100%


UNIX/Linux应用 - open

  • 例如:open.c,创建一个文件

    $ open $ cat output.txt

  • open() 创建一个文件,返回一个文件描述符(File Descriptor,简称FD,或-1表示错误)。

  • FD是正整数,代表一个打开的文件

  • 进一步细节可以参考UNIX/Linux手册,例如执行 "man 2 open"

  • man的第一个参数:1 表示查shell命令;2 表示查系统调用


UNIX/Linux应用 - copy

例如:copy.c,将输入文件内容复制到输出文件中 从输入文件中读取字节内容,将其写入输出文件中

    $ copy

read()和write()是系统调用 read()/write()第一个参数是"文件描述符"(fd) 传递给内核,告诉它要读/写哪个 "打开的文件"


UNIX/Linux应用 - copy

  • 一个文件描述符对应一个打开的文件

  • 一个进程可以打开许多文件,有许多描述符

  • 缺省情况:

    • 文件描述符0是 "标准输入", 通常是键盘
    • 文件描述符1是 "标准输出",通常是显示器
  • read()第二个参数是指向要读取的缓冲区的指针,缓冲区的大小由第三个参数指定

  • 文件访问模式:open -> read/write -> close


UNIX/Linux应用 - fork

fork()系统调用创建一个进程的副本(子进程)

  • 复制:指令、数据、寄存器、文件描述符、当前目录
  • 形成"父 "和 "子 "进程

bg right:50% 100%


UNIX/Linux应用 - fork

  • 区别:fork()在父进程中返回一个pid,在子进程中返回0。

  • pid(进程ID)是一个整数,内核给每个进程一个不同的pid

  • 因此,fork.c中父子进程的fork()返回值pid不同

  • 父子进程的执行差别就体现在对fork()返回值pid的判别上

    • 0代表子进程,否则代表父进程

bg right:40% 100%


UNIX/Linux应用 - exec

  • 怎样才能在这个进程中运行一个新程序呢?

  • 例如:exec.c,用一个可执行文件代替调用进程。

exec(filename, argument-array) argument-array保存命令行参数;exec传递给main()

exec()用新执行文件取代当前进程

  • 丢弃已有指令和数据内存空间
  • 从文件中加载新执行程序的指令和数据

UNIX/Linux应用 - forkexec

例如:forkexec.c,fork()一个新进程,exec()一个程序。

常见的UNIX APP执行模式

  • fork():创建子进程
  • exec():子进程中执行新程序
  • wait():父进程等待子进程完成
  • exit():进程退出

bg right:45% 100%


UNIX/Linux应用 - redirect

例子:redirect.c,重定向一个命令的输出

  • 缺省情况下,文件描述符为1的文件是屏幕输出
  • open()总是选择值最小的未使用的文件描述符
  • 通过 close(1) + open(...)操作,设定"output.txt"的文件描述符为1
  • exec(...)系统调用保留了文件描述符,执行echo命令后,它的屏幕输出将被重定向到"output.txt"
    $ redirect
    $ cat output.txt

分析UNIX/Linux类应用 - pipe2

  • 例子pipe2.c,进程间通信。
  • shell如何使用管道机制 "|"
    $ ls | grep x

pipe()系统调用创建了两个fd

  • 从fd[1]写入,从fd[0]中读取

bg right:50% 100%


UNIX/Linux应用

一些值得思考的问题:

  • 为什么是这些I/O和进程的抽象?为什么不是其他的东西?
  • 为什么要提供一个文件系统,而不让程序以自己的方式使用磁盘?
  • 为什么read/write文件用FD而不是文件名?
  • 为什么文件是字节流,而不是磁盘块或格式化记录?
  • 为什么不把fork()和exec()结合起来?

UNIX的设计很好用,但也存在其他的设计


分析UNIX/Linux类应用

小结

  • 介绍了UNIX的I/O、文件系统和进程的抽象
  • 这些接口很简洁,只有整数和I/O缓冲区
  • 这些抽象结合得很好,例如,I/O重定向