进程关系

9 进程关系

9.1 简介

进程关系:每个进程都有一个父进程(初始的内核级进程通常是自己的父进程)。当子进程终止时,父进程得到通知并能取得子进程的退出状态。进程关系中主要介绍登录shell和所有从登录shell启动的进程之间的关系,而这些关系中又涉及到了信号机制。

9.2 终端登录

先说明我们登录到UNIX系统时所执行的各个程序。在早期UNIX系统,用户用哑终端(用硬连接连到主机)进行登录。中断或者是本地的(直接连接)或者是远程的(通过调制解调器来接)。在这两种情况下,登录都经由内核中的中断设备驱动程序。连到主机上的中断设备数是固定的,故同时的登录数也就有了已知的上限。

随着位映射图终端的出现,开发了窗口系统,它向用户提供了与主机系统进行交互的新方式。创建终端窗口的应用也被开发出来,它仿真了基于字符的终端,使得用户可以用熟悉的方式(通过shell命令行)与主机进行交互。

现今,某些平台允许用户在登录后启动一个窗口系统,而另一些平台则自动为用户启动窗口系统。后一种仍需要登录。

我们可以使用终端登录至UNIX系统。该过程与使用的终端类型无关。终端类型:基于字符的终端、仿真基于字符终端的图形终端,或者运行窗口系统的图形终端。

BSD终端登录

**当系统自举时,内核创建进程ID为1的进程,也就是init进程。**init进程使系统进入多用户模式。init读取文件/etc/ttys,对每个允许登录的终端设备,init调用一次fork,它所生成的子进程为exec getty程序。最后,getty对终端设备调用open函数,以读、写方式将打开终端。如果设备是调制解调器,则open可能会在设备驱动程序中滞留,直到用户拨号调整解调器,并且线路被接通。之后调用login函数进行登录。login能调用相关函数取的用户相应的文件登录项,验证用户的密码,如果密码多次错误,则调用exit函数以表示登录失败。父进程init了解到子进程的终止情况后,将再次调用fork,其后又执行getty,对此终端重复上述过程。

UNIX系统已发展到支持多个身份验证过程。很多支持PAM(Pliuggable Authentication Modules,可插入的身份验证模块)的更加灵活的方案。PAM允许管理人员配置使用何种身份验证方法来访问那些使用PAM库编写的服务。

如果应用程序需要验证用户是否具有适当的权限去执行某个服务,那么我们要么将身份验证机制编写到应用中,要么使用PAM库得到同样的功能。使用PAM的优点是:管理员可以基于本地策略、针对不同任务配置不同的验证用户身份的方法。

如果用户正常登陆,login就将完成如下工作:

将当前工作目录改为用户的起始目录
调用chown更改该终端的所有权,使登录用户成为它的所有者
将对该终端设备的访问权限改变成“用户读和写”
调用setgid及initgroups设置进程的组ID
用login得到的所有信息初始化环境:起始目录,Shell,用户名,以及一个系统默认路径
login进程更改为登录用户的用户ID并调用该用户的登录shell。
此外,它还可以选择地打印日期消息文件,检查新邮件以及执行其他一些任务

setuid是由超级用户调用的,它更改所有3个用户ID:实际用户ID,有效用户ID和保存的用户ID。

登录用户登录shell后可以运行。起始进程ID是init进程(进程ID 1),所以当此登录shell终止时,init会通知(接到SIFCHLD信号),他会对读终端重复全部上述过程。登录shell的文件描述符0,1,2设置为终端设备。

登录shell读取启动文件(如.bash_profile,bash_login,.profile,.login等)。这些启动文件通常是更改某些环境并增加更多环境变量。

  • Mac OS X终端登录

    Mac OS X部分地基于BSD,与BSD终端登录进程的工作步骤基本相同,但存在下面两点不同之处:

    init的工作是由launchd完成的。
    一开始提供的就是图形终端。

  • Linux终端登录

    Linux的终端登录非常类似于BSD。其主要区别在于说明终端配置的方式。在此不做过多介绍。

  • Solaris终端登录

    Solaris支持两种形式终端登录:

    getty方式,类似BSD登录,用于控制台。登录shell父进程为init
    ttymon登录,用于其他终端登录。登录shell父进程为ttymon

9.3 网络登录

通过串行终端登录至系统和经由网络登录至系统两者之间的主要(物理上)区别是:网络登录时,在终端和计算机之间的连接不再是点到点的。在网络登录情况下,login仅仅是一种可用的服务,这与其他网络服务(FTP、SMTP)的性质相同。

通过串行终端登录中,init知道哪些设备可用来进行登录,并为每个设备生成一个getty程序。当用网络登录,所有登录都经由内核的网络接口驱动程序,且事先并不知道将会有这样的登录。故必须等待一个网络连接请求的到达,而不是使一个进程等待每一个可能的登录。

**为使同一个软件既能处理终端登录,又能处理网络登录,系统使用伪终端的软件驱动程序,它仿真串行终端的运行行为,并将终端操作映射为网络操作,反之亦然。
**
网络终端连接过程中,使用inetd进程并使用talnetd服务等。需重点理解的是:当通过终端或网络登录时,得到一个登录shell,其标准输入,标准输出和标准错误要么连接到一个终端设备,要么连接到一个伪终端设备上。

9.4 进程组

