深入浅出进程关系分析Job Control(一)
来源:互联网 发布:2017年泰国耽美网络剧 编辑:程序博客网 时间:2024/06/10 16:02
一:写在前面
笔者最近在研究基于kernel 4.14
的Qemu-kvm
环境的搭建,并做GDB
源码追踪。为此笔者补充了很多知识,例如:initrfs
,initramfs
,kernel
启动过程等,参考的资料主要来源自与kernel官方文档
,linux官方网站
,stackoverflow
精彩回答,及CSDN
一些优质博文。本文主要着眼点还是process_relation
。
二:理论先行
2.1 Terminal Logins
现在的linux
都是使用systmd
来实现终端登录了,关于这点会在别的文章一探究竟。这里还是着眼于经典的实现方式。IBM 中关于systemd的论述,本文如果探究systmd
将又是一番非常费事的差事,
以前的系统启动的时候,由init
进程(此init位于真正的根文件系统上)读取/etc/ttys
并为其中每一个允许用户登录的设备条目创建一个子进程并执行getty
。然后由getty
打开终端设备,并提示我们输入用户名。当我们输入完用户名之后,getty
会exec
login
,login
会继续调用getpwnam
获取password
文件的信息,之后调用 getpass
去提示我们输入密码,当我们键入回车的时候调用crypt
进行加密并和password
文件中的信息进行对比,如果我们输入的密码是错误的,那么login
调用exit
,此子进程结束的状态会通知init
,然后由其重复之前的操作。可惜,笔者基于fedora 27进行相关实验,所以上面提到的一些操作已经被废弃了。
正常的login
会再进行很多“初始化”工作,这里不赘述。但是有一个疑问:
File descriptors 0, 1, and 2 for our login shell are set to the terminal device.
思考一:linux中一切设备皆文件,这句话是指shell打开终端对应的文件,并且将FD 0,1,2分别映射到该文件上吗?
2.2 Network Logins
在系统启动的时候,init
会fork
一个shell
去执行/etc/rc
的脚本,由该脚本启动的一个服务inetd
,去捕获来自远程telnet client
的登录请求。inetd
会fork
一个子线程并执行telnetd
,接着telanetd
会再次fork
形成两个进程,一个负责处理网络来的信息,一个执行Login
,这两个进程通过telanetd
打开的pseudo terminal device
进行联系。如果我们正常登陆的话,后面进行的操作和前面Terminal Logins
相近。最后比较重要的一个总结:
we have a login shell with its standard input, standard output, and standard error connected to either a terminal device or a pseudo terminal device.
2.3 Process Groups
#include <unistd.h>pid_t getpgid(pid_t pid);Returns: process group ID if OK, −1 on errorint setpgid(pid_t pid, pid_t pgid);Returns: 0 if OK, −1 on error
比较重要的几个概念:
Each process group can have a process group leader. The leader is identified by its process group ID being equal to its process ID.
The process group still exists, as long as at least one process is in the group, regardless of whether the group leader terminates.
The last remaining process in the process group can either terminate or enter some other process group
Setpgid
只能设置进程自身,或者该进程的子进程。pid
为0时,代表调用setpgid
的进程,而pgid
为0时,pid
的值将会被用在pgid
上。这里对应实验一,确定下我的猜想。
2.4 Sessions
#include <unistd.h>pid_t setsid(void);Returns: process group ID if OK, −1 on errorpid_t getsid(pid_t pid);Returns: session leader’s process group ID if OK, −1 on error
Sessions由多个process group组成,当不是Process group leader的进程调用setsid
时,会有以下几点保证:
- The process becomes the session leader of this new session. (A session leader is the process that creates a session.) The process is the only process in this new session.
- The process becomes the process group leader of a new process group. The new process group ID is the process ID of the calling process.
- The process has no controlling terminal. (We’ll discuss controlling terminals in the next section.) If the process had a controlling terminal before calling setsid, that association is broken.
如果一个进程是Group leader,调用该函数会返回错误。所以一般由父进程fork
新的子进程之后终止,并由该子进程调用setsid
建立新的会话,此时会话的session ID
就是该子进程的process ID
也是其process group ID
。这里对应实验二,来确定我的理解是否正确。
2.5 Controlling Terminal
- A session can have a single controlling terminal.
- The session leader that establishes the connection to the controlling terminal is called the controlling process.
- The process groups within a session can be divided into a single foreground process group and one or more background process groups.
- If a session has a controlling terminal, it has a single foreground process group and all other process groups in the session are background process groups.
一般登录的时候就会自动建立和treminal
的联系,linux使用open without O_NOCTTY
(session leader打开的第一个终端设备文件)或者TIOCSCTTY ioctl command
两种方式显示的建立Controlling Terminal。/dev/tty
是该终端所对应的文件。
2.6 Tcgetpgrp, tcsetpgrp, and tcgetsid Functions
#include <unistd.h>pid_t tcgetpgrp(int fd);Returns: process group ID of foreground process group if OK, −1 on errorint tcsetpgrp(int fd, pid_t pgrpid);Returns: 0 if OK, −1 on error#include <termios.h>pid_t tcgetsid(int fd);Returns: session leader’s process group ID if OK, −1 on error
tcgetpgrp
用来得到fd
指定的terminal所对应的前台工作组的Group ID。而tcsetpgrp
只能被session leader使用用来设置前台工作组的Group ID,这个ID必须隶属于同一个session。这里的概念都好理解,不像前面有些地方模棱两可,不做实验无法确定。
思考二:是否任何时候Session id都和session leader’s process id or process group id 相等?
2.7 Job Control
This feature allows us to start multiple jobs (groups of processes) from a single terminal and to control which jobs can access the terminal and which jobs are run in the background.
上面的话总结了job control的作用,大家平时都在用job control,这里我不赞同某些博主说job control没什么作用的观点,因为现在我们使用的shell都默认开启job control,所以平时我们使用&
来后台运行某些任务的时候,就已经在使用该特性了。
由terminal driver根据ctrl+c
或者ctrl+z
等产生相应的信号发送给前台工作组,后台工作组不受该信号影响。对于终端的输入,后台进程尝试读取时,会收到终端所发送的SIGTTIN
信号,使其停止。如果想把后台进程放置前台使用fg %num
,这里num
从1开始。
2.8 Shell Execution of Programs
此处笔者使用fedora 27,kernel 4.13来做相关实验,Shell默认自带Job Control
。
#测试1[root@localhost ~]# ps -o pid,ppid,pgid,sid,comm PID PPID PGID SID COMMAND 1425 1424 1425 1425 bash 1942 1425 1942 1425 ps[root@localhost ~]# #测试2[root@localhost ~]# ps -o pid,ppid,pgid,sid,tpgid,comm PID PPID PGID SID TPGID COMMAND 1425 1424 1425 1425 1941 bash 1941 1425 1941 1425 1941 ps
TPGID
是terminal的一个属性,其值取自前台工作组的Group ID。所以严格上来说,Process ID不应该和TPGID
有直接的关系。充其量说前台工作组的Prosess Leader的Process ID和TPGID
相等。
#测试3[root@localhost ~]# ps -o pid,ppid,pgid,sid,comm &[root@localhost ~]# PID PPID PGID SID COMMAND 1425 1424 1425 1425 bash 5743 1425 5743 1425 ps[1]+ Done ps -o pid,ppid,pgid,sid,comm#测试4[root@localhost ~]# ps -o pid,ppid,pgid,sid,tpgid,comm &[1] 1955[root@localhost ~]# PID PPID PGID SID TPGID COMMAND 1425 1424 1425 1425 1425 bash 1955 1425 1955 1425 1425 ps[1]+ Done ps -o pid,ppid,pgid,sid,tpgid,comm[root@localhost ~]#
在后台运行的时候,测试2
与测试4
形成对比,可以看出来测试2
中TPGID
为ps
指令的Process Group ID
(注意我没说是Process ID
,虽然两个数值一样)。而在测试4
中为bash
的进程组ID,这样的结果和上面加黑的字体所述是一致的。
[root@localhost ~]# ps -o pid,ppid,pgid,sid,comm | cat PID PPID PGID SID COMMAND 1425 1424 1425 1425 bash 1970 1425 1970 1425 ps 1971 1425 1970 1425 cat[root@localhost ~]# ps -o pid,ppid,pgid,sid,comm | cat &[1] 5741[root@localhost ~]# PID PPID PGID SID COMMAND 1425 1424 1425 1425 bash 5740 1425 5740 1425 ps 5741 1425 5740 1425 cat[1]+ Done ps -o pid,ppid,pgid,sid,comm | cat[root@localhost ~]#[root@localhost ~]# cp /usr/bin/cat /usr/bin/cat1[root@localhost ~]# ps -o pid,ppid,pgid,sid,comm | cat | cat1 PID PPID PGID SID COMMAND 1425 1424 1425 1425 bash 5735 1425 5735 1425 ps 5736 1425 5735 1425 cat 5737 1425 5735 1425 cat1[root@localhost ~]#
cat
,ps
和cat
都为bash
的子进程,无论是否是在前台执行还是后台执行,这里与不支持job control
的shell
得到的结果不同,两者fork子进程的方式有很大区别。
[root@localhost ~]# cat > temp.foo &[1] 1979[root@localhost ~]#shuru[1]+ Stopped cat > temp.foo[root@localhost ~]#
后台工作组尝试对Control Terminal
读的时候,会收到来自该终端的SIGTTIN
从而被终止。
2.9 Orphaned Process Groups
The POSIX.1 definition of an orphaned process group is one in which the parent of every member is either itself a member of the group or is not a member of the group’s session. Another way of saying this is that the process group is not orphaned as long as a process in the group has a parent in a different process group but in the same session.
POSIX.1明确定义孤儿组的概念:只要该组至少有一个成员的父进程位于同一会话的别的组,那么该组就不是孤儿组。所以孤儿组要么,组里互相是父子关系,要么父进程不属于同一个会话,或者两种情况都有。同时,孤儿组里的进程都会被发送SIGHUP信号和SIGCONT信号。同时需要注意如果孤儿组里面的进程位于后台进程组却又读取Controlling Terminal
的话,SIGTTIN
信号将不会产生:
the process group of the reading process is orphaned, then the signal is not generated; instead, the read operation fails with errno set to EIO.
三:实验部分
题目一:
设计一段程序,设置子进程的process group id,使其子程序成为该group leader并考虑竞态的发生。
题目二:
setsid
是否会自动的设置调用该函数的进程为the new group’s leader?
题目三:
Write a small program that calls fork and has the child create a new session. Verify that the child becomes a process group leader and that the child no longer has a controlling terminal.
NOTE:避免篇幅过长,实验部分单独记录
- 深入浅出进程关系分析Job Control(一)
- 《深入浅出数据分析》笔记一
- 深入浅出--Rxjava源码分析<一>
- job control的管理
- Linux系统--job control
- Linux系统--job control
- MapReduce Job Control
- 作业控制( Job control )
- ctrl+c不能终止进程(busybox提示can't access tty.job control
- ctrl+c不能终止进程(busybox提示can't access tty.job control )
- ctrl+c不能终止进程(busybox提示can't access tty.job control
- Windows进程分析管理器:进程与父进程关系
- 创建进程,分析父子进程关系以及结束进程。
- Linux下的Job Control
- Linux 工作管理 job control
- linux job control学习整理
- Linux工作管理(job control)
- 深入浅出Hibernate(二)多对一关系映射
- 【开发工具】推荐一款超快的安卓模拟器-genymotion
- css中元素不可见的几种办法
- [C]判断素数
- Handler在Activity和Fragment中的内存泄露问题
- Python多元线性回归-sklearn.linear_model,并对其预测结果评估
- 深入浅出进程关系分析Job Control(一)
- typedef的用法总结
- curl安装与命令使用 win+linux
- java list 转 树形json 递归效率对比
- spring1 配置方式注入
- RocketMQ原理解析-producer 2.如何发送消息
- 使用canvas绘制风景时钟
- 【运维】浅识监控
- 解决跨域问题的8种方案(最新最全)