作业

jobs 查看当前会话的作业

fg %id 调到前台 bg %id 调到后台 ctrl+z 挂起

会话、进程组

$ proc1 | proc2 &
$ proc3 | proc4 | proc5

此时,这个用户登陆所在的会话,shell 是会话的首进程,也是独立的进程组。shell 创建了 proc1 和 proc2 两个程序的进程组(后面三个同理)

终端的输入指向的前台进程组(原来是 shell,后面变成那仨的),每个终端和会话关联,如果终端断开,整个会话都会结束(告诉会话首进程一个信号)

一些系统调用

fork

execve(最全的)用一个新的可执行程序覆盖自身进程空间(自己也不存在了)

信号

针对进程的异步通知机制

信号可以由一个进程/内核发送给另一个进程(组)。大多数默认信号处理为终止进程

进程并不能预先知道信号的准确发生时刻,UNIX 的信号没有排队机制(两个相同的信号可能会合并)

signal signication

  • Ctrl+C 发送的是 SIGINT 信号
  • Ctrl+\ 发送 SIGQUIT 信号
  • Ctrl+Z SIGSTP,默认暂停
  • bg/fg 发送 SIGCONT,默认继续
  • kill 无参数的时候 SIGTERM
  • sleep SIGALRM
  • 通知子进程终止 SIGCHLD
  • 用户终端断开 SIGHUP (hand up)

有些信号是不能忽略的,有些也是不能替换处理函数的

子进程会继承父进程的信号处理动作

进程和文件系统

内核中:

  • 文件表:打开状态和偏移量,v-node 指针
  • v-node 表:缓存 inode,当前文件长度

每个进程独立维护:文件描述符表:fd 和文件指针(指向文件表某一项)。优先使用最小的可用的文件描述符

dup 系统调用:复制文件描述符,在文件描述符表里面复制表项(文件指针指向同一个文件表)

dup2 可以指定新复制到的 fd 号。如果已经占用,那就先 close 掉旧的

假如两个独立进程各自打开同一个文件:两个进程上各自有两个进程表项,内核中给每个进程分配不同的文件表,指向的同一个 v 节点表。这样如果两个进程没有同步手段,则会写入混乱(同一个位置写两次)

假如 fork 了,父进程的文件描述符表也精确复制,指向的是相同的文件表,即共享打开的文件。此时不会发生同一个位置写两次的情况发生(但是顺序可能会乱)

重定向的实现

假设 shell 需要执行一个 cat 命令,该命令要求重定向标准输入和输出:

  1. 先 fork 出来子进程
  2. open 输入的文件
  3. STDIN close
  4. dup 输入文件的描述符(最小可用的就是 STDIN,即为替换操作)
  5. close 输出文件的描述符
  6. 标准输出同理
  7. execve cat,此时不改变文件描述符表了

管道的实现

假设 shell 需要管道连接两个命令 A | B

  1. 使用 pipe 创建一个管道,得到两个 fd
  2. fork,此时子进程也拥有这两个 fd
  3. 第一个子进程:
    1. 管道读端 close
    2. 把写端 dup 到 STDIN 位置
    3. execve 执行
  4. 再 fork
  5. 第二个子进程:
    1. 管道写端 close
    2. 把读端 dup 到 STDOUT 位置
    3. execve 执行
  6. waitpid 等两个仔死了继续执行

进程与权限

登录的 shell 的 EUID 和 EGID 决定了用户通过它于系统交互时的权限

特殊权限

UID 是文件拥有者,EUID 是命令以谁的权限在运行。一般情况这两个是同一个东西,但是可以设置不一样:

  • setuid:作用于普通文件,进程的 EUID 被设置为文件拥有者的 UID
  • setgid:与 setuid 类似,但作用的是组权限
  • 粘住:当目录设置了粘住位时,​​只有文件所有者、目录所有者或 root 用户才能删除或重命名其中的文件​​,即使其他用户有写权限。
    • 系统临时目录 /tmp 或 /var/tmp,所有用户可写入,但无法随意删除他人文件。 ​