每一个进程除了有一个进程ID之外,还属于一个进程组。进程组是一个或多个进程的集合。通常,他们是在同一个作业中结合起来的,同一个进程组中的各进程接收来自同一终端的各种信号。每个进程组有一个位于的进程组ID。每个进程组有一个组长进程。*每个进程组长可以创建一个进程组,创建该组中的进程,然后终止。只要在某个进程组中有一个进程存在,则该进程组就存在,这与其组长进程是否终止无关。从进程组创建开始到其最后一个进程离开为止的时间区间称为进程组的生命期。*某个进程组中的最后一个进程可以终止,也可以转移到另一个进程组。

一个进程只能为自己或它的子进程设置进程组ID。为减少竞争条件,fork之后调用setpgid函数,使父进程设置其子进程的进程ID,并且也是子进程设置其自己的进程ID,虽存在冗余,但可保证在父进程和子进程认为子进程已经入该进程组之前,确实已经发生。

9.5 会话

会话(session)是一个或多个进程组的集合。通常是由shell的管道将几个进程编程一组。

如果调用sersid建立新会话的进程不是一个进程组组长,则创建新会话。具体发生以下3件事:

该进程变成新会话的会话首进程(会话首进程是创建该会话的进程)。此时,该进程是新会话中的唯一进程。
该进程成为一个新进程组的组长进程。新进程组ID是调用进程的进程ID
该进程没有控制终端。如果在调用setsid之前该进程有一个控制终端,那么这种联系被切断。

会话进程是具有唯一进程ID的单个进程,故可将会话首进程的进程ID视为会话ID。

9.6 控制终端

会话和进程组还有一些其他特性:

一个会话可以有一个控制终端。通常是终端设备(在终端登录情况下)或伪终端设备(在网络登录下)
建立与控制终端连接的会话首进程被称为控制进程
一个会话中的几个进程组可被分成一个前台进程组以及一个或多个后台进程组。
如果一个会话有一个控制终端,则它有一个前台进程组,其他进程组为后台进程组
无论何时键入终端的中断键,都会将中断信号发送至前台进程组的所有进程。
无论何时键入终端的退出键,都会将退出信号发送至前台进程组的所有进程
如果终端接口检测到调制解调器(或网络)已经断开连接,则将挂断信号发送至控制进程(会话首进程)。

9.7 函数tcgetpgrp、tcsetpgrp和tcgetsid

tcgetpgrp和tcsetpgrp函数用来取得和设置前台进程ID,而tcgetsid用来让应用程序获得会话首进程的进程组ID。

9.8 作业控制

作业控制允许在一个终端上启动多个作业(进程组),它控制哪一个作业可以访问该终端以及哪个作业在后台运行。作业控制要求以下3种形式的支持:

支持作业控制shell
内核中的终端驱动程序必须支持作业控制
内核必须提供对某些作业控制信号的支持

存在3个特殊字符可使终端驱动程序产生信号,并将他们发送至前台进程组:

中断字符(delet、ctrl+c)产生SIGINT
退出字符(ctrl+\)产生SIGQUIT
挂起字符(ctrl+z)产生SIGTSTP

9.9 shell执行程序

进程并没有终端进程控制组,进程属于一个进程组,而进程组属于一个会话。会话也可能有也可能没有控制终端。

注意:使用的shell不同,创建各个进程的顺序也可能不同。

9.10 孤儿进程组

一个其父进程已终止的进程称为孤儿进程,这种进程由init进程收养。

在父进程终止时,如果该子进程停止(用作业控制)又将如何呢?子进程如何继续,以及子进程是否知道它已经是孤儿进程?
假设使用了一个作业控制shell。shell将前台进程放在(指前台进程)自己的进程组中,shell则留在自己的进程组内,子进程继承其父进程的进程组。在fork之后:

父进程睡眠5秒,这是一种让子进程在父进程终止之前运行的一种权宜之计。
子进程为挂断信号(SIGHUP)建立信号处理程序。这样就能观察到SIGHUP信号是否已发送给子进程。
子进程用kill函数向其自身发送停止信号(SIGTSTP)。这将停止子进程,类似于用于终端挂起字符(ctrl+z)停止一个前台作业。
当父进程终止时,该子进程称为孤儿进程,所以其父进程ID为1,即init进程ID。
子进程成为一个孤儿进程组的成员。孤儿进程组定义:该组中每个成员的父进程要么是该组的一个成员,要么是该组所属会话的成员。另一种描述:一个进程组不是孤儿进程组的条件是——该组中有一个进程,其父进程在属于同一会话的另一个组中。如果进程组不是孤儿进程组,则属于同一会话的另一个组中的父进程就有机会重新启动改组中停止的进程。
因为在父进程终止后,进程组包含一个停止的进程,进程组称为孤儿进程组,要求向新孤儿进程组中处于停止状态的每一个进程发送挂断信号,接着又向其发送继续信号。
在处理挂断信号后,子进程继续。对挂断信号的系统默认动作是终止该进程,为此必须提供一个信号处理程序以捕捉该信号。
**最后只得注意的是父进程终止时,子进程变成后台进程组,因为父进程由shell作为前台作业执行。
**

9.11 FreeBSD实现

FreeBSD的实现,主要涉及到进程、进程组、会话和控制终端等的各属性设置。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值