作业
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
无参数的时候 SIGTERMsleep
SIGALRM- 通知子进程终止 SIGCHLD
- 用户终端断开 SIGHUP (hand up)
有些信号是不能忽略的,有些也是不能替换处理函数的
子进程会继承父进程的信号处理动作
进程和文件系统
内核中:
- 文件表:打开状态和偏移量,v-node 指针
- v-node 表:缓存 inode,当前文件长度
每个进程独立维护:文件描述符表:fd 和文件指针(指向文件表某一项)。优先使用最小的可用的文件描述符
dup
系统调用:复制文件描述符,在文件描述符表里面复制表项(文件指针指向同一个文件表)
dup2
可以指定新复制到的 fd 号。如果已经占用,那就先 close 掉旧的
假如两个独立进程各自打开同一个文件:两个进程上各自有两个进程表项,内核中给每个进程分配不同的文件表,指向的同一个 v 节点表。这样如果两个进程没有同步手段,则会写入混乱(同一个位置写两次)
假如 fork 了,父进程的文件描述符表也精确复制,指向的是相同的文件表,即共享打开的文件。此时不会发生同一个位置写两次的情况发生(但是顺序可能会乱)
重定向的实现
假设 shell 需要执行一个 cat 命令,该命令要求重定向标准输入和输出:
- 先 fork 出来子进程
- open 输入的文件
- STDIN close
- dup 输入文件的描述符(最小可用的就是 STDIN,即为替换操作)
- close 输出文件的描述符
- 标准输出同理
- execve cat,此时不改变文件描述符表了
管道的实现
假设 shell 需要管道连接两个命令 A | B
- 使用
pipe
创建一个管道,得到两个 fd - fork,此时子进程也拥有这两个 fd
- 第一个子进程:
- 管道读端 close
- 把写端 dup 到 STDIN 位置
- execve 执行
- 再 fork
- 第二个子进程:
- 管道写端 close
- 把读端 dup 到 STDOUT 位置
- execve 执行
- waitpid 等两个仔死了继续执行
进程与权限
登录的 shell 的 EUID 和 EGID 决定了用户通过它于系统交互时的权限
特殊权限
UID 是文件拥有者,EUID 是命令以谁的权限在运行。一般情况这两个是同一个东西,但是可以设置不一样:
- setuid:作用于普通文件,进程的 EUID 被设置为文件拥有者的 UID
- setgid:与
setuid
类似,但作用的是组权限 - 粘住:当目录设置了粘住位时,只有文件所有者、目录所有者或 root 用户才能删除或重命名其中的文件,即使其他用户有写权限。
- 系统临时目录
/tmp
或/var/tmp
,所有用户可写入,但无法随意删除他人文件。
- 系统临时目录